panelgrid 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PanelGridProvider.cjs +3 -1
- package/dist/PanelGridProvider.cjs.map +1 -1
- package/dist/PanelGridProvider.d.cts +2 -0
- package/dist/PanelGridProvider.d.mts +2 -0
- package/dist/PanelGridProvider.mjs +3 -1
- package/dist/PanelGridProvider.mjs.map +1 -1
- package/dist/PanelGridRenderer.cjs +7 -3
- package/dist/PanelGridRenderer.cjs.map +1 -1
- package/dist/PanelGridRenderer.mjs +7 -3
- package/dist/PanelGridRenderer.mjs.map +1 -1
- package/dist/helpers/index.cjs +1 -0
- package/dist/helpers/index.d.cts +2 -2
- package/dist/helpers/index.d.mts +2 -2
- package/dist/helpers/index.mjs +2 -2
- package/dist/helpers/rearrangement.cjs +26 -5
- package/dist/helpers/rearrangement.cjs.map +1 -1
- package/dist/helpers/rearrangement.d.cts +11 -1
- package/dist/helpers/rearrangement.d.mts +11 -1
- package/dist/helpers/rearrangement.mjs +26 -6
- package/dist/helpers/rearrangement.mjs.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/styles.css +4 -0
- package/dist/types.d.cts +1 -0
- package/dist/types.d.mts +1 -0
- package/dist/usePanelGrid.cjs +53 -18
- package/dist/usePanelGrid.cjs.map +1 -1
- package/dist/usePanelGrid.d.cts +3 -0
- package/dist/usePanelGrid.d.mts +3 -0
- package/dist/usePanelGrid.mjs +53 -18
- package/dist/usePanelGrid.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePanelGrid.mjs","names":["newPanelCoordinate: PanelCoordinate","RESIZE_CURSOR_MAP: Record<string, string>","e"],"sources":["../src/usePanelGrid.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useReducer, useRef } from \"react\";\nimport {\n applySnapAnimation,\n detectAnimatingPanels,\n gridPositionToPixels,\n gridToPixels,\n pixelsToGridPosition,\n pixelsToGridSize,\n rearrangePanels,\n} from \"./helpers\";\nimport { findNewPositionToAddPanel } from \"./helpers/rearrangement\";\nimport type { PanelCoordinate, PanelId, RearrangementFunction, ResizeHandlePosition } from \"./types\";\n\ninterface PanelGridOptions {\n panels: PanelCoordinate[];\n columnCount: number;\n baseSize: number;\n gap: number;\n resizeHandlePositions: ResizeHandlePosition[];\n rearrangement?: RearrangementFunction;\n}\n\nexport interface PanelGridState {\n panels: PanelCoordinate[];\n}\n\ninterface InternalPanelState {\n activePanelId: PanelId | null;\n draggableElements: Record<PanelId, HTMLElement | null>;\n animatingPanels: Set<PanelId>;\n}\n\nexport type PanelGridAction =\n | { type: \"UPDATE_PANELS\"; newPanels: PanelCoordinate[] }\n | { type: \"ADD_PANEL\"; newPanel: Partial<PanelCoordinate>; columnCount: number }\n | { type: \"REMOVE_PANEL\"; panelId: PanelId }\n | { type: \"LOCK_PANEL_SIZE\"; panelId: PanelId }\n | { type: \"UNLOCK_PANEL_SIZE\"; panelId: PanelId };\n\nexport function panelGridReducer(state: PanelGridState, action: PanelGridAction): PanelGridState {\n switch (action.type) {\n case \"UPDATE_PANELS\":\n return {\n ...state,\n panels: action.newPanels,\n };\n case \"ADD_PANEL\": {\n const { newPanel, columnCount } = action;\n const newPosition = findNewPositionToAddPanel(newPanel, state.panels, columnCount);\n const newPanelCoordinate: PanelCoordinate = {\n id: newPanel.id || Math.random().toString(36).substring(2, 15),\n x: newPosition.x,\n y: newPosition.y,\n w: newPanel.w || 1,\n h: newPanel.h || 1,\n };\n return {\n ...state,\n panels: [...state.panels, newPanelCoordinate],\n };\n }\n case \"REMOVE_PANEL\":\n return {\n ...state,\n panels: state.panels.filter((panel) => panel.id !== action.panelId),\n };\n case \"LOCK_PANEL_SIZE\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockSize: true } : panel)),\n };\n case \"UNLOCK_PANEL_SIZE\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockSize: false } : panel)),\n };\n default:\n return state;\n }\n}\n\nconst ANIMATION_DURATION = 300;\ntype TimeoutId = ReturnType<typeof setTimeout>;\n\nconst RESIZE_CURSOR_MAP: Record<string, string> = {\n nw: \"nwse-resize\",\n ne: \"nesw-resize\",\n se: \"nwse-resize\",\n sw: \"nesw-resize\",\n n: \"ns-resize\",\n s: \"ns-resize\",\n e: \"ew-resize\",\n w: \"ew-resize\",\n};\n\nexport function usePanelGrid({\n panels,\n columnCount,\n baseSize,\n gap,\n resizeHandlePositions: _resizeHandlePositions,\n rearrangement,\n}: PanelGridOptions) {\n const [state, dispatch] = useReducer(panelGridReducer, {\n panels,\n });\n const ghostPanelRef = useRef<HTMLDivElement | null>(null);\n const animationTimeoutsRef = useRef<Set<TimeoutId>>(new Set());\n\n const panelMap = useMemo(() => {\n const map = new Map<PanelId, PanelCoordinate>();\n state.panels.forEach((panel) => {\n map.set(panel.id, panel);\n });\n return map;\n }, [state.panels]);\n\n const internalState = useRef<InternalPanelState>({\n activePanelId: null,\n draggableElements: {},\n animatingPanels: new Set(),\n }).current;\n\n // Cleanup animation timeouts on unmount\n useEffect(() => {\n return () => {\n animationTimeoutsRef.current.forEach((timeoutId) => clearTimeout(timeoutId));\n animationTimeoutsRef.current.clear();\n };\n }, []);\n\n // Ghost panel helper functions\n // Direct DOM manipulation is intentionally used here for performance.\n // This avoids React re-renders during high-frequency mousemove events.\n const showGhostPanel = useCallback((left: number, top: number, width: number, height: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.display = \"block\";\n ghostPanelRef.current.style.left = `${left}px`;\n ghostPanelRef.current.style.top = `${top}px`;\n ghostPanelRef.current.style.width = `${width}px`;\n ghostPanelRef.current.style.height = `${height}px`;\n ghostPanelRef.current.style.outline = \"1px dashed rgba(0, 0, 0, 0.2)\";\n }, []);\n\n const updateGhostPanelPosition = useCallback((left: number, top: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.left = `${left}px`;\n ghostPanelRef.current.style.top = `${top}px`;\n }, []);\n\n const updateGhostPanelSize = useCallback((width: number, height: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.width = `${width}px`;\n ghostPanelRef.current.style.height = `${height}px`;\n }, []);\n\n const hideGhostPanel = useCallback(() => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.display = \"none\";\n }, []);\n\n // Callback to update panels and trigger animations\n const updatePanelsWithAnimation = useCallback(\n (updatedPanel: PanelCoordinate, currentPanels: PanelCoordinate[]) => {\n // Use custom rearrangement function if provided, otherwise use default\n const rearrange = rearrangement || rearrangePanels;\n const nextPanels = rearrange(updatedPanel, currentPanels, columnCount);\n\n // Detect which panels have been rearranged\n internalState.animatingPanels = detectAnimatingPanels({\n oldPanels: currentPanels,\n newPanels: nextPanels,\n excludePanelId: updatedPanel.id,\n });\n\n dispatch({ type: \"UPDATE_PANELS\", newPanels: nextPanels });\n\n // Clear animating panels after animation completes\n const timeoutId = setTimeout(() => {\n internalState.animatingPanels.clear();\n animationTimeoutsRef.current.delete(timeoutId);\n }, ANIMATION_DURATION);\n animationTimeoutsRef.current.add(timeoutId);\n },\n [columnCount, internalState, rearrangement]\n );\n\n // Create drag handler for a specific panel\n const createDragHandler = useCallback(\n (panel: PanelCoordinate) => (e: React.MouseEvent<HTMLDivElement>) => {\n internalState.activePanelId = panel.id;\n const draggingElement = internalState.draggableElements[panel.id];\n if (!draggingElement) return;\n\n let isDragging = true;\n const initialX = e.clientX;\n const initialY = e.clientY;\n const offsetX = draggingElement.offsetLeft;\n const offsetY = draggingElement.offsetTop;\n const originalTransition = draggingElement.style.transition;\n\n document.body.classList.add(\"panelgrid-dragging\");\n\n draggingElement.classList.add(\"panelgrid-panel--dragging\");\n draggingElement.style.transition = \"\";\n\n showGhostPanel(offsetX, offsetY, draggingElement.offsetWidth, draggingElement.offsetHeight);\n\n const mouseUpListenerCtrl = new AbortController();\n const mouseMoveListenerCtrl = new AbortController();\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging) return;\n if (!draggingElement) return;\n\n const currentX = e.clientX;\n const currentY = e.clientY;\n const deltaX = currentX - initialX;\n const deltaY = currentY - initialY;\n\n draggingElement.style.left = offsetX + deltaX + \"px\";\n draggingElement.style.top = offsetY + deltaY + \"px\";\n\n // Update ghost panel position to snap to grid\n const droppedLeft = offsetX + deltaX;\n const droppedTop = offsetY + deltaY;\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n const nextLeft = gridPositionToPixels(nextGridX, baseSize, gap);\n const nextTop = gridPositionToPixels(nextGridY, baseSize, gap);\n\n updateGhostPanelPosition(nextLeft, nextTop);\n\n e.preventDefault(); // Prevent text selection during drag\n };\n\n const onMouseUp = () => {\n if (!draggingElement) return;\n\n isDragging = false;\n draggingElement.classList.remove(\"panelgrid-panel--dragging\");\n\n hideGhostPanel();\n\n const droppedLeft = parseFloat(draggingElement.style.left) || 0;\n const droppedTop = parseFloat(draggingElement.style.top) || 0;\n\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n\n const nextLeft = gridPositionToPixels(nextGridX, baseSize, gap);\n const nextTop = gridPositionToPixels(nextGridY, baseSize, gap);\n\n // Apply snap-back animation\n applySnapAnimation({\n element: draggingElement,\n droppedLeft,\n droppedTop,\n nextLeft,\n nextTop,\n originalTransition,\n });\n\n updatePanelsWithAnimation({ ...panel, x: nextGridX, y: nextGridY }, state.panels);\n\n document.body.classList.remove(\"panelgrid-dragging\");\n internalState.activePanelId = null;\n\n mouseMoveListenerCtrl.abort();\n mouseUpListenerCtrl.abort();\n };\n\n document.addEventListener(\"mousemove\", onMouseMove, {\n signal: mouseMoveListenerCtrl.signal,\n });\n document.addEventListener(\"mouseup\", onMouseUp, {\n signal: mouseUpListenerCtrl.signal,\n });\n },\n [\n baseSize,\n gap,\n internalState,\n state.panels,\n updatePanelsWithAnimation,\n showGhostPanel,\n updateGhostPanelPosition,\n hideGhostPanel,\n columnCount,\n ]\n );\n\n // Create resize handler for a specific panel\n const createResizeHandler = useCallback(\n (panel: PanelCoordinate) => (e: React.MouseEvent<HTMLSpanElement>) => {\n e.stopPropagation();\n let isResizing = true;\n internalState.activePanelId = panel.id;\n const draggingElement = internalState.draggableElements[panel.id];\n if (!draggingElement) return;\n\n const startX = e.clientX;\n const startY = e.clientY;\n const initialTop = draggingElement.offsetTop;\n const initialLeft = draggingElement.offsetLeft;\n const initialWidth = draggingElement.offsetWidth;\n const initialHeight = draggingElement.offsetHeight;\n const initialZIndex = draggingElement.style.zIndex;\n const initialCursor = draggingElement.style.cursor;\n\n const resizeHandle = e.currentTarget;\n const handlePosition = resizeHandle.dataset.pgResizeHandle;\n\n const northSideResizeEnabled = handlePosition?.includes(\"n\");\n const westSideResizeEnabled = handlePosition?.includes(\"w\");\n const isVerticalResizeOnly = handlePosition === \"n\" || handlePosition === \"s\";\n const isHorizontalResizeOnly = handlePosition === \"e\" || handlePosition === \"w\";\n\n document.body.classList.add(\"panelgrid-resizing\");\n\n draggingElement.style.cursor = RESIZE_CURSOR_MAP[handlePosition || \"se\"] || \"nwse-resize\";\n draggingElement.style.transition = \"\";\n\n showGhostPanel(draggingElement.offsetLeft, draggingElement.offsetTop, initialWidth, initialHeight);\n\n const mouseMoveController = new AbortController();\n const mouseUpController = new AbortController();\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isResizing) return;\n if (!draggingElement) return;\n\n const deltaX = e.clientX - startX;\n const deltaY = e.clientY - startY;\n\n // Calculate dimensions once, accounting for all resize directions\n const newWidth = westSideResizeEnabled\n ? Math.max(initialWidth - deltaX, 1)\n : isVerticalResizeOnly\n ? initialWidth\n : initialWidth + deltaX;\n\n const newHeight = northSideResizeEnabled\n ? Math.max(initialHeight - deltaY, 1)\n : isHorizontalResizeOnly\n ? initialHeight\n : initialHeight + deltaY;\n\n draggingElement.style.width = `${newWidth}px`;\n draggingElement.style.height = `${newHeight}px`;\n draggingElement.style.zIndex = \"calc(infinity)\";\n\n // Update position for north/west resizing\n if (northSideResizeEnabled) {\n draggingElement.style.top = `${initialTop + deltaY}px`;\n }\n if (westSideResizeEnabled) {\n draggingElement.style.left = `${initialLeft + deltaX}px`;\n }\n\n // Calculate current position (needed for grid calculations)\n const currentLeft = westSideResizeEnabled ? initialLeft + deltaX : initialLeft;\n const currentTop = northSideResizeEnabled ? initialTop + deltaY : initialTop;\n\n // Update ghost panel - calculate grid position BEFORE grid size\n const nextGridX = pixelsToGridPosition(currentLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(currentTop, baseSize, gap);\n const nextGridW = pixelsToGridSize(newWidth, baseSize, gap, columnCount, nextGridX);\n const nextGridH = pixelsToGridSize(newHeight, baseSize, gap, columnCount, nextGridY);\n\n const snappedWidth = gridToPixels(nextGridW, baseSize, gap);\n const snappedHeight = gridToPixels(nextGridH, baseSize, gap);\n const snappedLeft = gridPositionToPixels(nextGridX, baseSize, gap);\n const snappedTop = gridPositionToPixels(nextGridY, baseSize, gap);\n\n updateGhostPanelPosition(snappedLeft, snappedTop);\n updateGhostPanelSize(snappedWidth, snappedHeight);\n };\n\n const onMouseUp = () => {\n if (!draggingElement) return;\n\n hideGhostPanel();\n\n const rect = draggingElement.getBoundingClientRect();\n const droppedLeft = parseFloat(draggingElement.style.left) || 0;\n const droppedTop = parseFloat(draggingElement.style.top) || 0;\n\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n\n const nextGridW = pixelsToGridSize(rect.width, baseSize, gap, columnCount, nextGridX);\n const nextGridH = pixelsToGridSize(rect.height, baseSize, gap, columnCount, nextGridY);\n\n const left = gridPositionToPixels(nextGridX, baseSize, gap);\n const top = gridPositionToPixels(nextGridY, baseSize, gap);\n const width = gridToPixels(nextGridW, baseSize, gap);\n const height = gridToPixels(nextGridH, baseSize, gap);\n\n draggingElement.style.width = `${rect.width}px`;\n draggingElement.style.height = `${rect.height}px`;\n draggingElement.style.cursor = initialCursor;\n draggingElement.style.transition = \"\";\n\n window.requestAnimationFrame(() => {\n draggingElement.style.top = `${top}px`;\n draggingElement.style.left = `${left}px`;\n draggingElement.style.width = `${width}px`;\n draggingElement.style.height = `${height}px`;\n draggingElement.style.zIndex = initialZIndex;\n draggingElement.style.transition =\n \"width 0.1s ease-out, height 0.1s ease-out, top 0.1s ease-out, left 0.1s ease-out\";\n });\n\n updatePanelsWithAnimation({ ...panel, x: nextGridX, y: nextGridY, w: nextGridW, h: nextGridH }, state.panels);\n\n isResizing = false;\n internalState.activePanelId = null;\n document.body.classList.remove(\"panelgrid-resizing\");\n\n mouseMoveController.abort();\n mouseUpController.abort();\n };\n\n document.addEventListener(\"mousemove\", onMouseMove, {\n signal: mouseMoveController.signal,\n });\n document.addEventListener(\"mouseup\", onMouseUp, {\n signal: mouseUpController.signal,\n });\n },\n [\n baseSize,\n gap,\n internalState,\n state.panels,\n updatePanelsWithAnimation,\n showGhostPanel,\n updateGhostPanelPosition,\n updateGhostPanelSize,\n hideGhostPanel,\n columnCount,\n ]\n );\n\n // Create ref callback for panel elements\n const createRefCallback = useCallback(\n (panelId: PanelId) => (element: HTMLElement | null) => {\n if (!element) return;\n if (!internalState.draggableElements[panelId]) {\n internalState.draggableElements[panelId] = element;\n }\n },\n [internalState]\n );\n\n // Memoize panel props to avoid recreating on every render\n const panelsWithProps = useMemo(() => {\n return state.panels.map((panel) => {\n const isAnimating = internalState.animatingPanels.has(panel.id);\n const isActive = internalState.activePanelId === panel.id;\n\n return {\n panelProps: {\n key: panel.id,\n lockSize: panel.lockSize,\n positionData: {\n x: panel.x,\n y: panel.y,\n w: panel.w,\n h: panel.h,\n },\n style: {\n top: gridPositionToPixels(panel.y, baseSize, gap),\n left: gridPositionToPixels(panel.x, baseSize, gap),\n width: gridToPixels(panel.w, baseSize, gap),\n height: gridToPixels(panel.h, baseSize, gap),\n transition:\n isAnimating && !isActive\n ? \"top 0.3s ease-out, left 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out\"\n : undefined,\n },\n ref: createRefCallback(panel.id),\n onMouseDown: createDragHandler(panel),\n },\n resizeHandleProps: panel.lockSize\n ? undefined\n : {\n onMouseDown: createResizeHandler(panel),\n },\n };\n });\n }, [\n state.panels,\n baseSize,\n gap,\n internalState.animatingPanels,\n internalState.activePanelId,\n createRefCallback,\n createDragHandler,\n createResizeHandler,\n ]);\n\n const addPanel = useCallback(\n (panel: Partial<PanelCoordinate>) => {\n dispatch({\n type: \"ADD_PANEL\",\n newPanel: {\n ...panel,\n id: panel.id || Math.random().toString(36).substring(2, 15),\n },\n columnCount,\n });\n },\n [columnCount]\n );\n\n const removePanel = useCallback((id: PanelId) => {\n dispatch({ type: \"REMOVE_PANEL\", panelId: id });\n }, []);\n\n const lockPanelSize = useCallback((id: PanelId) => {\n dispatch({ type: \"LOCK_PANEL_SIZE\", panelId: id });\n }, []);\n\n const unlockPanelSize = useCallback((id: PanelId) => {\n dispatch({ type: \"UNLOCK_PANEL_SIZE\", panelId: id });\n }, []);\n\n const exportState = useCallback(() => {\n return state.panels;\n }, [state.panels]);\n\n return {\n panels: panelsWithProps,\n panelMap,\n ghostPanelRef,\n addPanel,\n removePanel,\n lockPanelSize,\n unlockPanelSize,\n exportState,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePanelGrid.mjs","names":["newPanelCoordinate: PanelCoordinate","RESIZE_CURSOR_MAP: Record<string, string>","e"],"sources":["../src/usePanelGrid.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useReducer, useRef } from \"react\";\nimport {\n applySnapAnimation,\n detectAnimatingPanels,\n gridPositionToPixels,\n gridToPixels,\n pixelsToGridPosition,\n pixelsToGridSize,\n rearrangePanels,\n} from \"./helpers\";\nimport { findNewPositionToAddPanel } from \"./helpers/rearrangement\";\nimport type { PanelCoordinate, PanelId, RearrangementFunction, ResizeHandlePosition } from \"./types\";\n\ninterface PanelGridOptions {\n panels: PanelCoordinate[];\n columnCount: number;\n baseSize: number;\n gap: number;\n resizeHandlePositions: ResizeHandlePosition[];\n rearrangement?: RearrangementFunction;\n}\n\nexport interface PanelGridState {\n panels: PanelCoordinate[];\n}\n\ninterface InternalPanelState {\n activePanelId: PanelId | null;\n draggableElements: Record<PanelId, HTMLElement | null>;\n animatingPanels: Set<PanelId>;\n}\n\nexport type PanelGridAction =\n | { type: \"UPDATE_PANELS\"; newPanels: PanelCoordinate[] }\n | { type: \"ADD_PANEL\"; newPanel: Partial<PanelCoordinate>; columnCount: number }\n | { type: \"REMOVE_PANEL\"; panelId: PanelId }\n | { type: \"LOCK_PANEL_SIZE\"; panelId: PanelId }\n | { type: \"UNLOCK_PANEL_SIZE\"; panelId: PanelId }\n | { type: \"LOCK_PANEL_POSITION\"; panelId: PanelId }\n | { type: \"UNLOCK_PANEL_POSITION\"; panelId: PanelId };\n\nexport function panelGridReducer(state: PanelGridState, action: PanelGridAction): PanelGridState {\n switch (action.type) {\n case \"UPDATE_PANELS\":\n return {\n ...state,\n panels: action.newPanels,\n };\n case \"ADD_PANEL\": {\n const { newPanel, columnCount } = action;\n const newPosition = findNewPositionToAddPanel(newPanel, state.panels, columnCount);\n const newPanelCoordinate: PanelCoordinate = {\n id: newPanel.id || Math.random().toString(36).substring(2, 15),\n x: newPosition.x,\n y: newPosition.y,\n w: newPanel.w || 1,\n h: newPanel.h || 1,\n };\n return {\n ...state,\n panels: [...state.panels, newPanelCoordinate],\n };\n }\n case \"REMOVE_PANEL\":\n return {\n ...state,\n panels: state.panels.filter((panel) => panel.id !== action.panelId),\n };\n case \"LOCK_PANEL_SIZE\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockSize: true } : panel)),\n };\n case \"UNLOCK_PANEL_SIZE\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockSize: false } : panel)),\n };\n case \"LOCK_PANEL_POSITION\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockPosition: true } : panel)),\n };\n case \"UNLOCK_PANEL_POSITION\":\n return {\n ...state,\n panels: state.panels.map((panel) => (panel.id === action.panelId ? { ...panel, lockPosition: false } : panel)),\n };\n default:\n return state;\n }\n}\n\nconst ANIMATION_DURATION = 300;\ntype TimeoutId = ReturnType<typeof setTimeout>;\n\nconst RESIZE_CURSOR_MAP: Record<string, string> = {\n nw: \"nwse-resize\",\n ne: \"nesw-resize\",\n se: \"nwse-resize\",\n sw: \"nesw-resize\",\n n: \"ns-resize\",\n s: \"ns-resize\",\n e: \"ew-resize\",\n w: \"ew-resize\",\n};\n\nexport function usePanelGrid({\n panels,\n columnCount,\n baseSize,\n gap,\n resizeHandlePositions: _resizeHandlePositions,\n rearrangement,\n}: PanelGridOptions) {\n const [state, dispatch] = useReducer(panelGridReducer, {\n panels,\n });\n const ghostPanelRef = useRef<HTMLDivElement | null>(null);\n const animationTimeoutsRef = useRef<Set<TimeoutId>>(new Set());\n\n const panelMap = useMemo(() => {\n const map = new Map<PanelId, PanelCoordinate>();\n state.panels.forEach((panel) => {\n map.set(panel.id, panel);\n });\n return map;\n }, [state.panels]);\n\n const internalState = useRef<InternalPanelState>({\n activePanelId: null,\n draggableElements: {},\n animatingPanels: new Set(),\n }).current;\n\n // Cleanup animation timeouts on unmount\n useEffect(() => {\n return () => {\n animationTimeoutsRef.current.forEach((timeoutId) => clearTimeout(timeoutId));\n animationTimeoutsRef.current.clear();\n };\n }, []);\n\n // Ghost panel helper functions\n // Direct DOM manipulation is intentionally used here for performance.\n // This avoids React re-renders during high-frequency mousemove events.\n const showGhostPanel = useCallback((left: number, top: number, width: number, height: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.display = \"block\";\n ghostPanelRef.current.style.left = `${left}px`;\n ghostPanelRef.current.style.top = `${top}px`;\n ghostPanelRef.current.style.width = `${width}px`;\n ghostPanelRef.current.style.height = `${height}px`;\n ghostPanelRef.current.style.outline = \"1px dashed rgba(0, 0, 0, 0.2)\";\n }, []);\n\n const updateGhostPanelPosition = useCallback((left: number, top: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.left = `${left}px`;\n ghostPanelRef.current.style.top = `${top}px`;\n }, []);\n\n const updateGhostPanelSize = useCallback((width: number, height: number) => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.width = `${width}px`;\n ghostPanelRef.current.style.height = `${height}px`;\n }, []);\n\n const hideGhostPanel = useCallback(() => {\n if (!ghostPanelRef.current) return;\n ghostPanelRef.current.style.display = \"none\";\n }, []);\n\n // Callback to update panels and trigger animations\n // Returns the rearranged panels so callers can inspect the actual result position\n const updatePanelsWithAnimation = useCallback(\n (updatedPanel: PanelCoordinate, currentPanels: PanelCoordinate[]): PanelCoordinate[] => {\n // Use custom rearrangement function if provided, otherwise use default\n const rearrange = rearrangement || rearrangePanels;\n const nextPanels = rearrange(updatedPanel, currentPanels, columnCount);\n\n // Detect which panels have been rearranged\n internalState.animatingPanels = detectAnimatingPanels({\n oldPanels: currentPanels,\n newPanels: nextPanels,\n excludePanelId: updatedPanel.id,\n });\n\n dispatch({ type: \"UPDATE_PANELS\", newPanels: nextPanels });\n\n // Clear animating panels after animation completes\n const timeoutId = setTimeout(() => {\n internalState.animatingPanels.clear();\n animationTimeoutsRef.current.delete(timeoutId);\n }, ANIMATION_DURATION);\n animationTimeoutsRef.current.add(timeoutId);\n\n return nextPanels;\n },\n [columnCount, internalState, rearrangement]\n );\n\n // Create drag handler for a specific panel\n const createDragHandler = useCallback(\n (panel: PanelCoordinate) => (e: React.MouseEvent<HTMLDivElement>) => {\n if (panel.lockPosition) return;\n internalState.activePanelId = panel.id;\n const draggingElement = internalState.draggableElements[panel.id];\n if (!draggingElement) return;\n\n let isDragging = true;\n const initialX = e.clientX;\n const initialY = e.clientY;\n const offsetX = draggingElement.offsetLeft;\n const offsetY = draggingElement.offsetTop;\n const originalTransition = draggingElement.style.transition;\n\n document.body.classList.add(\"panelgrid-dragging\");\n\n draggingElement.classList.add(\"panelgrid-panel--dragging\");\n draggingElement.style.transition = \"\";\n\n showGhostPanel(offsetX, offsetY, draggingElement.offsetWidth, draggingElement.offsetHeight);\n\n const mouseUpListenerCtrl = new AbortController();\n const mouseMoveListenerCtrl = new AbortController();\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging) return;\n if (!draggingElement) return;\n\n const currentX = e.clientX;\n const currentY = e.clientY;\n const deltaX = currentX - initialX;\n const deltaY = currentY - initialY;\n\n draggingElement.style.left = offsetX + deltaX + \"px\";\n draggingElement.style.top = offsetY + deltaY + \"px\";\n\n // Update ghost panel position to snap to grid\n const droppedLeft = offsetX + deltaX;\n const droppedTop = offsetY + deltaY;\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n const nextLeft = gridPositionToPixels(nextGridX, baseSize, gap);\n const nextTop = gridPositionToPixels(nextGridY, baseSize, gap);\n\n updateGhostPanelPosition(nextLeft, nextTop);\n\n e.preventDefault(); // Prevent text selection during drag\n };\n\n const onMouseUp = () => {\n if (!draggingElement) return;\n\n isDragging = false;\n draggingElement.classList.remove(\"panelgrid-panel--dragging\");\n\n hideGhostPanel();\n\n const droppedLeft = parseFloat(draggingElement.style.left) || 0;\n const droppedTop = parseFloat(draggingElement.style.top) || 0;\n\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n\n // Rearrange first so we know the actual result position.\n // On rollback (e.g. collision with a locked panel), the panel ends up at its original\n // position rather than the dropped position. applySnapAnimation must target the actual\n // result — otherwise the DOM is left at the dropped position while React's cached style\n // (same reference, no useMemo invalidation) never corrects it.\n const nextPanels = updatePanelsWithAnimation({ ...panel, x: nextGridX, y: nextGridY }, state.panels);\n const resultPanel = nextPanels.find((p) => p.id === panel.id);\n const actualGridX = resultPanel?.x ?? nextGridX;\n const actualGridY = resultPanel?.y ?? nextGridY;\n\n const nextLeft = gridPositionToPixels(actualGridX, baseSize, gap);\n const nextTop = gridPositionToPixels(actualGridY, baseSize, gap);\n\n applySnapAnimation({\n element: draggingElement,\n droppedLeft,\n droppedTop,\n nextLeft,\n nextTop,\n originalTransition,\n });\n\n document.body.classList.remove(\"panelgrid-dragging\");\n internalState.activePanelId = null;\n\n mouseMoveListenerCtrl.abort();\n mouseUpListenerCtrl.abort();\n };\n\n document.addEventListener(\"mousemove\", onMouseMove, {\n signal: mouseMoveListenerCtrl.signal,\n });\n document.addEventListener(\"mouseup\", onMouseUp, {\n signal: mouseUpListenerCtrl.signal,\n });\n },\n [\n baseSize,\n gap,\n internalState,\n state.panels,\n updatePanelsWithAnimation,\n showGhostPanel,\n updateGhostPanelPosition,\n hideGhostPanel,\n columnCount,\n ]\n );\n\n // Create resize handler for a specific panel\n const createResizeHandler = useCallback(\n (panel: PanelCoordinate) => (e: React.MouseEvent<HTMLSpanElement>) => {\n e.stopPropagation();\n let isResizing = true;\n internalState.activePanelId = panel.id;\n const draggingElement = internalState.draggableElements[panel.id];\n if (!draggingElement) return;\n\n const startX = e.clientX;\n const startY = e.clientY;\n const initialTop = draggingElement.offsetTop;\n const initialLeft = draggingElement.offsetLeft;\n const initialWidth = draggingElement.offsetWidth;\n const initialHeight = draggingElement.offsetHeight;\n const initialZIndex = draggingElement.style.zIndex;\n const initialCursor = draggingElement.style.cursor;\n\n const resizeHandle = e.currentTarget;\n const handlePosition = resizeHandle.dataset.pgResizeHandle;\n\n const northSideResizeEnabled = handlePosition?.includes(\"n\");\n const westSideResizeEnabled = handlePosition?.includes(\"w\");\n const isVerticalResizeOnly = handlePosition === \"n\" || handlePosition === \"s\";\n const isHorizontalResizeOnly = handlePosition === \"e\" || handlePosition === \"w\";\n\n document.body.classList.add(\"panelgrid-resizing\");\n\n draggingElement.style.cursor = RESIZE_CURSOR_MAP[handlePosition || \"se\"] || \"nwse-resize\";\n draggingElement.style.transition = \"\";\n\n showGhostPanel(draggingElement.offsetLeft, draggingElement.offsetTop, initialWidth, initialHeight);\n\n const mouseMoveController = new AbortController();\n const mouseUpController = new AbortController();\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isResizing) return;\n if (!draggingElement) return;\n\n const deltaX = e.clientX - startX;\n const deltaY = e.clientY - startY;\n\n // Calculate dimensions once, accounting for all resize directions\n const newWidth = westSideResizeEnabled\n ? Math.max(initialWidth - deltaX, 1)\n : isVerticalResizeOnly\n ? initialWidth\n : initialWidth + deltaX;\n\n const newHeight = northSideResizeEnabled\n ? Math.max(initialHeight - deltaY, 1)\n : isHorizontalResizeOnly\n ? initialHeight\n : initialHeight + deltaY;\n\n draggingElement.style.width = `${newWidth}px`;\n draggingElement.style.height = `${newHeight}px`;\n draggingElement.style.zIndex = \"calc(infinity)\";\n\n // Update position for north/west resizing\n if (northSideResizeEnabled) {\n draggingElement.style.top = `${initialTop + deltaY}px`;\n }\n if (westSideResizeEnabled) {\n draggingElement.style.left = `${initialLeft + deltaX}px`;\n }\n\n // Calculate current position (needed for grid calculations)\n const currentLeft = westSideResizeEnabled ? initialLeft + deltaX : initialLeft;\n const currentTop = northSideResizeEnabled ? initialTop + deltaY : initialTop;\n\n // Update ghost panel - calculate grid position BEFORE grid size\n const nextGridX = pixelsToGridPosition(currentLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(currentTop, baseSize, gap);\n const nextGridW = pixelsToGridSize(newWidth, baseSize, gap, columnCount, nextGridX);\n const nextGridH = pixelsToGridSize(newHeight, baseSize, gap, columnCount, nextGridY);\n\n const snappedWidth = gridToPixels(nextGridW, baseSize, gap);\n const snappedHeight = gridToPixels(nextGridH, baseSize, gap);\n const snappedLeft = gridPositionToPixels(nextGridX, baseSize, gap);\n const snappedTop = gridPositionToPixels(nextGridY, baseSize, gap);\n\n updateGhostPanelPosition(snappedLeft, snappedTop);\n updateGhostPanelSize(snappedWidth, snappedHeight);\n };\n\n const onMouseUp = () => {\n if (!draggingElement) return;\n\n hideGhostPanel();\n\n const rect = draggingElement.getBoundingClientRect();\n const droppedLeft = parseFloat(draggingElement.style.left) || 0;\n const droppedTop = parseFloat(draggingElement.style.top) || 0;\n\n const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);\n const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);\n\n const nextGridW = pixelsToGridSize(rect.width, baseSize, gap, columnCount, nextGridX);\n const nextGridH = pixelsToGridSize(rect.height, baseSize, gap, columnCount, nextGridY);\n\n // Rearrange first to get the actual result position/size.\n // On rollback the panel may end up at its original position; the RAF must target\n // that actual position so the DOM stays in sync with React state.\n const nextPanels = updatePanelsWithAnimation(\n { ...panel, x: nextGridX, y: nextGridY, w: nextGridW, h: nextGridH },\n state.panels\n );\n const resultPanel = nextPanels.find((p) => p.id === panel.id);\n const actualX = resultPanel?.x ?? nextGridX;\n const actualY = resultPanel?.y ?? nextGridY;\n const actualW = resultPanel?.w ?? nextGridW;\n const actualH = resultPanel?.h ?? nextGridH;\n\n const left = gridPositionToPixels(actualX, baseSize, gap);\n const top = gridPositionToPixels(actualY, baseSize, gap);\n const width = gridToPixels(actualW, baseSize, gap);\n const height = gridToPixels(actualH, baseSize, gap);\n\n draggingElement.style.width = `${rect.width}px`;\n draggingElement.style.height = `${rect.height}px`;\n draggingElement.style.cursor = initialCursor;\n draggingElement.style.transition = \"\";\n\n window.requestAnimationFrame(() => {\n draggingElement.style.top = `${top}px`;\n draggingElement.style.left = `${left}px`;\n draggingElement.style.width = `${width}px`;\n draggingElement.style.height = `${height}px`;\n draggingElement.style.zIndex = initialZIndex;\n draggingElement.style.transition =\n \"width 0.1s ease-out, height 0.1s ease-out, top 0.1s ease-out, left 0.1s ease-out\";\n });\n\n isResizing = false;\n internalState.activePanelId = null;\n document.body.classList.remove(\"panelgrid-resizing\");\n\n mouseMoveController.abort();\n mouseUpController.abort();\n };\n\n document.addEventListener(\"mousemove\", onMouseMove, {\n signal: mouseMoveController.signal,\n });\n document.addEventListener(\"mouseup\", onMouseUp, {\n signal: mouseUpController.signal,\n });\n },\n [\n baseSize,\n gap,\n internalState,\n state.panels,\n updatePanelsWithAnimation,\n showGhostPanel,\n updateGhostPanelPosition,\n updateGhostPanelSize,\n hideGhostPanel,\n columnCount,\n ]\n );\n\n // Create ref callback for panel elements\n const createRefCallback = useCallback(\n (panelId: PanelId) => (element: HTMLElement | null) => {\n if (!element) return;\n if (!internalState.draggableElements[panelId]) {\n internalState.draggableElements[panelId] = element;\n }\n },\n [internalState]\n );\n\n // Memoize panel props to avoid recreating on every render\n const panelsWithProps = useMemo(() => {\n return state.panels.map((panel) => {\n const isAnimating = internalState.animatingPanels.has(panel.id);\n const isActive = internalState.activePanelId === panel.id;\n\n return {\n panelProps: {\n key: panel.id,\n lockSize: panel.lockSize,\n lockPosition: panel.lockPosition,\n positionData: {\n x: panel.x,\n y: panel.y,\n w: panel.w,\n h: panel.h,\n },\n style: {\n top: gridPositionToPixels(panel.y, baseSize, gap),\n left: gridPositionToPixels(panel.x, baseSize, gap),\n width: gridToPixels(panel.w, baseSize, gap),\n height: gridToPixels(panel.h, baseSize, gap),\n transition:\n isAnimating && !isActive\n ? \"top 0.3s ease-out, left 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out\"\n : undefined,\n },\n ref: createRefCallback(panel.id),\n onMouseDown: createDragHandler(panel),\n },\n resizeHandleProps: panel.lockSize\n ? undefined\n : {\n onMouseDown: createResizeHandler(panel),\n },\n };\n });\n }, [\n state.panels,\n baseSize,\n gap,\n internalState.animatingPanels,\n internalState.activePanelId,\n createRefCallback,\n createDragHandler,\n createResizeHandler,\n ]);\n\n const addPanel = useCallback(\n (panel: Partial<PanelCoordinate>) => {\n dispatch({\n type: \"ADD_PANEL\",\n newPanel: {\n ...panel,\n id: panel.id || Math.random().toString(36).substring(2, 15),\n },\n columnCount,\n });\n },\n [columnCount]\n );\n\n const removePanel = useCallback((id: PanelId) => {\n dispatch({ type: \"REMOVE_PANEL\", panelId: id });\n }, []);\n\n const lockPanelSize = useCallback((id: PanelId) => {\n dispatch({ type: \"LOCK_PANEL_SIZE\", panelId: id });\n }, []);\n\n const unlockPanelSize = useCallback((id: PanelId) => {\n dispatch({ type: \"UNLOCK_PANEL_SIZE\", panelId: id });\n }, []);\n\n const lockPanelPosition = useCallback((id: PanelId) => {\n dispatch({ type: \"LOCK_PANEL_POSITION\", panelId: id });\n }, []);\n\n const unlockPanelPosition = useCallback((id: PanelId) => {\n dispatch({ type: \"UNLOCK_PANEL_POSITION\", panelId: id });\n }, []);\n\n const exportState = useCallback(() => {\n return state.panels;\n }, [state.panels]);\n\n return {\n panels: panelsWithProps,\n panelMap,\n ghostPanelRef,\n addPanel,\n removePanel,\n lockPanelSize,\n unlockPanelSize,\n lockPanelPosition,\n unlockPanelPosition,\n exportState,\n };\n}\n"],"mappings":"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"}
|