react-zeugma 0.6.1 → 0.7.0
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 +6 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,6 +181,10 @@ Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _c
|
|
|
181
181
|
|
|
182
182
|
Splits the entire dashboard tree at the root, placing the dragged `draggingId` pane on one half and the rest of the layout tree on the other.
|
|
183
183
|
|
|
184
|
+
#### `findPane(tree: TreeNode | null, paneId: string): PaneNode | null`
|
|
185
|
+
|
|
186
|
+
Recursively searches the layout tree and returns the target `PaneNode` if found, or `null` otherwise.
|
|
187
|
+
|
|
184
188
|
---
|
|
185
189
|
|
|
186
190
|
## Custom Styling
|
|
@@ -425,6 +429,8 @@ Import these helpers from `react-zeugma` to manipulate the tree layout programma
|
|
|
425
429
|
Swaps the positions of two panes in the tree.
|
|
426
430
|
- **`updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null`**
|
|
427
431
|
Updates the metadata of a specific pane.
|
|
432
|
+
- **`findPane(tree: TreeNode | null, paneId: string): PaneNode | null`**
|
|
433
|
+
Recursively searches the layout tree and returns the target `PaneNode` if found, or `null` otherwise.
|
|
428
434
|
|
|
429
435
|
Alternatively, you can consume the convenient mutation helpers directly from the **`useDashboard()`** context hook inside pane components without importing utilities:
|
|
430
436
|
|
package/dist/index.cjs
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
cursor: ${t?"col-resize":"row-resize"} !important;
|
|
4
4
|
user-select: none !important;
|
|
5
5
|
}
|
|
6
|
-
`,document.head.appendChild(F),v&&v(),a&&a(c);let f=x.getBoundingClientRect(),Z=m.clientX,_=m.clientY,S=n,k=m.currentTarget;k.setAttribute("data-resizing","true");let Y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(b=>b!==k&&b.getAttribute("data-direction")===o).map(b=>{let y=b.getBoundingClientRect();return t?y.left+y.width/2:y.top+y.height/2}),O=S,U=b=>{let y=t?(b.clientX-Z)/f.width*100:(b.clientY-_)/f.height*100,p=S+y,u=t?f.left+(f.width-r)*(p/100)+r/2:f.top+(f.height-r)*(p/100)+r/2,R=1/0,d=null;for(let B of Y){let C=Math.abs(u-B);C<i&&C<R&&(R=C,d=B);}let E=p;d!==null&&(E=t?(d-r/2-f.left)/(f.width-r)*100:(d-r/2-f.top)/(f.height-r)*100);let T=Math.max(w,Math.min(P,E));O=T;let A=H(s,c,T);N(A),l&&l(c,T);},V=()=>{document.body.classList.remove("zeugma-resizing"),k.removeAttribute("data-resizing");let b=document.getElementById("zeugma-global-cursor-style");b&&b.remove(),document.removeEventListener("pointermove",U),document.removeEventListener("pointerup",V),h&&h(),g&&g(c,O);};document.addEventListener("pointermove",U),document.addEventListener("pointerup",V);},[e,t,o,n,r,i,s,c,N,v,h,a,l,g,w,P])}var Ue=({currentNode:e,resizerSize:t,snapThreshold:o,renderResizer:n})=>{let{layout:r,onLayoutChange:i,classNames:s,renderResizer:c}=M(),[N,v]=react.useState(false),h=n||c,a=react.useRef(null),{direction:l,first:g,second:w,splitPercentage:P}=e,m=l==="row",x=ne({containerRef:a,isRow:m,direction:l,splitPercentage:P,resizerSize:t,snapThreshold:o??8,layout:r,currentNode:e,onLayoutChange:i,onResizeStart:()=>v(true),onResizeEnd:()=>v(false)});return jsxRuntime.jsxs("div",{ref:a,style:{display:"flex",flexDirection:m?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${P} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(oe,{tree:g,resizerSize:t,snapThreshold:o,renderResizer:n})}),h?h({direction:l,splitPercentage:P,resizerSize:t,isResizing:N,onPointerDown:x}):jsxRuntime.jsx("div",{className:s.resizer,"data-direction":l,style:{width:m?`${t}px`:"100%",height:m?"100%":`${t}px`,cursor:m?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:x,role:"separator","aria-valuenow":P,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-P} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(oe,{tree:w,resizerSize:t,snapThreshold:o,renderResizer:n})})]})},oe=({tree:e,resizerSize:t=4,snapThreshold:o,renderResizer:n})=>{let{layout:r,renderPane:i,activeId:s,classNames:c,fullscreenPaneId:N,snapThreshold:v}=M(),h=o!==void 0?o:v,a=react.useMemo(()=>s?z(r,s)!==null:false,[r,s]);if(N&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(N)});let l=e!==void 0?e:r;if(!l)return null;let g=()=>l.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(l.paneId)}):jsxRuntime.jsx(Ue,{currentNode:l,resizerSize:t,snapThreshold:h,renderResizer:n});return e===void 0?jsxRuntime.jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[g(),jsxRuntime.jsx(de,{activeId:s,hasOtherPanes:a,dropPreviewClassName:c.dropPreview})]}):g()};var K=react.createContext(null);var Xe={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},Ye={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},center:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},ce=({id:e,position:t,activeClassName:o})=>{let{setNodeRef:n,isOver:r}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:n,style:Xe[t]}),r&&jsxRuntime.jsx("div",{className:o,style:Ye[t]})]})},Ge=({id:e,children:t,style:o})=>{let{layout:n,activeId:r,classNames:i,fullscreenPaneId:s,onRemove:c,onFullscreenChange:N,removePane:v,updatePaneMetadata:h}=M(),a=r!==null&&r!==e,{attributes:l,listeners:g,setNodeRef:w,isDragging:P}=core.useDraggable({id:e}),m=r===e||P,x=s===e,f=react.useMemo(()=>D(n,e),[n,e])?.metadata,Z={isDragging:m,isFullscreen:x,toggleFullscreen:()=>N?.(x?null:e),remove:()=>{x&&N?.(null),c?c(e):v(e);},metadata:f,updateMetadata:S=>{h(e,S);}},_=react.useMemo(()=>({...g,...l}),[g,l]);return jsxRuntime.jsx(K.Provider,{value:_,children:jsxRuntime.jsxs("div",{ref:w,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...o},children:[t(Z),a&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsxRuntime.jsx(ce,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsxRuntime.jsx(ce,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Ke=({children:e,className:t,style:o})=>{let n=react.useContext(K);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...o},...n,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=be;exports.DEFAULT_RESIZER_SIZE=at;exports.DEFAULT_SNAP_THRESHOLD=Pe;exports.DashboardProvider=Te;exports.DragHandle=Ke;exports.Pane=Ge;exports.PaneTree=oe;exports.addPane=se;exports.
|
|
6
|
+
`,document.head.appendChild(F),v&&v(),a&&a(c);let f=x.getBoundingClientRect(),Z=m.clientX,_=m.clientY,S=n,k=m.currentTarget;k.setAttribute("data-resizing","true");let Y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(b=>b!==k&&b.getAttribute("data-direction")===o).map(b=>{let y=b.getBoundingClientRect();return t?y.left+y.width/2:y.top+y.height/2}),O=S,U=b=>{let y=t?(b.clientX-Z)/f.width*100:(b.clientY-_)/f.height*100,p=S+y,u=t?f.left+(f.width-r)*(p/100)+r/2:f.top+(f.height-r)*(p/100)+r/2,R=1/0,d=null;for(let B of Y){let C=Math.abs(u-B);C<i&&C<R&&(R=C,d=B);}let E=p;d!==null&&(E=t?(d-r/2-f.left)/(f.width-r)*100:(d-r/2-f.top)/(f.height-r)*100);let T=Math.max(w,Math.min(P,E));O=T;let A=H(s,c,T);N(A),l&&l(c,T);},V=()=>{document.body.classList.remove("zeugma-resizing"),k.removeAttribute("data-resizing");let b=document.getElementById("zeugma-global-cursor-style");b&&b.remove(),document.removeEventListener("pointermove",U),document.removeEventListener("pointerup",V),h&&h(),g&&g(c,O);};document.addEventListener("pointermove",U),document.addEventListener("pointerup",V);},[e,t,o,n,r,i,s,c,N,v,h,a,l,g,w,P])}var Ue=({currentNode:e,resizerSize:t,snapThreshold:o,renderResizer:n})=>{let{layout:r,onLayoutChange:i,classNames:s,renderResizer:c}=M(),[N,v]=react.useState(false),h=n||c,a=react.useRef(null),{direction:l,first:g,second:w,splitPercentage:P}=e,m=l==="row",x=ne({containerRef:a,isRow:m,direction:l,splitPercentage:P,resizerSize:t,snapThreshold:o??8,layout:r,currentNode:e,onLayoutChange:i,onResizeStart:()=>v(true),onResizeEnd:()=>v(false)});return jsxRuntime.jsxs("div",{ref:a,style:{display:"flex",flexDirection:m?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${P} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(oe,{tree:g,resizerSize:t,snapThreshold:o,renderResizer:n})}),h?h({direction:l,splitPercentage:P,resizerSize:t,isResizing:N,onPointerDown:x}):jsxRuntime.jsx("div",{className:s.resizer,"data-direction":l,style:{width:m?`${t}px`:"100%",height:m?"100%":`${t}px`,cursor:m?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:x,role:"separator","aria-valuenow":P,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-P} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(oe,{tree:w,resizerSize:t,snapThreshold:o,renderResizer:n})})]})},oe=({tree:e,resizerSize:t=4,snapThreshold:o,renderResizer:n})=>{let{layout:r,renderPane:i,activeId:s,classNames:c,fullscreenPaneId:N,snapThreshold:v}=M(),h=o!==void 0?o:v,a=react.useMemo(()=>s?z(r,s)!==null:false,[r,s]);if(N&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(N)});let l=e!==void 0?e:r;if(!l)return null;let g=()=>l.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(l.paneId)}):jsxRuntime.jsx(Ue,{currentNode:l,resizerSize:t,snapThreshold:h,renderResizer:n});return e===void 0?jsxRuntime.jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[g(),jsxRuntime.jsx(de,{activeId:s,hasOtherPanes:a,dropPreviewClassName:c.dropPreview})]}):g()};var K=react.createContext(null);var Xe={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},Ye={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},center:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},ce=({id:e,position:t,activeClassName:o})=>{let{setNodeRef:n,isOver:r}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:n,style:Xe[t]}),r&&jsxRuntime.jsx("div",{className:o,style:Ye[t]})]})},Ge=({id:e,children:t,style:o})=>{let{layout:n,activeId:r,classNames:i,fullscreenPaneId:s,onRemove:c,onFullscreenChange:N,removePane:v,updatePaneMetadata:h}=M(),a=r!==null&&r!==e,{attributes:l,listeners:g,setNodeRef:w,isDragging:P}=core.useDraggable({id:e}),m=r===e||P,x=s===e,f=react.useMemo(()=>D(n,e),[n,e])?.metadata,Z={isDragging:m,isFullscreen:x,toggleFullscreen:()=>N?.(x?null:e),remove:()=>{x&&N?.(null),c?c(e):v(e);},metadata:f,updateMetadata:S=>{h(e,S);}},_=react.useMemo(()=>({...g,...l}),[g,l]);return jsxRuntime.jsx(K.Provider,{value:_,children:jsxRuntime.jsxs("div",{ref:w,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...o},children:[t(Z),a&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsxRuntime.jsx(ce,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsxRuntime.jsx(ce,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Ke=({children:e,className:t,style:o})=>{let n=react.useContext(K);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...o},...n,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=be;exports.DEFAULT_RESIZER_SIZE=at;exports.DEFAULT_SNAP_THRESHOLD=Pe;exports.DashboardProvider=Te;exports.DragHandle=Ke;exports.Pane=Ge;exports.PaneTree=oe;exports.addPane=se;exports.findPane=D;exports.removePane=z;exports.splitPane=W;exports.splitRoot=ae;exports.swapPanes=ee;exports.updatePaneMetadata=q;exports.updateSplitPercentage=H;exports.useDashboard=M;exports.useResizer=ne;//# sourceMappingURL=index.cjs.map
|
|
7
7
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPaneNode","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleRemovePane","useCallback","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPaneNode(tree, idA)\n const nodeB = findPaneNode(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPaneNode(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPaneNode(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPaneNode(tree.first, paneId) ?? findPaneNode(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPaneNode,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n layout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPaneNode(layout, draggingId) ?? { type: 'pane', paneId: draggingId }\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layout, paneIdA, paneIdB)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPaneNode(layout, paneToAdd) ?? { type: 'pane', paneId: paneToAdd }\n const treeWithoutDragging = removePane(layout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layout, currentNode, percentage)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layout, paneId, updater)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPaneNode } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPaneNode(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleRemovePane","useCallback","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n layout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(layout, draggingId) ?? { type: 'pane', paneId: draggingId }\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layout, paneIdA, paneIdB)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(layout, paneToAdd) ?? { type: 'pane', paneId: paneToAdd }\n const treeWithoutDragging = removePane(layout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layout, currentNode, percentage)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layout, paneId, updater)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -162,10 +162,10 @@ declare function splitRoot(tree: TreeNode | null, draggingId: string, splitType:
|
|
|
162
162
|
/**
|
|
163
163
|
* Find a PaneNode by its paneId.
|
|
164
164
|
*/
|
|
165
|
-
declare function
|
|
165
|
+
declare function findPane(tree: TreeNode | null, paneId: string): PaneNode | null;
|
|
166
166
|
/**
|
|
167
167
|
* Update metadata on a specific pane node using an updater function.
|
|
168
168
|
*/
|
|
169
169
|
declare function updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null;
|
|
170
170
|
|
|
171
|
-
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane,
|
|
171
|
+
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboard, useResizer };
|
package/dist/index.d.ts
CHANGED
|
@@ -162,10 +162,10 @@ declare function splitRoot(tree: TreeNode | null, draggingId: string, splitType:
|
|
|
162
162
|
/**
|
|
163
163
|
* Find a PaneNode by its paneId.
|
|
164
164
|
*/
|
|
165
|
-
declare function
|
|
165
|
+
declare function findPane(tree: TreeNode | null, paneId: string): PaneNode | null;
|
|
166
166
|
/**
|
|
167
167
|
* Update metadata on a specific pane node using an updater function.
|
|
168
168
|
*/
|
|
169
169
|
declare function updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null;
|
|
170
170
|
|
|
171
|
-
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane,
|
|
171
|
+
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboard, useResizer };
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,5 @@ import {createContext,useContext,useState,useCallback,useMemo,useRef,useEffect}f
|
|
|
3
3
|
cursor: ${t?"col-resize":"row-resize"} !important;
|
|
4
4
|
user-select: none !important;
|
|
5
5
|
}
|
|
6
|
-
`,document.head.appendChild(F),v&&v(),a&&a(c);let f=x.getBoundingClientRect(),Z=m.clientX,_=m.clientY,S=n,k=m.currentTarget;k.setAttribute("data-resizing","true");let Y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(b=>b!==k&&b.getAttribute("data-direction")===o).map(b=>{let y=b.getBoundingClientRect();return t?y.left+y.width/2:y.top+y.height/2}),O=S,U=b=>{let y=t?(b.clientX-Z)/f.width*100:(b.clientY-_)/f.height*100,p=S+y,u=t?f.left+(f.width-r)*(p/100)+r/2:f.top+(f.height-r)*(p/100)+r/2,R=1/0,d=null;for(let B of Y){let C=Math.abs(u-B);C<i&&C<R&&(R=C,d=B);}let E=p;d!==null&&(E=t?(d-r/2-f.left)/(f.width-r)*100:(d-r/2-f.top)/(f.height-r)*100);let T=Math.max(w,Math.min(P,E));O=T;let A=H(s,c,T);N(A),l&&l(c,T);},V=()=>{document.body.classList.remove("zeugma-resizing"),k.removeAttribute("data-resizing");let b=document.getElementById("zeugma-global-cursor-style");b&&b.remove(),document.removeEventListener("pointermove",U),document.removeEventListener("pointerup",V),h&&h(),g&&g(c,O);};document.addEventListener("pointermove",U),document.addEventListener("pointerup",V);},[e,t,o,n,r,i,s,c,N,v,h,a,l,g,w,P])}var Ue=({currentNode:e,resizerSize:t,snapThreshold:o,renderResizer:n})=>{let{layout:r,onLayoutChange:i,classNames:s,renderResizer:c}=M(),[N,v]=useState(false),h=n||c,a=useRef(null),{direction:l,first:g,second:w,splitPercentage:P}=e,m=l==="row",x=ne({containerRef:a,isRow:m,direction:l,splitPercentage:P,resizerSize:t,snapThreshold:o??8,layout:r,currentNode:e,onLayoutChange:i,onResizeStart:()=>v(true),onResizeEnd:()=>v(false)});return jsxs("div",{ref:a,style:{display:"flex",flexDirection:m?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${P} 1 0%`,overflow:"hidden"},children:jsx(oe,{tree:g,resizerSize:t,snapThreshold:o,renderResizer:n})}),h?h({direction:l,splitPercentage:P,resizerSize:t,isResizing:N,onPointerDown:x}):jsx("div",{className:s.resizer,"data-direction":l,style:{width:m?`${t}px`:"100%",height:m?"100%":`${t}px`,cursor:m?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:x,role:"separator","aria-valuenow":P,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-P} 1 0%`,overflow:"hidden"},children:jsx(oe,{tree:w,resizerSize:t,snapThreshold:o,renderResizer:n})})]})},oe=({tree:e,resizerSize:t=4,snapThreshold:o,renderResizer:n})=>{let{layout:r,renderPane:i,activeId:s,classNames:c,fullscreenPaneId:N,snapThreshold:v}=M(),h=o!==void 0?o:v,a=useMemo(()=>s?z(r,s)!==null:false,[r,s]);if(N&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(N)});let l=e!==void 0?e:r;if(!l)return null;let g=()=>l.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(l.paneId)}):jsx(Ue,{currentNode:l,resizerSize:t,snapThreshold:h,renderResizer:n});return e===void 0?jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[g(),jsx(de,{activeId:s,hasOtherPanes:a,dropPreviewClassName:c.dropPreview})]}):g()};var K=createContext(null);var Xe={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},Ye={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},center:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},ce=({id:e,position:t,activeClassName:o})=>{let{setNodeRef:n,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:n,style:Xe[t]}),r&&jsx("div",{className:o,style:Ye[t]})]})},Ge=({id:e,children:t,style:o})=>{let{layout:n,activeId:r,classNames:i,fullscreenPaneId:s,onRemove:c,onFullscreenChange:N,removePane:v,updatePaneMetadata:h}=M(),a=r!==null&&r!==e,{attributes:l,listeners:g,setNodeRef:w,isDragging:P}=useDraggable({id:e}),m=r===e||P,x=s===e,f=useMemo(()=>D(n,e),[n,e])?.metadata,Z={isDragging:m,isFullscreen:x,toggleFullscreen:()=>N?.(x?null:e),remove:()=>{x&&N?.(null),c?c(e):v(e);},metadata:f,updateMetadata:S=>{h(e,S);}},_=useMemo(()=>({...g,...l}),[g,l]);return jsx(K.Provider,{value:_,children:jsxs("div",{ref:w,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...o},children:[t(Z),a&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsx(ce,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsx(ce,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Ke=({children:e,className:t,style:o})=>{let n=useContext(K);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...o},...n,children:e})};export{be as DEFAULT_DRAG_ACTIVATION_DISTANCE,at as DEFAULT_RESIZER_SIZE,Pe as DEFAULT_SNAP_THRESHOLD,Te as DashboardProvider,Ke as DragHandle,Ge as Pane,oe as PaneTree,se as addPane,D as
|
|
6
|
+
`,document.head.appendChild(F),v&&v(),a&&a(c);let f=x.getBoundingClientRect(),Z=m.clientX,_=m.clientY,S=n,k=m.currentTarget;k.setAttribute("data-resizing","true");let Y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(b=>b!==k&&b.getAttribute("data-direction")===o).map(b=>{let y=b.getBoundingClientRect();return t?y.left+y.width/2:y.top+y.height/2}),O=S,U=b=>{let y=t?(b.clientX-Z)/f.width*100:(b.clientY-_)/f.height*100,p=S+y,u=t?f.left+(f.width-r)*(p/100)+r/2:f.top+(f.height-r)*(p/100)+r/2,R=1/0,d=null;for(let B of Y){let C=Math.abs(u-B);C<i&&C<R&&(R=C,d=B);}let E=p;d!==null&&(E=t?(d-r/2-f.left)/(f.width-r)*100:(d-r/2-f.top)/(f.height-r)*100);let T=Math.max(w,Math.min(P,E));O=T;let A=H(s,c,T);N(A),l&&l(c,T);},V=()=>{document.body.classList.remove("zeugma-resizing"),k.removeAttribute("data-resizing");let b=document.getElementById("zeugma-global-cursor-style");b&&b.remove(),document.removeEventListener("pointermove",U),document.removeEventListener("pointerup",V),h&&h(),g&&g(c,O);};document.addEventListener("pointermove",U),document.addEventListener("pointerup",V);},[e,t,o,n,r,i,s,c,N,v,h,a,l,g,w,P])}var Ue=({currentNode:e,resizerSize:t,snapThreshold:o,renderResizer:n})=>{let{layout:r,onLayoutChange:i,classNames:s,renderResizer:c}=M(),[N,v]=useState(false),h=n||c,a=useRef(null),{direction:l,first:g,second:w,splitPercentage:P}=e,m=l==="row",x=ne({containerRef:a,isRow:m,direction:l,splitPercentage:P,resizerSize:t,snapThreshold:o??8,layout:r,currentNode:e,onLayoutChange:i,onResizeStart:()=>v(true),onResizeEnd:()=>v(false)});return jsxs("div",{ref:a,style:{display:"flex",flexDirection:m?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${P} 1 0%`,overflow:"hidden"},children:jsx(oe,{tree:g,resizerSize:t,snapThreshold:o,renderResizer:n})}),h?h({direction:l,splitPercentage:P,resizerSize:t,isResizing:N,onPointerDown:x}):jsx("div",{className:s.resizer,"data-direction":l,style:{width:m?`${t}px`:"100%",height:m?"100%":`${t}px`,cursor:m?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:x,role:"separator","aria-valuenow":P,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-P} 1 0%`,overflow:"hidden"},children:jsx(oe,{tree:w,resizerSize:t,snapThreshold:o,renderResizer:n})})]})},oe=({tree:e,resizerSize:t=4,snapThreshold:o,renderResizer:n})=>{let{layout:r,renderPane:i,activeId:s,classNames:c,fullscreenPaneId:N,snapThreshold:v}=M(),h=o!==void 0?o:v,a=useMemo(()=>s?z(r,s)!==null:false,[r,s]);if(N&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(N)});let l=e!==void 0?e:r;if(!l)return null;let g=()=>l.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(l.paneId)}):jsx(Ue,{currentNode:l,resizerSize:t,snapThreshold:h,renderResizer:n});return e===void 0?jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[g(),jsx(de,{activeId:s,hasOtherPanes:a,dropPreviewClassName:c.dropPreview})]}):g()};var K=createContext(null);var Xe={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},Ye={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},center:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},ce=({id:e,position:t,activeClassName:o})=>{let{setNodeRef:n,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:n,style:Xe[t]}),r&&jsx("div",{className:o,style:Ye[t]})]})},Ge=({id:e,children:t,style:o})=>{let{layout:n,activeId:r,classNames:i,fullscreenPaneId:s,onRemove:c,onFullscreenChange:N,removePane:v,updatePaneMetadata:h}=M(),a=r!==null&&r!==e,{attributes:l,listeners:g,setNodeRef:w,isDragging:P}=useDraggable({id:e}),m=r===e||P,x=s===e,f=useMemo(()=>D(n,e),[n,e])?.metadata,Z={isDragging:m,isFullscreen:x,toggleFullscreen:()=>N?.(x?null:e),remove:()=>{x&&N?.(null),c?c(e):v(e);},metadata:f,updateMetadata:S=>{h(e,S);}},_=useMemo(()=>({...g,...l}),[g,l]);return jsx(K.Provider,{value:_,children:jsxs("div",{ref:w,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...o},children:[t(Z),a&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsx(ce,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsx(ce,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Ke=({children:e,className:t,style:o})=>{let n=useContext(K);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...o},...n,children:e})};export{be as DEFAULT_DRAG_ACTIVATION_DISTANCE,at as DEFAULT_RESIZER_SIZE,Pe as DEFAULT_SNAP_THRESHOLD,Te as DashboardProvider,Ke as DragHandle,Ge as Pane,oe as PaneTree,se as addPane,D as findPane,z as removePane,W as splitPane,ae as splitRoot,ee as swapPanes,q as updatePaneMetadata,H as updateSplitPercentage,M as useDashboard,ne as useResizer};//# sourceMappingURL=index.js.map
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPaneNode","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleRemovePane","useCallback","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"+PAmDO,IAAMA,EAAmBC,aAAAA,CAAiD,MAAS,EChDnF,IAAMC,EAAe,IAAM,CAChC,IAAMC,CAAAA,CAAUC,UAAAA,CAAWJ,CAAgB,CAAA,CAC3C,GAAI,CAACG,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,sDAAsD,EAExE,OAAOA,CACT,ECJO,SAASE,CAAAA,CAAWC,EAAuBC,CAAAA,CAAqC,CACrF,GAAID,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,EAAK,IAAA,GAAS,MAAA,CAChB,OAAOA,CAAAA,CAAK,MAAA,GAAWC,EAAa,IAAA,CAAOD,CAAAA,CAE7C,IAAME,CAAAA,CAAWH,CAAAA,CAAWC,EAAK,KAAA,CAAOC,CAAU,EAC5CE,CAAAA,CAAYJ,CAAAA,CAAWC,EAAK,MAAA,CAAQC,CAAU,EACpD,OAAIC,CAAAA,GAAa,KAAaC,CAAAA,CAC1BA,CAAAA,GAAc,KAAaD,CAAAA,CACxB,CAAE,GAAGF,CAAAA,CAAM,KAAA,CAAOE,EAAU,MAAA,CAAQC,CAAU,CACvD,CAKO,SAASC,EACdJ,CAAAA,CACAK,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAIR,CAAAA,GAAS,KACX,OAAO,OAAOQ,GAAc,QAAA,CAAW,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQA,CAAU,CAAA,CAAIA,CAAAA,CAE/E,GAAIR,CAAAA,CAAK,IAAA,GAAS,OAAQ,CACxB,GAAIA,EAAK,MAAA,GAAWK,CAAAA,CAAU,CAC5B,IAAMI,CAAAA,CACJ,OAAOD,CAAAA,EAAc,QAAA,CAAW,CAAE,IAAA,CAAM,MAAA,CAAQ,OAAQA,CAAU,CAAA,CAAIA,EAClEE,CAAAA,CAAUH,CAAAA,GAAc,QAAUA,CAAAA,GAAc,KAAA,CACtD,OAAO,CACL,IAAA,CAAM,QACN,SAAA,CAAAD,CAAAA,CACA,MAAOI,CAAAA,CAAUD,CAAAA,CAAYT,EAC7B,MAAA,CAAQU,CAAAA,CAAUV,EAAOS,CAAAA,CACzB,eAAA,CAAiB,EACnB,CACF,CACA,OAAOT,CACT,CACA,OAAO,CACL,GAAGA,EACH,KAAA,CAAOI,CAAAA,CAAUJ,EAAK,KAAA,CAAOK,CAAAA,CAAUC,EAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKR,CAAAA,CAAK,KAAA,CAChF,MAAA,CAAQI,EAAUJ,CAAAA,CAAK,MAAA,CAAQK,EAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKR,CAAAA,CAAK,MACpF,CACF,CAKO,SAASW,EAAAA,CAAUX,CAAAA,CAAuBY,EAAaC,CAAAA,CAA8B,CAC1F,GAAIb,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAG1B,IAAMc,EAAQC,CAAAA,CAAaf,CAAAA,CAAMY,CAAG,CAAA,CAC9BI,CAAAA,CAAQD,EAAaf,CAAAA,CAAMa,CAAG,EACpC,GAAI,CAACC,GAAS,CAACE,CAAAA,CAAO,OAAOhB,CAAAA,CAG7B,SAASiB,EAAKC,CAAAA,CAA0B,CACtC,OAAIA,CAAAA,CAAK,IAAA,GAAS,OACZA,CAAAA,CAAK,MAAA,GAAWN,EAAY,CAAE,GAAGI,CAAO,CAAA,CACxCE,CAAAA,CAAK,SAAWL,CAAAA,CAAY,CAAE,GAAGC,CAAO,CAAA,CACrCI,EAEF,CACL,GAAGA,EACH,KAAA,CAAOD,CAAAA,CAAKC,EAAK,KAAK,CAAA,CACtB,OAAQD,CAAAA,CAAKC,CAAAA,CAAK,MAAM,CAC1B,CACF,CAEA,OAAOD,CAAAA,CAAKjB,CAAI,CAClB,CAKO,SAASmB,EAAAA,CAAQnB,CAAAA,CAAuBQ,EAA6B,CAC1E,GAAIR,IAAS,IAAA,CACX,OAAO,CAAE,IAAA,CAAM,MAAA,CAAQ,OAAQQ,CAAU,CAAA,CAG3C,SAASY,CAAAA,CAAOF,CAAAA,CAAgBG,EAAkD,CAChF,OAAIH,EAAK,IAAA,GAAS,MAAA,CAET,CACL,IAAA,CAAM,OAAA,CACN,UAHgCG,CAAAA,GAAoB,KAAA,CAAQ,SAAW,KAAA,CAIvE,eAAA,CAAiB,GACjB,KAAA,CAAOH,CAAAA,CACP,OAAQ,CAAE,IAAA,CAAM,OAAQ,MAAA,CAAQV,CAAU,CAC5C,CAAA,CAGK,CACL,GAAGU,CAAAA,CACH,MAAA,CAAQE,EAAOF,CAAAA,CAAK,MAAA,CAAQA,EAAK,SAAS,CAC5C,CACF,CAEA,OAAOE,EAAOpB,CAAAA,CAAM,IAAI,CAC1B,CAKO,SAASsB,EACdtB,CAAAA,CACAuB,CAAAA,CACAC,EACiB,CACjB,OAAIxB,IAAS,IAAA,CAAa,IAAA,CACtBA,IAASuB,CAAAA,CACJ,CAAE,GAAGvB,CAAAA,CAAM,eAAA,CAAiBwB,CAAc,CAAA,CAE/CxB,CAAAA,CAAK,OAAS,OAAA,CACT,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOsB,EAAsBtB,CAAAA,CAAK,KAAA,CAAOuB,EAAQC,CAAa,CAAA,EAAKxB,EAAK,KAAA,CACxE,MAAA,CAAQsB,EAAsBtB,CAAAA,CAAK,MAAA,CAAQuB,EAAQC,CAAa,CAAA,EAAKxB,EAAK,MAC5E,CAAA,CAEKA,CACT,CAKO,SAASyB,EAAAA,CACdzB,EACA0B,CAAAA,CACAnB,CAAAA,CACiB,CAEjB,IAAMoB,CAAAA,CAA4BZ,EAAaf,CAAAA,CAAM0B,CAAU,GAAK,CAClE,IAAA,CAAM,OACN,MAAA,CAAQA,CACV,EACME,CAAAA,CAAsB7B,CAAAA,CAAWC,EAAM0B,CAAU,CAAA,CACvD,GAAIE,CAAAA,GAAwB,IAAA,CAC1B,OAAO,CAAE,GAAGD,CAAgB,CAAA,CAG9B,IAAMrB,EAA4BC,CAAAA,GAAc,MAAA,EAAUA,IAAc,OAAA,CAAU,KAAA,CAAQ,SACpFG,CAAAA,CAAUH,CAAAA,GAAc,QAAUA,CAAAA,GAAc,KAAA,CAChDsB,EAAwB,CAAE,GAAGF,CAAgB,CAAA,CAEnD,OAAO,CACL,IAAA,CAAM,OAAA,CACN,UAAArB,CAAAA,CACA,KAAA,CAAOI,EAAUmB,CAAAA,CAAcD,CAAAA,CAC/B,OAAQlB,CAAAA,CAAUkB,CAAAA,CAAsBC,EACxC,eAAA,CAAiB,EACnB,CACF,CAKO,SAASd,EAAaf,CAAAA,CAAuB8B,CAAAA,CAAiC,CACnF,OAAI9B,CAAAA,GAAS,KAAa,IAAA,CACtBA,CAAAA,CAAK,OAAS,MAAA,CACTA,CAAAA,CAAK,SAAW8B,CAAAA,CAAS9B,CAAAA,CAAO,KAElCe,CAAAA,CAAaf,CAAAA,CAAK,MAAO8B,CAAM,CAAA,EAAKf,EAAaf,CAAAA,CAAK,MAAA,CAAQ8B,CAAM,CAC7E,CAKO,SAASC,CAAAA,CACd/B,CAAAA,CACA8B,EACAE,CAAAA,CACiB,CACjB,GAAIhC,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,EAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,SAAW8B,CAAAA,CAAQ,CAC1B,IAAMG,CAAAA,CAAcD,CAAAA,CAAQhC,EAAK,QAAQ,CAAA,CACzC,GAAIiC,CAAAA,GAAgB,MAAA,CAAW,CAE7B,GAAM,CAAE,SAAUC,CAAAA,CAAG,GAAGC,CAAK,CAAA,CAAInC,CAAAA,CACjC,OAAOmC,CACT,CACA,OAAO,CAAE,GAAGnC,EAAM,QAAA,CAAUiC,CAAY,CAC1C,CACA,OAAOjC,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,MAAO+B,CAAAA,CAAmB/B,CAAAA,CAAK,MAAO8B,CAAAA,CAAQE,CAAO,GAAKhC,CAAAA,CAAK,KAAA,CAC/D,OAAQ+B,CAAAA,CAAmB/B,CAAAA,CAAK,OAAQ8B,CAAAA,CAAQE,CAAO,GAAKhC,CAAAA,CAAK,MACnE,CACF,CCvMO,IAAMoC,GAAyB,CAAA,CACzBC,EAAAA,CAAmC,EACnCC,EAAAA,CAAuB,ECuBpC,IAAMC,GAID,CAAC,CAAE,SAAAC,CAAAA,CAAU,MAAA,CAAAC,CAAAA,CAAQ,SAAA,CAAAC,CAAU,CAAA,GAAM,CACxC,IAAMC,CAAAA,CAAMC,OAAuB,IAAI,CAAA,CAEvC,OAAAC,SAAAA,CAAU,IAAM,CACd,IAAMC,CAAAA,CAAcC,GAAoB,CAClCJ,CAAAA,CAAI,UACNA,CAAAA,CAAI,OAAA,CAAQ,MAAM,SAAA,CAAY,CAAA,UAAA,EAAaI,EAAE,OAAA,CAAU,EAAE,OAAOA,CAAAA,CAAE,OAAA,CAAU,EAAE,CAAA,GAAA,CAAA,EAElF,CAAA,CACA,gBAAS,gBAAA,CAAiB,aAAA,CAAeD,CAAU,CAAA,CAC5C,IAAM,SAAS,mBAAA,CAAoB,aAAA,CAAeA,CAAU,CACrE,CAAA,CAAG,EAAE,CAAA,CAGHE,IAAC,KAAA,CAAA,CACC,GAAA,CAAKL,EACL,SAAA,CAAWD,CAAAA,CACX,MAAO,CACL,QAAA,CAAU,QACV,GAAA,CAAK,CAAA,CACL,KAAM,CAAA,CACN,MAAA,CAAQ,KACR,aAAA,CAAe,MACjB,EAEC,QAAA,CAAAD,CAAAA,CAAOD,CAAQ,CAAA,CAClB,CAEJ,EAgCaS,EAAAA,CAAsD,CAAC,CAClE,MAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,UAAA,CAAAC,EACA,iBAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CAAa,GACb,gBAAA,CAAAC,CAAAA,CAAmB,KACnB,kBAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,sBAAA,CAAAC,CAAAA,CAAyB,CAAA,CACzB,aAAA,CAAAC,CAAAA,CAAgB,EAChB,WAAA,CAAAC,CAAAA,CACA,UAAAC,CAAAA,CACA,aAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,YAAAC,CAAAA,CACA,aAAA,CAAAC,EACA,kBAAA,CAAAC,CAAAA,CAAqB,EACrB,kBAAA,CAAAC,CAAAA,CAAqB,GACrB,QAAA,CAAAC,CACF,IAAM,CACJ,GAAM,CAAC5B,CAAAA,CAAU6B,CAAW,EAAIC,QAAAA,CAAwB,IAAI,EAEtDC,CAAAA,CAAUC,UAAAA,CACdC,UAAUC,aAAAA,CAAe,CACvB,qBAAsB,CAAE,QAAA,CAAUhB,CAAuB,CAC3D,CAAC,CACH,CAAA,CAEMiB,CAAAA,CAAmBC,GAA0B,CACjD,IAAMlD,EAAakD,CAAAA,CAAM,MAAA,CAAO,GAAG,QAAA,EAAS,CAC5CP,EAAY3C,CAAU,CAAA,CAClBkC,GACFA,CAAAA,CAAYlC,CAAU,EAE1B,CAAA,CAEMmD,CAAAA,CAAiBD,GAAwB,CAC7CP,CAAAA,CAAY,IAAI,CAAA,CAChB,GAAM,CAAE,MAAA,CAAAS,CAAAA,CAAQ,KAAAC,CAAK,CAAA,CAAIH,EACnBlD,CAAAA,CAAaoD,CAAAA,CAAO,GAAG,QAAA,EAAS,CAEtC,GAAI,CAACC,CAAAA,CAAM,CACLlB,CAAAA,EACFA,CAAAA,CAAUnC,EAAY,IAAA,CAAM,IAAI,EAElC,MACF,CAEA,IAAMsD,CAAAA,CAAYD,CAAAA,CAAK,EAAA,CAAG,UAAS,CAG7BE,CAAAA,CAAYD,EAAU,KAAA,CAAM,qCAAqC,EACvE,GAAIC,CAAAA,CAAW,CACb,GAAM,EAAGC,CAAQ,CAAA,CAAID,EACfE,EAAAA,CAAY1D,EAAAA,CAChByB,EACAxB,CAAAA,CACAwD,CACF,EACA/B,CAAAA,CAASgC,EAAS,EAEdtB,CAAAA,EAGFA,CAAAA,CAAUnC,EAAY,MAAA,CAAQ,CAC5B,KAAM,OAAA,CACN,SAAA,CAHAwD,IAAa,MAAA,EAAUA,CAAAA,GAAa,QAAU,KAAA,CAAQ,QAAA,CAItD,SAAUA,CACZ,CAAC,EAEH,MACF,CAGA,IAAME,CAAAA,CAAYJ,CAAAA,CAAU,MAAM,oBAAoB,CAAA,CACtD,GAAII,CAAAA,CAAW,CACb,GAAM,EAAG/E,CAAQ,CAAA,CAAI+E,CAAAA,CACjB1D,IAAerB,CAAAA,EACjB8C,CAAAA,CAASxC,GAAUuC,CAAAA,CAAQxB,CAAAA,CAAYrB,CAAQ,CAAC,CAAA,CAE9CwD,GACFA,CAAAA,CAAUnC,CAAAA,CAAYrB,EAAU,CAAE,IAAA,CAAM,OAAQ,QAAA,CAAU,QAAS,CAAC,CAAA,CAEtE,MACF,CAGA,IAAMgF,CAAAA,CAAQL,EAAU,KAAA,CAAM,qCAAqC,EACnE,GAAI,CAACK,EAAO,CACNxB,CAAAA,EACFA,EAAUnC,CAAAA,CAAY,IAAA,CAAM,IAAI,CAAA,CAElC,MACF,CAEA,GAAM,EAAGwD,CAAAA,CAAU7E,CAAQ,EAAIgF,CAAAA,CAC/B,GAAI3D,IAAerB,CAAAA,CAAU,CACvBwD,GACFA,CAAAA,CAAUnC,CAAAA,CAAY,KAAM,IAAI,CAAA,CAElC,MACF,CAEA,IAAMpB,GAA4B4E,CAAAA,GAAa,MAAA,EAAUA,IAAa,OAAA,CAAU,KAAA,CAAQ,SAClFvD,EAAAA,CAAkBZ,CAAAA,CAAamC,EAAQxB,CAAU,CAAA,EAAK,CAAE,IAAA,CAAM,MAAA,CAAQ,OAAQA,CAAW,CAAA,CACzFE,GAAsB7B,CAAAA,CAAWmD,CAAAA,CAAQxB,CAAU,CAAA,CAEnDyD,EAAAA,CAAY/E,EAChBwB,EAAAA,CACAvB,CAAAA,CACAC,GACA4E,CAAAA,CACAvD,EACF,EACAwB,CAAAA,CAASgC,EAAS,EACdtB,CAAAA,EACFA,CAAAA,CAAUnC,EAAYrB,CAAAA,CAAU,CAC9B,KAAM,OAAA,CACN,SAAA,CAAAC,GACA,QAAA,CAAU4E,CACZ,CAAC,EAEL,CAAA,CAEMI,EAAmBC,WAAAA,CACtBzD,CAAAA,EAAmB,CAClB,IAAMqD,CAAAA,CAAYpF,EAAWmD,CAAAA,CAAQpB,CAAM,EAC3CqB,CAAAA,CAASgC,CAAS,EACpB,CAAA,CACA,CAACjC,EAAQC,CAAQ,CACnB,EAEMqC,CAAAA,CAAgBD,WAAAA,CACnBzD,CAAAA,EAAmB,CAClB,IAAMqD,CAAAA,CAAYhE,GAAQ+B,CAAAA,CAAQpB,CAAM,EACxCqB,CAAAA,CAASgC,CAAS,EACpB,CAAA,CACA,CAACjC,EAAQC,CAAQ,CACnB,EAEMsC,CAAAA,CAAkBF,WAAAA,CACtB,CAACG,CAAAA,CAAiBC,CAAAA,GAAoB,CACpC,IAAMR,CAAAA,CAAYxE,GAAUuC,CAAAA,CAAQwC,CAAAA,CAASC,CAAO,CAAA,CACpDxC,CAAAA,CAASgC,CAAS,EACpB,CAAA,CACA,CAACjC,CAAAA,CAAQC,CAAQ,CACnB,CAAA,CAEMyC,CAAAA,CAAkBL,YACtB,CACElF,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,GACG,CACH,IAAMmB,CAAAA,CAAkBZ,EAAamC,CAAAA,CAAQ1C,CAAS,GAAK,CAAE,IAAA,CAAM,OAAQ,MAAA,CAAQA,CAAU,EACvFoB,CAAAA,CAAsB7B,CAAAA,CAAWmD,EAAQ1C,CAAS,CAAA,CAClD2E,EAAY/E,CAAAA,CAChBwB,CAAAA,CACAvB,EACAC,CAAAA,CACAC,CAAAA,CACAoB,CACF,CAAA,CACAwB,CAAAA,CAASgC,CAAS,EACpB,CAAA,CACA,CAACjC,CAAAA,CAAQC,CAAQ,CACnB,CAAA,CAEM0C,CAAAA,CAA8BN,YAClC,CAACO,CAAAA,CAAwBC,IAAuB,CAC9C,IAAMZ,EAAY7D,CAAAA,CAAsB4B,CAAAA,CAAQ4C,EAAaC,CAAU,CAAA,CACvE5C,EAASgC,CAAS,EACpB,CAAA,CACA,CAACjC,CAAAA,CAAQC,CAAQ,CACnB,CAAA,CAEM6C,CAAAA,CAA2BT,YAC/B,CACEzD,CAAAA,CACAE,IAGG,CACH,IAAMmD,EAAYpD,CAAAA,CAAmBmB,CAAAA,CAAQpB,EAAQE,CAAO,CAAA,CAC5DmB,EAASgC,CAAS,EACpB,EACA,CAACjC,CAAAA,CAAQC,CAAQ,CACnB,CAAA,CAGM8C,EAAeC,OAAAA,CACnB,KAAO,CACL,MAAA,CAAAhD,CAAAA,CACA,eAAgBC,CAAAA,CAChB,UAAA,CAAAC,EACA,QAAA,CAAAZ,CAAAA,CACA,iBAAAe,CAAAA,CACA,UAAA,CAAAD,EACA,QAAA,CAAAG,CAAAA,CACA,mBAAAD,CAAAA,CACA,aAAA,CAAAG,EACA,aAAA,CAAAG,CAAAA,CACA,SAAAC,CAAAA,CACA,WAAA,CAAAC,EACA,aAAA,CAAAC,CAAAA,CACA,mBAAAC,CAAAA,CACA,kBAAA,CAAAC,EACA,UAAA,CAAYmB,CAAAA,CACZ,QAASE,CAAAA,CACT,SAAA,CAAWC,EACX,SAAA,CAAWG,CAAAA,CACX,sBAAuBC,CAAAA,CACvB,kBAAA,CAAoBG,CACtB,CAAA,CAAA,CACA,CACE9C,EACAC,CAAAA,CACAC,CAAAA,CACAZ,EACAe,CAAAA,CACAD,CAAAA,CACAG,EACAD,CAAAA,CACAG,CAAAA,CACAG,EACAC,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,CACAmB,EACAE,CAAAA,CACAC,CAAAA,CACAG,EACAC,CAAAA,CACAG,CACF,CACF,CAAA,CAEA,OACEG,IAAAA,CAACzG,EAAiB,QAAA,CAAjB,CAA0B,MAAOuG,CAAAA,CAChC,QAAA,CAAA,CAAAjD,IAACoD,UAAAA,CAAA,CACC,GAAG,oBAAA,CACH,OAAA,CAAS7B,EACT,kBAAA,CAAoB8B,aAAAA,CACpB,YAAa1B,CAAAA,CACb,SAAA,CAAWE,EAEV,QAAA,CAAAT,CAAAA,CACH,EACC5B,CAAAA,EAAYa,CAAAA,EACXL,IAACT,EAAAA,CAAA,CACC,SAAUC,CAAAA,CACV,MAAA,CAAQa,EACR,SAAA,CAAWC,CAAAA,CAAW,YACxB,CAAA,CAAA,CAEJ,CAEJ,EC3VA,IAAMgD,EAAAA,CAA+D,CACnE,IAAK,CACH,QAAA,CAAU,WACV,GAAA,CAAK,CAAA,CACL,KAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,MAAA,CACR,OAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,OAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,CAAA,CACP,OAAQ,MAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MACjB,EACA,IAAA,CAAM,CACJ,SAAU,UAAA,CACV,GAAA,CAAK,EACL,MAAA,CAAQ,CAAA,CACR,KAAM,CAAA,CACN,KAAA,CAAO,OACP,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,MAAO,CACL,QAAA,CAAU,WACV,GAAA,CAAK,CAAA,CACL,OAAQ,CAAA,CACR,KAAA,CAAO,EACP,KAAA,CAAO,MAAA,CACP,OAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CACF,CAAA,CAEMC,GAA4D,CAChE,GAAA,CAAK,CACH,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,IAAA,CAAM,EACN,KAAA,CAAO,CAAA,CACP,OAAQ,KAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,UAAW,YACb,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,WACV,MAAA,CAAQ,CAAA,CACR,KAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,OAAQ,EAAA,CACR,aAAA,CAAe,OACf,SAAA,CAAW,YACb,EACA,IAAA,CAAM,CACJ,SAAU,UAAA,CACV,GAAA,CAAK,EACL,MAAA,CAAQ,CAAA,CACR,KAAM,CAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,MAAA,CAAQ,EACR,KAAA,CAAO,CAAA,CACP,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CACF,CAAA,CAQaC,GAA4C,CAAC,CAAE,GAAAC,CAAAA,CAAI,QAAA,CAAAC,EAAU,eAAA,CAAAC,CAAgB,IAAM,CAC9F,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,OAAAC,CAAO,CAAA,CAAIC,aAAa,CAAE,EAAA,CAAAL,CAAG,CAAC,CAAA,CAClD,OACEN,IAAAA,CAAAY,QAAAA,CAAA,CACE,QAAA,CAAA,CAAA/D,GAAAA,CAAC,OAAI,GAAA,CAAK4D,CAAAA,CAAY,MAAON,EAAAA,CAAwBI,CAAQ,EAAG,CAAA,CAC/DG,CAAAA,EAAU7D,IAAC,KAAA,CAAA,CAAI,SAAA,CAAW2D,EAAiB,KAAA,CAAOJ,EAAAA,CAAqBG,CAAQ,CAAA,CAAG,CAAA,CAAA,CACrF,CAEJ,CAAA,CAQaM,EAAAA,CAA8C,CAAC,CAC1D,QAAA,CAAAxE,EACA,aAAA,CAAAyE,CAAAA,CACA,qBAAAC,CACF,CAAA,GACM,CAAC1E,CAAAA,EAAY,CAACyE,EAAsB,IAAA,CAGtCjE,GAAAA,CAAC,OACC,KAAA,CAAO,CACL,SAAU,UAAA,CACV,GAAA,CAAK,EACL,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,EACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CAEE,UAAC,KAAA,CAAO,QAAA,CAAU,MAAA,CAAQ,OAAO,CAAA,CAAY,GAAA,CAAKmE,GAClDnE,GAAAA,CAACwD,EAAAA,CAAA,CAEC,EAAA,CAAI,CAAA,UAAA,EAAaW,CAAG,CAAA,CAAA,CACpB,QAAA,CAAUA,EACV,eAAA,CAAiBD,CAAAA,CAAAA,CAHZC,CAIP,CACD,CAAA,CACH,ECnHG,SAASC,GAAW,CACzB,YAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,UAAAhH,CAAAA,CACA,eAAA,CAAAiH,EACA,WAAA,CAAAC,CAAAA,CACA,cAAA7D,CAAAA,CACA,MAAA,CAAAT,EACA,WAAA,CAAA4C,CAAAA,CACA,eAAA2B,CAAAA,CACA,aAAA,CAAeC,EACf,WAAA,CAAaC,CACf,EAAoB,CAClB,GAAM,CACJ,aAAA,CAAeC,CAAAA,CACf,SAAUC,CAAAA,CACV,WAAA,CAAaC,EACb,kBAAA,CAAA5D,CAAAA,CAAqB,EACrB,kBAAA,CAAAC,CAAAA,CAAqB,EACvB,CAAA,CAAIvE,CAAAA,GAEJ,OAAO2F,WAAAA,CACJxC,GAA0C,CACzCA,CAAAA,CAAE,gBAAe,CACjB,IAAMgF,EAAYV,CAAAA,CAAa,OAAA,CAC/B,GAAI,CAACU,CAAAA,CAAW,OAEhB,QAAA,CAAS,IAAA,CAAK,UAAU,GAAA,CAAI,iBAAiB,EAG7C,IAAMC,CAAAA,CAAU,SAAS,aAAA,CAAc,OAAO,EAC9CA,CAAAA,CAAQ,EAAA,CAAK,4BAAA,CACbA,CAAAA,CAAQ,WAAA,CAAc;AAAA;AAAA,gBAAA,EAEVV,CAAAA,CAAQ,aAAe,YAAY,CAAA;AAAA;AAAA;AAAA,IAAA,CAAA,CAI/C,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYU,CAAO,EAE7BN,CAAAA,EACFA,CAAAA,EAAmB,CAEjBE,CAAAA,EACFA,CAAAA,CAAoB9B,CAAW,CAAA,CAGjC,IAAMmC,EAAOF,CAAAA,CAAU,qBAAA,EAAsB,CACvCG,CAAAA,CAASnF,CAAAA,CAAE,OAAA,CACXoF,CAAAA,CAASpF,CAAAA,CAAE,QACXqF,CAAAA,CAAkBb,CAAAA,CAGlBc,CAAAA,CAAYtF,CAAAA,CAAE,cACpBsF,CAAAA,CAAU,YAAA,CAAa,eAAA,CAAiB,MAAM,EAM9C,IAAMC,CAAAA,CAJgB,KAAA,CAAM,IAAA,CAC1B,QAAA,CAAS,gBAAA,CAAiB,uCAAuC,CACnE,EAAE,MAAA,CAAQC,CAAAA,EAAOA,CAAAA,GAAOF,CAAAA,EAAaE,EAAG,YAAA,CAAa,gBAAgB,CAAA,GAAMjI,CAAS,EAE/C,GAAA,CAAKiI,CAAAA,EAAO,CAC/C,IAAMC,CAAAA,CAAID,CAAAA,CAAG,qBAAA,EAAsB,CACnC,OAAOjB,CAAAA,CAAQkB,CAAAA,CAAE,IAAA,CAAOA,CAAAA,CAAE,MAAQ,CAAA,CAAIA,CAAAA,CAAE,GAAA,CAAMA,CAAAA,CAAE,OAAS,CAC3D,CAAC,CAAA,CAEGC,CAAAA,CAAoBL,CAAAA,CAElBM,CAAAA,CAAqBC,CAAAA,EAA4B,CACrD,IAAMC,CAAAA,CAAQtB,CAAAA,CAAAA,CACRqB,CAAAA,CAAU,OAAA,CAAUT,CAAAA,EAAUD,CAAAA,CAAK,KAAA,CAAS,GAAA,CAAA,CAC5CU,EAAU,OAAA,CAAUR,CAAAA,EAAUF,CAAAA,CAAK,MAAA,CAAU,GAAA,CAC7CY,CAAAA,CAAqBT,CAAAA,CAAkBQ,CAAAA,CAGvCE,EAAcxB,CAAAA,CAChBW,CAAAA,CAAK,IAAA,CAAA,CAAQA,CAAAA,CAAK,MAAQT,CAAAA,GAAgBqB,CAAAA,CAAqB,GAAA,CAAA,CAAOrB,CAAAA,CAAc,EACpFS,CAAAA,CAAK,GAAA,CAAA,CAAOA,CAAAA,CAAK,MAAA,CAAST,CAAAA,GAAgBqB,CAAAA,CAAqB,GAAA,CAAA,CAAOrB,CAAAA,CAAc,EAEpFuB,CAAAA,CAAkB,CAAA,CAAA,CAAA,CAClBC,CAAAA,CAA4B,IAAA,CAEhC,QAAW7B,CAAAA,IAAOmB,CAAAA,CAAgB,CAChC,IAAMW,EAAO,IAAA,CAAK,GAAA,CAAIH,CAAAA,CAAc3B,CAAG,CAAA,CACnC8B,CAAAA,CAAOtF,CAAAA,EAAiBsF,CAAAA,CAAOF,IACjCA,CAAAA,CAAkBE,CAAAA,CAClBD,CAAAA,CAAa7B,CAAAA,EAEjB,CAEA,IAAI+B,CAAAA,CAAoBL,CAAAA,CACpBG,CAAAA,GAAe,OACjBE,CAAAA,CAAoB5B,CAAAA,CAAAA,CACd0B,CAAAA,CAAaxB,CAAAA,CAAc,CAAA,CAAIS,CAAAA,CAAK,IAAA,GAASA,CAAAA,CAAK,MAAQT,CAAAA,CAAAA,CAAgB,GAAA,CAAA,CAC1EwB,CAAAA,CAAaxB,CAAAA,CAAc,CAAA,CAAIS,CAAAA,CAAK,GAAA,GAAQA,CAAAA,CAAK,OAAST,CAAAA,CAAAA,CAAgB,GAAA,CAAA,CAGlF,IAAM2B,CAAAA,CAAkB,IAAA,CAAK,GAAA,CAC3BjF,CAAAA,CACA,IAAA,CAAK,IAAIC,CAAAA,CAAoB+E,CAAiB,CAChD,CAAA,CACAT,EAAoBU,CAAAA,CACpB,IAAMhE,CAAAA,CAAY7D,CAAAA,CAAsB4B,EAAQ4C,CAAAA,CAAaqD,CAAe,CAAA,CAC5E1B,CAAAA,CAAetC,CAAS,CAAA,CACpB0C,CAAAA,EACFA,CAAAA,CAAe/B,EAAaqD,CAAe,EAE/C,CAAA,CAEMC,CAAAA,CAAkB,IAAM,CAC5B,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,OAAO,iBAAiB,CAAA,CAChDf,CAAAA,CAAU,eAAA,CAAgB,eAAe,CAAA,CAEzC,IAAMgB,CAAAA,CAAc,SAAS,cAAA,CAAe,4BAA4B,CAAA,CACpEA,CAAAA,EACFA,EAAY,MAAA,EAAO,CAGrB,QAAA,CAAS,mBAAA,CAAoB,cAAeX,CAAiB,CAAA,CAC7D,QAAA,CAAS,mBAAA,CAAoB,WAAA,CAAaU,CAAe,CAAA,CAErDzB,CAAAA,EACFA,GAAiB,CAEfG,CAAAA,EACFA,CAAAA,CAAkBhC,CAAAA,CAAa2C,CAAiB,EAEpD,CAAA,CAEA,QAAA,CAAS,iBAAiB,aAAA,CAAeC,CAAiB,CAAA,CAC1D,QAAA,CAAS,gBAAA,CAAiB,WAAA,CAAaU,CAAe,EACxD,EACA,CACE/B,CAAAA,CACAC,CAAAA,CACAhH,CAAAA,CACAiH,EACAC,CAAAA,CACA7D,CAAAA,CACAT,CAAAA,CACA4C,CAAAA,CACA2B,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA5D,CAAAA,CACAC,CACF,CACF,CACF,CClJA,IAAMmF,EAAAA,CAAsC,CAAC,CAC3C,WAAA,CAAAxD,CAAAA,CACA,WAAA,CAAA0B,CAAAA,CACA,cAAA7D,CAAAA,CACA,aAAA,CAAe4F,CACjB,CAAA,GAAM,CACJ,GAAM,CAAE,MAAA,CAAArG,CAAAA,CAAQ,cAAA,CAAAuE,CAAAA,CAAgB,UAAA,CAAAnE,CAAAA,CAAY,cAAekG,CAAqB,CAAA,CAAI5J,CAAAA,EAAa,CAC3F,CAAC6J,CAAAA,CAAYC,CAAa,CAAA,CAAIpF,SAAS,KAAK,CAAA,CAE5CL,CAAAA,CAAgBsF,CAAAA,EAAqBC,CAAAA,CAErCnC,CAAAA,CAAezE,MAAAA,CAAuB,IAAI,EAC1C,CAAE,SAAA,CAAAtC,CAAAA,CAAW,KAAA,CAAAqJ,EAAO,MAAA,CAAAC,CAAAA,CAAQ,eAAA,CAAArC,CAAgB,EAAIzB,CAAAA,CAChDwB,CAAAA,CAAQhH,CAAAA,GAAc,KAAA,CAEtBuJ,CAAAA,CAAoBzC,EAAAA,CAAW,CACnC,YAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,SAAA,CAAAhH,CAAAA,CACA,gBAAAiH,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,aAAA,CAAe7D,GAAiB,CAAA,CAChC,MAAA,CAAAT,CAAAA,CACA,WAAA,CAAA4C,CAAAA,CACA,cAAA,CAAA2B,CAAAA,CACA,aAAA,CAAe,IAAMiC,CAAAA,CAAc,IAAI,CAAA,CACvC,WAAA,CAAa,IAAMA,CAAAA,CAAc,KAAK,CACxC,CAAC,EAED,OACEvD,IAAAA,CAAC,KAAA,CAAA,CACC,GAAA,CAAKkB,CAAAA,CACL,KAAA,CAAO,CACL,OAAA,CAAS,OACT,aAAA,CAAeC,CAAAA,CAAQ,KAAA,CAAQ,QAAA,CAC/B,KAAA,CAAO,MAAA,CACP,MAAA,CAAQ,MAAA,CACR,SAAU,QACZ,CAAA,CAEA,QAAA,CAAA,CAAAtE,GAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,IAAA,CAAM,GAAGuE,CAAe,CAAA,KAAA,CAAA,CAAS,QAAA,CAAU,QAAS,EAChE,QAAA,CAAAvE,GAAAA,CAAC8G,EAAAA,CAAA,CACC,KAAMH,CAAAA,CACN,WAAA,CAAanC,CAAAA,CACb,aAAA,CAAe7D,CAAAA,CACf,aAAA,CAAe4F,CAAAA,CACjB,CAAA,CACF,EACCtF,CAAAA,CACCA,CAAAA,CAAc,CACZ,SAAA,CAAA3D,EACA,eAAA,CAAAiH,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,WAAAiC,CAAAA,CACA,aAAA,CAAeI,CACjB,CAAC,CAAA,CAED7G,GAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAWM,EAAW,OAAA,CACtB,gBAAA,CAAgBhD,CAAAA,CAChB,KAAA,CAAO,CACL,KAAA,CAAOgH,CAAAA,CAAQ,CAAA,EAAGE,CAAW,KAAO,MAAA,CACpC,MAAA,CAAQF,CAAAA,CAAQ,MAAA,CAAS,CAAA,EAAGE,CAAW,CAAA,EAAA,CAAA,CACvC,MAAA,CAAQF,EAAQ,YAAA,CAAe,YAAA,CAC/B,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,EAAA,CACR,UAAA,CAAY,MAAA,CACZ,UAAW,YAAA,CACX,UAAA,CAAY,CACd,CAAA,CACA,aAAA,CAAeuC,CAAAA,CACf,IAAA,CAAK,WAAA,CACL,gBAAetC,CAAAA,CACf,eAAA,CAAe,CAAA,CACf,eAAA,CAAe,GACjB,CAAA,CAEFvE,GAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAG,GAAA,CAAMuE,CAAe,CAAA,KAAA,CAAA,CAAS,QAAA,CAAU,QAAS,CAAA,CACtE,SAAAvE,GAAAA,CAAC8G,EAAAA,CAAA,CACC,IAAA,CAAMF,EACN,WAAA,CAAapC,CAAAA,CACb,aAAA,CAAe7D,CAAAA,CACf,cAAe4F,CAAAA,CACjB,CAAA,CACF,CAAA,CAAA,CACF,CAEJ,CAAA,CAEaO,EAAAA,CAAoC,CAAC,CAChD,KAAA9J,CAAAA,CACA,WAAA,CAAAwH,CAAAA,CAAc,CAAA,CACd,cAAeuC,CAAAA,CACf,aAAA,CAAA9F,CACF,CAAA,GAAM,CACJ,GAAM,CACJ,MAAA,CAAAf,CAAAA,CACA,UAAA,CAAAE,CAAAA,CACA,QAAA,CAAAZ,CAAAA,CACA,WAAAc,CAAAA,CACA,gBAAA,CAAAC,CAAAA,CACA,aAAA,CAAeyG,CACjB,CAAA,CAAIpK,CAAAA,EAAa,CAEX+D,EAAgBoG,CAAAA,GAAsB,MAAA,CAAYA,CAAAA,CAAoBC,CAAAA,CAEtE/C,CAAAA,CAAgBf,OAAAA,CAAQ,IACvB1D,CAAAA,CACEzC,EAAWmD,CAAAA,CAAQV,CAAQ,CAAA,GAAM,IAAA,CADlB,MAErB,CAACU,CAAAA,CAAQV,CAAQ,CAAC,EAGrB,GAAIe,CAAAA,EAAoB,CAACvD,CAAAA,CACvB,OACEgD,GAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,SAAU,UAAW,CAAA,CAC/D,QAAA,CAAAI,CAAAA,CAAWG,CAAgB,CAAA,CAC9B,CAAA,CAIJ,IAAMuC,CAAAA,CAAc9F,CAAAA,GAAS,MAAA,CAAYA,CAAAA,CAAOkD,CAAAA,CAEhD,GAAI,CAAC4C,CAAAA,CAAa,OAAO,IAAA,CAEzB,IAAMmE,CAAAA,CAAgB,IAChBnE,CAAAA,CAAY,IAAA,GAAS,OAErB9C,GAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,SAAU,UAAW,CAAA,CAC/D,QAAA,CAAAI,CAAAA,CAAW0C,CAAAA,CAAY,MAAM,CAAA,CAChC,CAAA,CAKF9C,IAACsG,EAAAA,CAAA,CACC,WAAA,CAAaxD,CAAAA,CACb,WAAA,CAAa0B,CAAAA,CACb,aAAA,CAAe7D,CAAAA,CACf,cAAeM,CAAAA,CACjB,CAAA,CAKJ,OAAIjE,CAAAA,GAAS,OAETmG,IAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAU,uBAAA,CACV,MAAO,CACL,QAAA,CAAU,UAAA,CACV,KAAA,CAAO,MAAA,CACP,MAAA,CAAQ,MAAA,CACR,QAAA,CAAU,QACZ,CAAA,CAEC,QAAA,CAAA,CAAA8D,CAAAA,EAAc,CACfjH,IAACgE,EAAAA,CAAA,CACC,QAAA,CAAUxE,CAAAA,CACV,cAAeyE,CAAAA,CACf,oBAAA,CAAsB3D,CAAAA,CAAW,WAAA,CACnC,CAAA,CAAA,CACF,CAAA,CAIG2G,CAAAA,EACT,EC3LO,IAAMC,CAAAA,CAAmBvK,aAAAA,CAA8C,IAAI,CAAA,CCWlF,IAAMwK,GAA2D,CAC/D,GAAA,CAAK,CACH,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,MACN,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,KAAA,CACR,OAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,KAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,IAAA,CAAM,CACJ,SAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,MAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,KAAA,CAAO,CACL,SAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,KAAA,CAAO,CAAA,CACP,KAAA,CAAO,MACP,MAAA,CAAQ,MAAA,CACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,KAAA,CACL,IAAA,CAAM,KAAA,CACN,KAAA,CAAO,KAAA,CACP,OAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CACF,CAAA,CAEMC,EAAAA,CAAwD,CAC5D,IAAK,CACH,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,KAAM,CACJ,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,EACA,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,MAAO,CAAA,CACP,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,EACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,CAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,CACF,CAAA,CAEMC,EAAAA,CAAoC,CAAC,CAAE,EAAA,CAAA5D,CAAAA,CAAI,QAAA,CAAAC,CAAAA,CAAU,gBAAAC,CAAgB,CAAA,GAAM,CAC/E,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,MAAA,CAAAC,CAAO,EAAIC,YAAAA,CAAa,CAAE,EAAA,CAAAL,CAAG,CAAC,CAAA,CAClD,OACEN,IAAAA,CAAAY,SAAA,CACE,QAAA,CAAA,CAAA/D,GAAAA,CAAC,KAAA,CAAA,CAAI,GAAA,CAAK4D,CAAAA,CAAY,KAAA,CAAOuD,EAAAA,CAAoBzD,CAAQ,CAAA,CAAG,CAAA,CAC3DG,CAAAA,EAAU7D,GAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAW2D,CAAAA,CAAiB,KAAA,CAAOyD,GAAiB1D,CAAQ,CAAA,CAAG,CAAA,CAAA,CACjF,CAEJ,EAQa4D,EAAAA,CAA4B,CAAC,CAAE,EAAA,CAAA7D,EAAI,QAAA,CAAArC,CAAAA,CAAU,KAAA,CAAAmG,CAAM,CAAA,GAAM,CACpE,GAAM,CACJ,OAAArH,CAAAA,CACA,QAAA,CAAAV,CAAAA,CACA,UAAA,CAAAc,EACA,gBAAA,CAAAC,CAAAA,CACA,QAAA,CAAAE,CAAAA,CACA,mBAAAD,CAAAA,CACA,UAAA,CAAAzD,CAAAA,CACA,kBAAA,CAAAgC,CACF,CAAA,CAAInC,CAAAA,EAAa,CACX4K,EAAgBhI,CAAAA,GAAa,IAAA,EAAQA,CAAAA,GAAaiE,CAAAA,CAElD,CAAE,UAAA,CAAAgE,CAAAA,CAAY,SAAA,CAAAC,CAAAA,CAAW,WAAA9D,CAAAA,CAAY,UAAA,CAAA+D,CAAW,CAAA,CAAIC,YAAAA,CAAa,CAAE,EAAA,CAAAnE,CAAG,CAAC,CAAA,CACvEoE,CAAAA,CAAWrI,CAAAA,GAAaiE,CAAAA,EAAMkE,CAAAA,CAC9BG,CAAAA,CAAevH,CAAAA,GAAqBkD,CAAAA,CAGpCsE,EADW7E,OAAAA,CAAQ,IAAMnF,CAAAA,CAAamC,CAAAA,CAAQuD,CAAE,CAAA,CAAG,CAACvD,CAAAA,CAAQuD,CAAE,CAAC,CAAA,EAC1C,QAAA,CAErBuE,CAAAA,CAA+B,CACnC,UAAA,CAAYH,CAAAA,CACZ,YAAA,CAAAC,CAAAA,CACA,iBAAkB,IAAMtH,CAAAA,GAAqBsH,CAAAA,CAAe,IAAA,CAAOrE,CAAE,CAAA,CACrE,MAAA,CAAQ,IAAM,CACRqE,CAAAA,EACFtH,CAAAA,GAAqB,IAAI,CAAA,CAEvBC,EACFA,CAAAA,CAASgD,CAAE,CAAA,CAEX1G,CAAAA,CAAW0G,CAAE,EAEjB,CAAA,CACA,QAAA,CAAAsE,CAAAA,CACA,cAAA,CAAiB/I,CAAAA,EAAY,CAC3BD,CAAAA,CAAmB0E,EAAIzE,CAAO,EAChC,CACF,CAAA,CAGMiE,EAAeC,OAAAA,CACnB,KAAO,CACL,GAAGwE,EACH,GAAGD,CACL,CAAA,CAAA,CACA,CAACC,CAAAA,CAAWD,CAAU,CACxB,CAAA,CAEA,OACEzH,GAAAA,CAACkH,CAAAA,CAAiB,QAAA,CAAjB,CAA0B,KAAA,CAAOjE,CAAAA,CAChC,QAAA,CAAAE,IAAAA,CAAC,OACC,GAAA,CAAKS,CAAAA,CACL,SAAA,CAAWtD,CAAAA,CAAW,IAAA,CACtB,KAAA,CAAO,CAAE,QAAA,CAAU,WAAY,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,GAAGiH,CAAM,CAAA,CAEtE,QAAA,CAAA,CAAAnG,CAAAA,CAAS4G,CAAW,CAAA,CAEpBR,CAAAA,EACCrE,IAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,CAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CAEE,QAAA,CAAA,CAAA,CAAC,KAAA,CAAO,QAAA,CAAU,MAAA,CAAQ,OAAO,CAAA,CAAY,IAAKgB,CAAAA,EAClDnE,GAAAA,CAACqH,EAAAA,CAAA,CAEC,GAAI,CAAA,KAAA,EAAQlD,CAAG,CAAA,CAAA,EAAIV,CAAE,GACrB,QAAA,CAAUU,CAAAA,CACV,eAAA,CAAiB7D,CAAAA,CAAW,WAAA,CAAA,CAHvB6D,CAIP,CACD,CAAA,CACDnE,IAACqH,EAAAA,CAAA,CACC,EAAA,CAAI,CAAA,YAAA,EAAe5D,CAAE,CAAA,CAAA,CACrB,QAAA,CAAS,QAAA,CACT,gBAAiBnD,CAAAA,CAAW,WAAA,CAC9B,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,CAAA,CACF,CAEJ,ECnNO,IAAM2H,EAAAA,CAAwC,CAAC,CAAE,SAAA7G,CAAAA,CAAU,SAAA,CAAA1B,CAAAA,CAAW,KAAA,CAAA6H,CAAM,CAAA,GAAM,CACvF,IAAMW,EAAYpL,UAAAA,CAAWoK,CAAgB,CAAA,CAC7C,GAAI,CAACgB,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,2CAA2C,CAAA,CAE7D,OACElI,GAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAWN,CAAAA,CACX,KAAA,CAAO,CAAE,OAAQ,MAAA,CAAQ,UAAA,CAAY,MAAA,CAAQ,GAAG6H,CAAM,CAAA,CACrD,GAAGW,CAAAA,CAEH,QAAA,CAAA9G,EACH,CAEJ","file":"index.js","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPaneNode(tree, idA)\n const nodeB = findPaneNode(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPaneNode(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPaneNode(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPaneNode(tree.first, paneId) ?? findPaneNode(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPaneNode,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n layout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPaneNode(layout, draggingId) ?? { type: 'pane', paneId: draggingId }\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layout, paneIdA, paneIdB)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPaneNode(layout, paneToAdd) ?? { type: 'pane', paneId: paneToAdd }\n const treeWithoutDragging = removePane(layout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layout, currentNode, percentage)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layout, paneId, updater)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPaneNode } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPaneNode(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleRemovePane","useCallback","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n layout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(layout, draggingId) ?? { type: 'pane', paneId: draggingId }\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(layout, paneId)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layout, paneIdA, paneIdB)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(layout, paneToAdd) ?? { type: 'pane', paneId: paneToAdd }\n const treeWithoutDragging = removePane(layout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layout, currentNode, percentage)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layout, paneId, updater)\n onChange(newLayout)\n },\n [layout, onChange],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-zeugma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Recursive drag-and-drop dashboard layout engine for React — combining the tree-based splitting of react-mosaic with the declarative API of react-grid-layout.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|