({ tabAtom, contents, getCursorPoint }: TileLayoutProps)
| 55 | const DragPreviewHeight = 300; |
| 56 | |
| 57 | function TileLayoutComponent({ tabAtom, contents, getCursorPoint }: TileLayoutProps) { |
| 58 | const layoutModel = useTileLayout(tabAtom, contents); |
| 59 | const overlayTransform = useAtomValue(layoutModel.overlayTransform); |
| 60 | const setActiveDrag = useSetAtom(layoutModel.activeDrag); |
| 61 | const setReady = useSetAtom(layoutModel.ready); |
| 62 | const isResizing = useAtomValue(layoutModel.isResizing); |
| 63 | |
| 64 | const { activeDrag, dragClientOffset, dragItemType } = useDragLayer((monitor) => ({ |
| 65 | activeDrag: monitor.isDragging(), |
| 66 | dragClientOffset: monitor.getClientOffset(), |
| 67 | dragItemType: monitor.getItemType(), |
| 68 | })); |
| 69 | |
| 70 | useEffect(() => { |
| 71 | const activeTileDrag = activeDrag && dragItemType == tileItemType; |
| 72 | setActiveDrag(activeTileDrag); |
| 73 | }, [activeDrag, dragItemType]); |
| 74 | |
| 75 | const checkForCursorBounds = useCallback( |
| 76 | debounce(100, (dragClientOffset: XYCoord) => { |
| 77 | const cursorPoint = dragClientOffset ?? getCursorPoint?.(); |
| 78 | if (cursorPoint && layoutModel.displayContainerRef?.current) { |
| 79 | const displayContainerRect = layoutModel.displayContainerRef.current.getBoundingClientRect(); |
| 80 | const normalizedX = cursorPoint.x - displayContainerRect.x; |
| 81 | const normalizedY = cursorPoint.y - displayContainerRect.y; |
| 82 | if ( |
| 83 | normalizedX <= 0 || |
| 84 | normalizedX >= displayContainerRect.width || |
| 85 | normalizedY <= 0 || |
| 86 | normalizedY >= displayContainerRect.height |
| 87 | ) { |
| 88 | layoutModel.treeReducer({ type: LayoutTreeActionType.ClearPendingAction }); |
| 89 | } |
| 90 | } |
| 91 | }), |
| 92 | [getCursorPoint] |
| 93 | ); |
| 94 | |
| 95 | // Effect to detect when the cursor leaves the TileLayout hit trap so we can remove any placeholders. This cannot be done using pointer capture |
| 96 | // because that conflicts with the DnD layer. |
| 97 | useEffect(() => checkForCursorBounds(dragClientOffset), [dragClientOffset]); |
| 98 | |
| 99 | // Ensure that we don't see any jostling in the layout when we're rendering it the first time. |
| 100 | // `animate` will be disabled until after the transforms have all applied the first time. |
| 101 | const [animate, setAnimate] = useState(false); |
| 102 | useEffect(() => { |
| 103 | setTimeout(() => { |
| 104 | setAnimate(true); |
| 105 | setReady(true); |
| 106 | }, 50); |
| 107 | }, []); |
| 108 | |
| 109 | const gapSizePx = useAtomValue(layoutModel.gapSizePx); |
| 110 | const animationTimeS = useAtomValue(layoutModel.animationTimeS); |
| 111 | const tileStyle = useMemo( |
| 112 | () => |
| 113 | ({ |
| 114 | "--gap-size-px": `${gapSizePx}px`, |
nothing calls this directly
no test coverage detected