panelgrid 0.4.3 → 0.4.4

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/README.md CHANGED
@@ -227,7 +227,12 @@ PanelGrid uses non-scoped CSS classes with the `panelgrid-` prefix, allowing you
227
227
  - `.panelgrid-panel-ghost` - Ghost panel shown during drag/resize operations
228
228
  - `.panelgrid-panel--dragging` - Applied to a panel while it's being dragged
229
229
  - `.panelgrid-panel--with-transition` - Applied to panels that are animating to new positions
230
- - `.panelgrid-resize-handle` - Resize handle in the bottom-right corner of panels
230
+ - `.panelgrid-panel--size-locked` - Applied to panels with `lockSize: true`
231
+ - `.panelgrid-panel--position-locked` - Applied to panels with `lockPosition: true`
232
+ - `.panelgrid-resize-handle` - Resize handle element
233
+ - `.panelgrid-resize-handle--{position}` - Position-specific resize handle (e.g. `--se`, `--nw`); see `ResizeHandlePosition` type for all values
234
+ - `.panelgrid-resizing` - Applied to `<body>` while a resize is in progress
235
+ - `.panelgrid-dragging` - Applied to `<body>` while a drag is in progress
231
236
 
232
237
  #### Example: Custom Panel Styling
233
238
 
@@ -305,6 +310,7 @@ The renderer uses CSS custom properties that you can use in your custom styles:
305
310
 
306
311
  - `--column-count` - Number of grid columns (set automatically)
307
312
  - `--gap` - Gap between panels in pixels
313
+ - `--panelgrid-handle-color` - Color of the resize handle icon (default: `#000`)
308
314
 
309
315
  ```css
310
316
  /* Example: Use custom properties in your styles */
@@ -325,6 +331,7 @@ The main provider component that manages panel state.
325
331
  - `panels`: `PanelCoordinate[]` - Array of panel configurations
326
332
  - `columnCount`: `number` - Number of columns in the grid
327
333
  - `gap`: `number` - Gap between panels in pixels
334
+ - `resizeHandlePositions?`: `ResizeHandlePosition[]` - Positions to render resize handles (default: `["se"]`)
328
335
  - `rearrangement?`: `RearrangementFunction` - Optional custom rearrangement logic (see [Custom Rearrangement Logic](#custom-rearrangement-logic))
329
336
 
330
337
  ### `<PanelGridRenderer>`
@@ -366,6 +373,10 @@ Hook to access panel control functions.
366
373
 
367
374
  - `addPanel(panel: Partial<PanelCoordinate>)`: Add a new panel
368
375
  - `removePanel(id: PanelId)`: Remove a panel by ID
376
+ - `lockPanelSize(id: PanelId)`: Prevent a panel from being resized
377
+ - `unlockPanelSize(id: PanelId)`: Allow a panel to be resized again
378
+ - `lockPanelPosition(id: PanelId)`: Prevent a panel from being moved or pushed by other panels
379
+ - `unlockPanelPosition(id: PanelId)`: Allow a panel to be moved again
369
380
  - `exportState()`: Export current panel state
370
381
 
371
382
  ### Types
@@ -375,13 +386,16 @@ type PanelId = number | string;
375
386
 
376
387
  interface PanelCoordinate {
377
388
  id: PanelId;
378
- x: number; // Column position (0-indexed)
379
- y: number; // Row position (0-indexed)
380
- w: number; // Width in columns
381
- h: number; // Height in rows
382
- lockSize?: boolean; // If true, prevents panel from being resized
389
+ x: number; // Column position (0-indexed)
390
+ y: number; // Row position (0-indexed)
391
+ w: number; // Width in columns
392
+ h: number; // Height in rows
393
+ lockSize?: boolean; // If true, prevents panel from being resized
394
+ lockPosition?: boolean; // If true, prevents panel from being moved or pushed
383
395
  }
384
396
 
397
+ type ResizeHandlePosition = "n" | "e" | "s" | "w" | "ne" | "nw" | "se" | "sw";
398
+
385
399
  type RearrangementFunction = (
386
400
  movingPanel: PanelCoordinate,
387
401
  allPanels: PanelCoordinate[],
@@ -51,11 +51,12 @@ function PanelGridRenderer({ children: ItemComponent }) {
51
51
  }),
52
52
  panels.map((panel) => {
53
53
  const { panelProps, resizeHandleProps } = panel;
54
- const { key, lockSize, lockPosition, style, positionData, ref, onMouseDown } = panelProps;
54
+ const { key, lockSize, lockPosition, isAnimating, style, positionData, ref, onMouseDown } = panelProps;
55
55
  const className = [
56
56
  "panelgrid-panel",
57
57
  lockSize ? "panelgrid-panel--size-locked" : "",
58
- lockPosition ? "panelgrid-panel--position-locked" : ""
58
+ lockPosition ? "panelgrid-panel--position-locked" : "",
59
+ isAnimating ? "panelgrid-panel--with-transition" : ""
59
60
  ].filter(Boolean).join(" ");
60
61
  const { x, y, w, h } = positionData;
61
62
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"PanelGridRenderer.cjs","names":["usePanelGridState","usePanelGridControls","getGridRowCount"],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentType } from \"react\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n children: ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ children: ItemComponent }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, resizeHandlePositions, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n // biome-ignore lint/suspicious/noArrayIndexKey: The order of placeholders will not be changed.\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, lockPosition, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = [\n \"panelgrid-panel\",\n lockSize ? \"panelgrid-panel--size-locked\" : \"\",\n lockPosition ? \"panelgrid-panel--position-locked\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemComponent id={key} />\n {resizeHandleProps &&\n resizeHandlePositions.map((pos) => {\n return (\n <span\n key={pos}\n className={`panelgrid-resize-handle panelgrid-resize-handle--${pos}`}\n {...resizeHandleProps}\n data-pg-resize-handle={pos}\n />\n );\n })}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,kBAAkB,EAAE,UAAU,iBAAyC;CACrF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,uBAAuB,kBAAkBA,6CAAmB;CACxG,MAAM,EAAE,gBAAgBC,gDAAsB;CAC9C,MAAM,iCAA6C,KAAK;CACxD,MAAM,WAAWC,yCACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,kCAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,4CAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAE3C,WAAO,2CAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,2CAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,cAAc,OAAO,cAAc,KAAK,gBAAgB;IAE/E,MAAM,YAAY;KAChB;KACA,WAAW,iCAAiC;KAC5C,eAAe,qCAAqC;KACrD,CACE,OAAO,QAAQ,CACf,KAAK,IAAI;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,4CAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,2CAAC,iBAAc,IAAI,MAAO,EACzB,qBACC,sBAAsB,KAAK,QAAQ;AACjC,aACE,2CAAC;OAEC,WAAW,oDAAoD;OAC/D,GAAI;OACJ,yBAAuB;SAHlB,IAIL;OAEJ;OAtBC,IAuBD;KAER;;GACE"}
1
+ {"version":3,"file":"PanelGridRenderer.cjs","names":["usePanelGridState","usePanelGridControls","getGridRowCount"],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentType } from \"react\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n children: ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ children: ItemComponent }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, resizeHandlePositions, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n // biome-ignore lint/suspicious/noArrayIndexKey: The order of placeholders will not be changed.\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, lockPosition, isAnimating, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = [\n \"panelgrid-panel\",\n lockSize ? \"panelgrid-panel--size-locked\" : \"\",\n lockPosition ? \"panelgrid-panel--position-locked\" : \"\",\n isAnimating ? \"panelgrid-panel--with-transition\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemComponent id={key} />\n {resizeHandleProps &&\n resizeHandlePositions.map((pos) => {\n return (\n <span\n key={pos}\n className={`panelgrid-resize-handle panelgrid-resize-handle--${pos}`}\n {...resizeHandleProps}\n data-pg-resize-handle={pos}\n />\n );\n })}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,kBAAkB,EAAE,UAAU,iBAAyC;CACrF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,uBAAuB,kBAAkBA,6CAAmB;CACxG,MAAM,EAAE,gBAAgBC,gDAAsB;CAC9C,MAAM,iCAA6C,KAAK;CACxD,MAAM,WAAWC,yCACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,kCAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,4CAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAE3C,WAAO,2CAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,2CAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,cAAc,aAAa,OAAO,cAAc,KAAK,gBAAgB;IAE5F,MAAM,YAAY;KAChB;KACA,WAAW,iCAAiC;KAC5C,eAAe,qCAAqC;KACpD,cAAc,qCAAqC;KACpD,CACE,OAAO,QAAQ,CACf,KAAK,IAAI;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,4CAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,2CAAC,iBAAc,IAAI,MAAO,EACzB,qBACC,sBAAsB,KAAK,QAAQ;AACjC,aACE,2CAAC;OAEC,WAAW,oDAAoD;OAC/D,GAAI;OACJ,yBAAuB;SAHlB,IAIL;OAEJ;OAtBC,IAuBD;KAER;;GACE"}
@@ -51,11 +51,12 @@ function PanelGridRenderer({ children: ItemComponent }) {
51
51
  }),
52
52
  panels.map((panel) => {
53
53
  const { panelProps, resizeHandleProps } = panel;
54
- const { key, lockSize, lockPosition, style, positionData, ref, onMouseDown } = panelProps;
54
+ const { key, lockSize, lockPosition, isAnimating, style, positionData, ref, onMouseDown } = panelProps;
55
55
  const className = [
56
56
  "panelgrid-panel",
57
57
  lockSize ? "panelgrid-panel--size-locked" : "",
58
- lockPosition ? "panelgrid-panel--position-locked" : ""
58
+ lockPosition ? "panelgrid-panel--position-locked" : "",
59
+ isAnimating ? "panelgrid-panel--with-transition" : ""
59
60
  ].filter(Boolean).join(" ");
60
61
  const { x, y, w, h } = positionData;
61
62
  return /* @__PURE__ */ jsxs("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"PanelGridRenderer.mjs","names":[],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentType } from \"react\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n children: ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ children: ItemComponent }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, resizeHandlePositions, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n // biome-ignore lint/suspicious/noArrayIndexKey: The order of placeholders will not be changed.\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, lockPosition, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = [\n \"panelgrid-panel\",\n lockSize ? \"panelgrid-panel--size-locked\" : \"\",\n lockPosition ? \"panelgrid-panel--position-locked\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemComponent id={key} />\n {resizeHandleProps &&\n resizeHandlePositions.map((pos) => {\n return (\n <span\n key={pos}\n className={`panelgrid-resize-handle panelgrid-resize-handle--${pos}`}\n {...resizeHandleProps}\n data-pg-resize-handle={pos}\n />\n );\n })}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,kBAAkB,EAAE,UAAU,iBAAyC;CACrF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,uBAAuB,kBAAkB,mBAAmB;CACxG,MAAM,EAAE,gBAAgB,sBAAsB;CAC9C,MAAM,eAAe,OAA8B,KAAK;CACxD,MAAM,WAAW,gBACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,uBAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,qBAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAE3C,WAAO,oBAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,oBAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,cAAc,OAAO,cAAc,KAAK,gBAAgB;IAE/E,MAAM,YAAY;KAChB;KACA,WAAW,iCAAiC;KAC5C,eAAe,qCAAqC;KACrD,CACE,OAAO,QAAQ,CACf,KAAK,IAAI;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,qBAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,oBAAC,iBAAc,IAAI,MAAO,EACzB,qBACC,sBAAsB,KAAK,QAAQ;AACjC,aACE,oBAAC;OAEC,WAAW,oDAAoD;OAC/D,GAAI;OACJ,yBAAuB;SAHlB,IAIL;OAEJ;OAtBC,IAuBD;KAER;;GACE"}
1
+ {"version":3,"file":"PanelGridRenderer.mjs","names":[],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentType } from \"react\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n children: ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ children: ItemComponent }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, resizeHandlePositions, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n // biome-ignore lint/suspicious/noArrayIndexKey: The order of placeholders will not be changed.\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, lockPosition, isAnimating, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = [\n \"panelgrid-panel\",\n lockSize ? \"panelgrid-panel--size-locked\" : \"\",\n lockPosition ? \"panelgrid-panel--position-locked\" : \"\",\n isAnimating ? \"panelgrid-panel--with-transition\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemComponent id={key} />\n {resizeHandleProps &&\n resizeHandlePositions.map((pos) => {\n return (\n <span\n key={pos}\n className={`panelgrid-resize-handle panelgrid-resize-handle--${pos}`}\n {...resizeHandleProps}\n data-pg-resize-handle={pos}\n />\n );\n })}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,kBAAkB,EAAE,UAAU,iBAAyC;CACrF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,uBAAuB,kBAAkB,mBAAmB;CACxG,MAAM,EAAE,gBAAgB,sBAAsB;CAC9C,MAAM,eAAe,OAA8B,KAAK;CACxD,MAAM,WAAW,gBACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,uBAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,qBAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAE3C,WAAO,oBAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,oBAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,cAAc,aAAa,OAAO,cAAc,KAAK,gBAAgB;IAE5F,MAAM,YAAY;KAChB;KACA,WAAW,iCAAiC;KAC5C,eAAe,qCAAqC;KACpD,cAAc,qCAAqC;KACpD,CACE,OAAO,QAAQ,CACf,KAAK,IAAI;IACZ,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,qBAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,oBAAC,iBAAc,IAAI,MAAO,EACzB,qBACC,sBAAsB,KAAK,QAAQ;AACjC,aACE,oBAAC;OAEC,WAAW,oDAAoD;OAC/D,GAAI;OACJ,yBAAuB;SAHlB,IAIL;OAEJ;OAtBC,IAuBD;KAER;;GACE"}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.cjs";
1
+ import { PanelCoordinate, PanelId, RearrangementFunction, ResizeHandlePosition } from "./types.cjs";
2
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, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
6
+ export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, type ResizeHandlePosition, rearrangePanels, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.mjs";
1
+ import { PanelCoordinate, PanelId, RearrangementFunction, ResizeHandlePosition } from "./types.mjs";
2
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, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
6
+ export { type PanelCoordinate, PanelGridProvider, PanelGridRenderer, type PanelId, type RearrangementFunction, type ResizeHandlePosition, rearrangePanels, resolveWithLockRollback, usePanel, usePanelGridControls, usePanelGridState };
package/dist/styles.css CHANGED
@@ -54,6 +54,9 @@
54
54
  z-index: calc(infinity);
55
55
  }
56
56
 
57
+ .panelgrid-panel--size-locked {
58
+ }
59
+
57
60
  .panelgrid-panel--position-locked {
58
61
  cursor: default;
59
62
  }
@@ -333,6 +333,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
333
333
  key: panel.id,
334
334
  lockSize: panel.lockSize,
335
335
  lockPosition: panel.lockPosition,
336
+ isAnimating: isAnimating && !isActive,
336
337
  positionData: {
337
338
  x: panel.x,
338
339
  y: panel.y,
@@ -343,8 +344,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
343
344
  top: require_gridCalculations.gridPositionToPixels(panel.y, baseSize, gap),
344
345
  left: require_gridCalculations.gridPositionToPixels(panel.x, baseSize, gap),
345
346
  width: require_gridCalculations.gridToPixels(panel.w, baseSize, gap),
346
- height: require_gridCalculations.gridToPixels(panel.h, baseSize, gap),
347
- transition: isAnimating && !isActive ? "top 0.3s ease-out, left 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out" : void 0
347
+ height: require_gridCalculations.gridToPixels(panel.h, baseSize, gap)
348
348
  },
349
349
  ref: createRefCallback(panel.id),
350
350
  onMouseDown: createDragHandler(panel)
@@ -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 | { 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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"}
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 isAnimating: isAnimating && !isActive,\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 },\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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"}
@@ -23,6 +23,7 @@ declare function usePanelGrid({
23
23
  key: PanelId;
24
24
  lockSize: boolean | undefined;
25
25
  lockPosition: boolean | undefined;
26
+ isAnimating: boolean;
26
27
  positionData: {
27
28
  x: number;
28
29
  y: number;
@@ -34,7 +35,6 @@ declare function usePanelGrid({
34
35
  left: number;
35
36
  width: number;
36
37
  height: number;
37
- transition: string | undefined;
38
38
  };
39
39
  ref: (element: HTMLElement | null) => void;
40
40
  onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => void;
@@ -23,6 +23,7 @@ declare function usePanelGrid({
23
23
  key: PanelId;
24
24
  lockSize: boolean | undefined;
25
25
  lockPosition: boolean | undefined;
26
+ isAnimating: boolean;
26
27
  positionData: {
27
28
  x: number;
28
29
  y: number;
@@ -34,7 +35,6 @@ declare function usePanelGrid({
34
35
  left: number;
35
36
  width: number;
36
37
  height: number;
37
- transition: string | undefined;
38
38
  };
39
39
  ref: (element: HTMLElement | null) => void;
40
40
  onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => void;
@@ -333,6 +333,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
333
333
  key: panel.id,
334
334
  lockSize: panel.lockSize,
335
335
  lockPosition: panel.lockPosition,
336
+ isAnimating: isAnimating && !isActive,
336
337
  positionData: {
337
338
  x: panel.x,
338
339
  y: panel.y,
@@ -343,8 +344,7 @@ function usePanelGrid({ panels, columnCount, baseSize, gap, resizeHandlePosition
343
344
  top: gridPositionToPixels(panel.y, baseSize, gap),
344
345
  left: gridPositionToPixels(panel.x, baseSize, gap),
345
346
  width: gridToPixels(panel.w, baseSize, gap),
346
- height: gridToPixels(panel.h, baseSize, gap),
347
- transition: isAnimating && !isActive ? "top 0.3s ease-out, left 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out" : void 0
347
+ height: gridToPixels(panel.h, baseSize, gap)
348
348
  },
349
349
  ref: createRefCallback(panel.id),
350
350
  onMouseDown: createDragHandler(panel)
@@ -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 | { 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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"}
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 isAnimating: isAnimating && !isActive,\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 },\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panelgrid",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "A flexible and performant React grid layout library with drag-and-drop and resize capabilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",