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
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,7 @@ const require_usePanel = require('./usePanel.cjs');
|
|
|
6
6
|
exports.PanelGridProvider = require_PanelGridProvider.PanelGridProvider;
|
|
7
7
|
exports.PanelGridRenderer = require_PanelGridRenderer.PanelGridRenderer;
|
|
8
8
|
exports.rearrangePanels = require_rearrangement.rearrangePanels;
|
|
9
|
+
exports.resolveWithLockRollback = require_rearrangement.resolveWithLockRollback;
|
|
9
10
|
exports.usePanel = require_usePanel.usePanel;
|
|
10
11
|
exports.usePanelGridControls = require_PanelGridProvider.usePanelGridControls;
|
|
11
12
|
exports.usePanelGridState = require_PanelGridProvider.usePanelGridState;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.cjs";
|
|
2
|
-
import { rearrangePanels } from "./helpers/rearrangement.cjs";
|
|
2
|
+
import { rearrangePanels, resolveWithLockRollback } from "./helpers/rearrangement.cjs";
|
|
3
3
|
import { PanelGridProvider, usePanelGridControls, usePanelGridState } from "./PanelGridProvider.cjs";
|
|
4
4
|
import { PanelGridRenderer } from "./PanelGridRenderer.cjs";
|
|
5
5
|
import { usePanel } from "./usePanel.cjs";
|
|
6
|
-
export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, rearrangePanels, usePanel, usePanelGridControls, usePanelGridState };
|
|
6
|
+
export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, rearrangePanels, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.mjs";
|
|
2
|
-
import { rearrangePanels } from "./helpers/rearrangement.mjs";
|
|
2
|
+
import { rearrangePanels, resolveWithLockRollback } from "./helpers/rearrangement.mjs";
|
|
3
3
|
import { PanelGridProvider, usePanelGridControls, usePanelGridState } from "./PanelGridProvider.mjs";
|
|
4
4
|
import { PanelGridRenderer } from "./PanelGridRenderer.mjs";
|
|
5
5
|
import { usePanel } from "./usePanel.mjs";
|
|
6
|
-
export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, rearrangePanels, usePanel, usePanelGridControls, usePanelGridState };
|
|
6
|
+
export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, rearrangePanels, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { rearrangePanels } from "./helpers/rearrangement.mjs";
|
|
1
|
+
import { rearrangePanels, resolveWithLockRollback } from "./helpers/rearrangement.mjs";
|
|
2
2
|
import { PanelGridProvider, usePanelGridControls, usePanelGridState } from "./PanelGridProvider.mjs";
|
|
3
3
|
import { PanelGridRenderer } from "./PanelGridRenderer.mjs";
|
|
4
4
|
import { usePanel } from "./usePanel.mjs";
|
|
5
5
|
|
|
6
|
-
export { PanelGridProvider, PanelGridRenderer, rearrangePanels, usePanel, usePanelGridControls, usePanelGridState };
|
|
6
|
+
export { PanelGridProvider, PanelGridRenderer, rearrangePanels, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
|
package/dist/styles.css
CHANGED
package/dist/types.d.cts
CHANGED
package/dist/types.d.mts
CHANGED
package/dist/usePanelGrid.cjs
CHANGED
|
@@ -44,6 +44,20 @@ function panelGridReducer(state, action) {
|
|
|
44
44
|
lockSize: false
|
|
45
45
|
} : panel)
|
|
46
46
|
};
|
|
47
|
+
case "LOCK_PANEL_POSITION": return {
|
|
48
|
+
...state,
|
|
49
|
+
panels: state.panels.map((panel) => panel.id === action.panelId ? {
|
|
50
|
+
...panel,
|
|
51
|
+
lockPosition: true
|
|
52
|
+
} : panel)
|
|
53
|
+
};
|
|
54
|
+
case "UNLOCK_PANEL_POSITION": return {
|
|
55
|
+
...state,
|
|
56
|
+
panels: state.panels.map((panel) => panel.id === action.panelId ? {
|
|
57
|
+
...panel,
|
|
58
|
+
lockPosition: false
|
|
59
|
+
} : panel)
|
|
60
|
+
};
|
|
47
61
|
default: return state;
|
|
48
62
|
}
|
|
49
63
|
}
|
|
@@ -119,12 +133,14 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
119
133
|
animationTimeoutsRef.current.delete(timeoutId);
|
|
120
134
|
}, ANIMATION_DURATION);
|
|
121
135
|
animationTimeoutsRef.current.add(timeoutId);
|
|
136
|
+
return nextPanels;
|
|
122
137
|
}, [
|
|
123
138
|
columnCount,
|
|
124
139
|
internalState,
|
|
125
140
|
rearrangement
|
|
126
141
|
]);
|
|
127
142
|
const createDragHandler = (0, react.useCallback)((panel) => (e) => {
|
|
143
|
+
if (panel.lockPosition) return;
|
|
128
144
|
internalState.activePanelId = panel.id;
|
|
129
145
|
const draggingElement = internalState.draggableElements[panel.id];
|
|
130
146
|
if (!draggingElement) return;
|
|
@@ -165,19 +181,21 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
165
181
|
const droppedTop = parseFloat(draggingElement.style.top) || 0;
|
|
166
182
|
const nextGridX = require_gridCalculations.pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);
|
|
167
183
|
const nextGridY = require_gridCalculations.pixelsToGridPosition(droppedTop, baseSize, gap);
|
|
184
|
+
const resultPanel = updatePanelsWithAnimation({
|
|
185
|
+
...panel,
|
|
186
|
+
x: nextGridX,
|
|
187
|
+
y: nextGridY
|
|
188
|
+
}, state.panels).find((p) => p.id === panel.id);
|
|
189
|
+
const actualGridX = resultPanel?.x ?? nextGridX;
|
|
190
|
+
const actualGridY = resultPanel?.y ?? nextGridY;
|
|
168
191
|
require_animation.applySnapAnimation({
|
|
169
192
|
element: draggingElement,
|
|
170
193
|
droppedLeft,
|
|
171
194
|
droppedTop,
|
|
172
|
-
nextLeft: require_gridCalculations.gridPositionToPixels(
|
|
173
|
-
nextTop: require_gridCalculations.gridPositionToPixels(
|
|
195
|
+
nextLeft: require_gridCalculations.gridPositionToPixels(actualGridX, baseSize, gap),
|
|
196
|
+
nextTop: require_gridCalculations.gridPositionToPixels(actualGridY, baseSize, gap),
|
|
174
197
|
originalTransition
|
|
175
198
|
});
|
|
176
|
-
updatePanelsWithAnimation({
|
|
177
|
-
...panel,
|
|
178
|
-
x: nextGridX,
|
|
179
|
-
y: nextGridY
|
|
180
|
-
}, state.panels);
|
|
181
199
|
document.body.classList.remove("panelgrid-dragging");
|
|
182
200
|
internalState.activePanelId = null;
|
|
183
201
|
mouseMoveListenerCtrl.abort();
|
|
@@ -254,10 +272,21 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
254
272
|
const nextGridY = require_gridCalculations.pixelsToGridPosition(droppedTop, baseSize, gap);
|
|
255
273
|
const nextGridW = require_gridCalculations.pixelsToGridSize(rect.width, baseSize, gap, columnCount, nextGridX);
|
|
256
274
|
const nextGridH = require_gridCalculations.pixelsToGridSize(rect.height, baseSize, gap, columnCount, nextGridY);
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
275
|
+
const resultPanel = updatePanelsWithAnimation({
|
|
276
|
+
...panel,
|
|
277
|
+
x: nextGridX,
|
|
278
|
+
y: nextGridY,
|
|
279
|
+
w: nextGridW,
|
|
280
|
+
h: nextGridH
|
|
281
|
+
}, state.panels).find((p) => p.id === panel.id);
|
|
282
|
+
const actualX = resultPanel?.x ?? nextGridX;
|
|
283
|
+
const actualY = resultPanel?.y ?? nextGridY;
|
|
284
|
+
const actualW = resultPanel?.w ?? nextGridW;
|
|
285
|
+
const actualH = resultPanel?.h ?? nextGridH;
|
|
286
|
+
const left = require_gridCalculations.gridPositionToPixels(actualX, baseSize, gap);
|
|
287
|
+
const top = require_gridCalculations.gridPositionToPixels(actualY, baseSize, gap);
|
|
288
|
+
const width = require_gridCalculations.gridToPixels(actualW, baseSize, gap);
|
|
289
|
+
const height = require_gridCalculations.gridToPixels(actualH, baseSize, gap);
|
|
261
290
|
draggingElement.style.width = `${rect.width}px`;
|
|
262
291
|
draggingElement.style.height = `${rect.height}px`;
|
|
263
292
|
draggingElement.style.cursor = initialCursor;
|
|
@@ -270,13 +299,6 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
270
299
|
draggingElement.style.zIndex = initialZIndex;
|
|
271
300
|
draggingElement.style.transition = "width 0.1s ease-out, height 0.1s ease-out, top 0.1s ease-out, left 0.1s ease-out";
|
|
272
301
|
});
|
|
273
|
-
updatePanelsWithAnimation({
|
|
274
|
-
...panel,
|
|
275
|
-
x: nextGridX,
|
|
276
|
-
y: nextGridY,
|
|
277
|
-
w: nextGridW,
|
|
278
|
-
h: nextGridH
|
|
279
|
-
}, state.panels);
|
|
280
302
|
isResizing = false;
|
|
281
303
|
internalState.activePanelId = null;
|
|
282
304
|
document.body.classList.remove("panelgrid-resizing");
|
|
@@ -310,6 +332,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
310
332
|
panelProps: {
|
|
311
333
|
key: panel.id,
|
|
312
334
|
lockSize: panel.lockSize,
|
|
335
|
+
lockPosition: panel.lockPosition,
|
|
313
336
|
positionData: {
|
|
314
337
|
x: panel.x,
|
|
315
338
|
y: panel.y,
|
|
@@ -369,6 +392,18 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
369
392
|
panelId: id
|
|
370
393
|
});
|
|
371
394
|
}, []),
|
|
395
|
+
lockPanelPosition: (0, react.useCallback)((id) => {
|
|
396
|
+
dispatch({
|
|
397
|
+
type: "LOCK_PANEL_POSITION",
|
|
398
|
+
panelId: id
|
|
399
|
+
});
|
|
400
|
+
}, []),
|
|
401
|
+
unlockPanelPosition: (0, react.useCallback)((id) => {
|
|
402
|
+
dispatch({
|
|
403
|
+
type: "UNLOCK_PANEL_POSITION",
|
|
404
|
+
panelId: id
|
|
405
|
+
});
|
|
406
|
+
}, []),
|
|
372
407
|
exportState: (0, react.useCallback)(() => {
|
|
373
408
|
return state.panels;
|
|
374
409
|
}, [state.panels])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePanelGrid.cjs","names":["findNewPositionToAddPanel","newPanelCoordinate: PanelCoordinate","RESIZE_CURSOR_MAP: Record<string, string>","rearrangePanels","detectAnimatingPanels","e","pixelsToGridPosition","gridPositionToPixels","pixelsToGridSize","gridToPixels"],"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.cjs","names":["findNewPositionToAddPanel","newPanelCoordinate: PanelCoordinate","RESIZE_CURSOR_MAP: Record<string, string>","rearrangePanels","detectAnimatingPanels","e","pixelsToGridPosition","gridPositionToPixels","pixelsToGridSize","gridToPixels"],"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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"}
|
package/dist/usePanelGrid.d.cts
CHANGED
|
@@ -22,6 +22,7 @@ declare function usePanelGrid({
|
|
|
22
22
|
panelProps: {
|
|
23
23
|
key: PanelId;
|
|
24
24
|
lockSize: boolean | undefined;
|
|
25
|
+
lockPosition: boolean | undefined;
|
|
25
26
|
positionData: {
|
|
26
27
|
x: number;
|
|
27
28
|
y: number;
|
|
@@ -48,6 +49,8 @@ declare function usePanelGrid({
|
|
|
48
49
|
removePanel: (id: PanelId) => void;
|
|
49
50
|
lockPanelSize: (id: PanelId) => void;
|
|
50
51
|
unlockPanelSize: (id: PanelId) => void;
|
|
52
|
+
lockPanelPosition: (id: PanelId) => void;
|
|
53
|
+
unlockPanelPosition: (id: PanelId) => void;
|
|
51
54
|
exportState: () => PanelCoordinate[];
|
|
52
55
|
};
|
|
53
56
|
//#endregion
|
package/dist/usePanelGrid.d.mts
CHANGED
|
@@ -22,6 +22,7 @@ declare function usePanelGrid({
|
|
|
22
22
|
panelProps: {
|
|
23
23
|
key: PanelId;
|
|
24
24
|
lockSize: boolean | undefined;
|
|
25
|
+
lockPosition: boolean | undefined;
|
|
25
26
|
positionData: {
|
|
26
27
|
x: number;
|
|
27
28
|
y: number;
|
|
@@ -48,6 +49,8 @@ declare function usePanelGrid({
|
|
|
48
49
|
removePanel: (id: PanelId) => void;
|
|
49
50
|
lockPanelSize: (id: PanelId) => void;
|
|
50
51
|
unlockPanelSize: (id: PanelId) => void;
|
|
52
|
+
lockPanelPosition: (id: PanelId) => void;
|
|
53
|
+
unlockPanelPosition: (id: PanelId) => void;
|
|
51
54
|
exportState: () => PanelCoordinate[];
|
|
52
55
|
};
|
|
53
56
|
//#endregion
|
package/dist/usePanelGrid.mjs
CHANGED
|
@@ -44,6 +44,20 @@ function panelGridReducer(state, action) {
|
|
|
44
44
|
lockSize: false
|
|
45
45
|
} : panel)
|
|
46
46
|
};
|
|
47
|
+
case "LOCK_PANEL_POSITION": return {
|
|
48
|
+
...state,
|
|
49
|
+
panels: state.panels.map((panel) => panel.id === action.panelId ? {
|
|
50
|
+
...panel,
|
|
51
|
+
lockPosition: true
|
|
52
|
+
} : panel)
|
|
53
|
+
};
|
|
54
|
+
case "UNLOCK_PANEL_POSITION": return {
|
|
55
|
+
...state,
|
|
56
|
+
panels: state.panels.map((panel) => panel.id === action.panelId ? {
|
|
57
|
+
...panel,
|
|
58
|
+
lockPosition: false
|
|
59
|
+
} : panel)
|
|
60
|
+
};
|
|
47
61
|
default: return state;
|
|
48
62
|
}
|
|
49
63
|
}
|
|
@@ -119,12 +133,14 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
119
133
|
animationTimeoutsRef.current.delete(timeoutId);
|
|
120
134
|
}, ANIMATION_DURATION);
|
|
121
135
|
animationTimeoutsRef.current.add(timeoutId);
|
|
136
|
+
return nextPanels;
|
|
122
137
|
}, [
|
|
123
138
|
columnCount,
|
|
124
139
|
internalState,
|
|
125
140
|
rearrangement
|
|
126
141
|
]);
|
|
127
142
|
const createDragHandler = useCallback((panel) => (e) => {
|
|
143
|
+
if (panel.lockPosition) return;
|
|
128
144
|
internalState.activePanelId = panel.id;
|
|
129
145
|
const draggingElement = internalState.draggableElements[panel.id];
|
|
130
146
|
if (!draggingElement) return;
|
|
@@ -165,19 +181,21 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
165
181
|
const droppedTop = parseFloat(draggingElement.style.top) || 0;
|
|
166
182
|
const nextGridX = pixelsToGridPosition(droppedLeft, baseSize, gap, columnCount, panel.w);
|
|
167
183
|
const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);
|
|
184
|
+
const resultPanel = updatePanelsWithAnimation({
|
|
185
|
+
...panel,
|
|
186
|
+
x: nextGridX,
|
|
187
|
+
y: nextGridY
|
|
188
|
+
}, state.panels).find((p) => p.id === panel.id);
|
|
189
|
+
const actualGridX = resultPanel?.x ?? nextGridX;
|
|
190
|
+
const actualGridY = resultPanel?.y ?? nextGridY;
|
|
168
191
|
applySnapAnimation({
|
|
169
192
|
element: draggingElement,
|
|
170
193
|
droppedLeft,
|
|
171
194
|
droppedTop,
|
|
172
|
-
nextLeft: gridPositionToPixels(
|
|
173
|
-
nextTop: gridPositionToPixels(
|
|
195
|
+
nextLeft: gridPositionToPixels(actualGridX, baseSize, gap),
|
|
196
|
+
nextTop: gridPositionToPixels(actualGridY, baseSize, gap),
|
|
174
197
|
originalTransition
|
|
175
198
|
});
|
|
176
|
-
updatePanelsWithAnimation({
|
|
177
|
-
...panel,
|
|
178
|
-
x: nextGridX,
|
|
179
|
-
y: nextGridY
|
|
180
|
-
}, state.panels);
|
|
181
199
|
document.body.classList.remove("panelgrid-dragging");
|
|
182
200
|
internalState.activePanelId = null;
|
|
183
201
|
mouseMoveListenerCtrl.abort();
|
|
@@ -254,10 +272,21 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
254
272
|
const nextGridY = pixelsToGridPosition(droppedTop, baseSize, gap);
|
|
255
273
|
const nextGridW = pixelsToGridSize(rect.width, baseSize, gap, columnCount, nextGridX);
|
|
256
274
|
const nextGridH = pixelsToGridSize(rect.height, baseSize, gap, columnCount, nextGridY);
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
275
|
+
const resultPanel = updatePanelsWithAnimation({
|
|
276
|
+
...panel,
|
|
277
|
+
x: nextGridX,
|
|
278
|
+
y: nextGridY,
|
|
279
|
+
w: nextGridW,
|
|
280
|
+
h: nextGridH
|
|
281
|
+
}, state.panels).find((p) => p.id === panel.id);
|
|
282
|
+
const actualX = resultPanel?.x ?? nextGridX;
|
|
283
|
+
const actualY = resultPanel?.y ?? nextGridY;
|
|
284
|
+
const actualW = resultPanel?.w ?? nextGridW;
|
|
285
|
+
const actualH = resultPanel?.h ?? nextGridH;
|
|
286
|
+
const left = gridPositionToPixels(actualX, baseSize, gap);
|
|
287
|
+
const top = gridPositionToPixels(actualY, baseSize, gap);
|
|
288
|
+
const width = gridToPixels(actualW, baseSize, gap);
|
|
289
|
+
const height = gridToPixels(actualH, baseSize, gap);
|
|
261
290
|
draggingElement.style.width = `${rect.width}px`;
|
|
262
291
|
draggingElement.style.height = `${rect.height}px`;
|
|
263
292
|
draggingElement.style.cursor = initialCursor;
|
|
@@ -270,13 +299,6 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
270
299
|
draggingElement.style.zIndex = initialZIndex;
|
|
271
300
|
draggingElement.style.transition = "width 0.1s ease-out, height 0.1s ease-out, top 0.1s ease-out, left 0.1s ease-out";
|
|
272
301
|
});
|
|
273
|
-
updatePanelsWithAnimation({
|
|
274
|
-
...panel,
|
|
275
|
-
x: nextGridX,
|
|
276
|
-
y: nextGridY,
|
|
277
|
-
w: nextGridW,
|
|
278
|
-
h: nextGridH
|
|
279
|
-
}, state.panels);
|
|
280
302
|
isResizing = false;
|
|
281
303
|
internalState.activePanelId = null;
|
|
282
304
|
document.body.classList.remove("panelgrid-resizing");
|
|
@@ -310,6 +332,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
310
332
|
panelProps: {
|
|
311
333
|
key: panel.id,
|
|
312
334
|
lockSize: panel.lockSize,
|
|
335
|
+
lockPosition: panel.lockPosition,
|
|
313
336
|
positionData: {
|
|
314
337
|
x: panel.x,
|
|
315
338
|
y: panel.y,
|
|
@@ -369,6 +392,18 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
|
|
|
369
392
|
panelId: id
|
|
370
393
|
});
|
|
371
394
|
}, []),
|
|
395
|
+
lockPanelPosition: useCallback((id) => {
|
|
396
|
+
dispatch({
|
|
397
|
+
type: "LOCK_PANEL_POSITION",
|
|
398
|
+
panelId: id
|
|
399
|
+
});
|
|
400
|
+
}, []),
|
|
401
|
+
unlockPanelPosition: useCallback((id) => {
|
|
402
|
+
dispatch({
|
|
403
|
+
type: "UNLOCK_PANEL_POSITION",
|
|
404
|
+
panelId: id
|
|
405
|
+
});
|
|
406
|
+
}, []),
|
|
372
407
|
exportState: useCallback(() => {
|
|
373
408
|
return state.panels;
|
|
374
409
|
}, [state.panels])
|