react-zeugma 0.2.0 → 0.3.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 CHANGED
@@ -107,16 +107,17 @@ export default function Dashboard() {
107
107
 
108
108
  The context provider that sets up the drag-and-drop state machine, monitors active drags, and registers layout change notifications.
109
109
 
110
- | Prop | Type | Required | Description |
111
- | -------------------- | ------------------------------------ | -------- | ----------------------------------------------------------------------- |
112
- | `layout` | `TreeNode \| null` | Yes | The serializable tree layout schema. |
113
- | `onChange` | `(layout: TreeNode \| null) => void` | Yes | Fires when resizes, splits, swaps, or removes modify the tree. |
114
- | `renderPane` | `(paneId: string) => ReactNode` | Yes | Renderer function lookup that returns a `<Pane>` structure. |
115
- | `renderDragOverlay` | `(activeId: string) => ReactNode` | No | Renders a custom cursor-following drag preview. |
116
- | `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
117
- | `fullscreenPaneId` | `string \| null` | No | Active ID of the pane taking full viewport coverage. |
118
- | `onFullscreenChange` | `(paneId: string \| null) => void` | No | Callback triggered when a pane enters/leaves fullscreen. |
119
- | `onRemove` | `(paneId: string) => void` | No | Callback triggered when a pane is closed/removed. |
110
+ | Prop | Type | Required | Description |
111
+ | ------------------------ | ------------------------------------ | -------- | ----------------------------------------------------------------------------------------- |
112
+ | `layout` | `TreeNode \| null` | Yes | The serializable tree layout schema. |
113
+ | `onChange` | `(layout: TreeNode \| null) => void` | Yes | Fires when resizes, splits, swaps, or removes modify the tree. |
114
+ | `renderPane` | `(paneId: string) => ReactNode` | Yes | Renderer function lookup that returns a `<Pane>` structure. |
115
+ | `renderDragOverlay` | `(activeId: string) => ReactNode` | No | Renders a custom cursor-following drag preview. |
116
+ | `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
117
+ | `fullscreenPaneId` | `string \| null` | No | Active ID of the pane taking full viewport coverage. |
118
+ | `onFullscreenChange` | `(paneId: string \| null) => void` | No | Callback triggered when a pane enters/leaves fullscreen. |
119
+ | `onRemove` | `(paneId: string) => void` | No | Callback triggered when a pane is closed/removed. |
120
+ | `dragActivationDistance` | `number` | No | Minimum pointer drag distance (in pixels) required to activate dragging. Defaults to `8`. |
120
121
 
121
122
  ### `<PaneTree>`
122
123
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,7 @@
1
- 'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var O=react.createContext(void 0),I=()=>{let e=react.useContext(O);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function S(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=S(e.first,t),o=S(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function C(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},c={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:c,second:s?c:i,splitPercentage:50}}return e}return {...e,first:C(e.first,t,n,o,r)||e.first,second:C(e.second,t,n,o,r)||e.second}}function E(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:E(e.first,t,n)||e.first,second:E(e.second,t,n)||e.second}}function B(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}var j=({activeId:e,render:t,className:n})=>{let o=react.useRef(null);return react.useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsxRuntime.jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},A=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:c,onRemove:s,dragActivationDistance:a=8,children:x})=>{let[g,h]=react.useState(null),p=core.useSensors(core.useSensor(core.PointerSensor,{activationConstraint:{distance:a}})),l=d=>{h(d.active.id.toString());},f=d=>{h(null);let{active:u,over:N}=d;if(!N)return;let v=u.id.toString(),y=N.id.toString(),R=y.match(/^drop-center-(.+)$/);if(R){let[,M]=R;v!==M&&t(E(e,v,M));return}let D=y.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!D)return;let[,P,w]=D;if(v===w)return;let z=P==="left"||P==="right"?"row":"column",L=S(e,v),T=C(L,w,z,P,v);t(T);};return jsxRuntime.jsxs(O.Provider,{value:{layout:e,onLayoutChange:t,renderPane:n,activeId:g,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:c},children:[jsxRuntime.jsx(core.DndContext,{sensors:p,collisionDetection:core.pointerWithin,onDragStart:l,onDragEnd:f,children:x}),g&&o&&jsxRuntime.jsx(j,{activeId:g,render:o,className:r.dragOverlay})]})};function $(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:$(e.first,t,n)||e.first,second:$(e.second,t,n)||e.second}:e}var Z=({tree:e,resizerSize:t=4})=>{let{layout:n,onLayoutChange:o,renderPane:r,fullscreenPaneId:i,classNames:c}=I(),s=react.useRef(null);if(i&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let a=e!==void 0?e:n;if(!a)return null;if(a.type==="pane")return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(a.paneId)});let{direction:x,first:g,second:h,splitPercentage:p}=a,l=x==="row",f=d=>{d.preventDefault();let u=s.current;if(!u)return;document.body.classList.add("zeugma-resizing");let N=u.getBoundingClientRect(),v=d.clientX,y=d.clientY,R=p,D=w=>{let z=l?(w.clientX-v)/N.width*100:(w.clientY-y)/N.height*100,L=Math.max(5,Math.min(95,R+z)),T=$(n,a,L);o(T);},P=()=>{document.body.classList.remove("zeugma-resizing"),document.removeEventListener("pointermove",D),document.removeEventListener("pointerup",P);};document.addEventListener("pointermove",D),document.addEventListener("pointerup",P);};return jsxRuntime.jsxs("div",{ref:s,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${p} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(Z,{tree:g,resizerSize:t})}),jsxRuntime.jsx("div",{className:c.resizer,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:f,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(Z,{tree:h,resizerSize:t})})]})};var Y=react.createContext(null),ae={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"}},le={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"}},X=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:o,style:ae[t]}),r&&jsxRuntime.jsx("div",{className:n,style:le[t]})]})},de=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:c,onFullscreenChange:s}=I(),a=o!==null&&o!==e,{attributes:x,listeners:g,setNodeRef:h,isDragging:p}=core.useDraggable({id:e}),l=o===e||p,f=i===e,d={isDragging:l,isFullscreen:f,toggleFullscreen:()=>s?.(f?null:e),remove:()=>{f&&s?.(null),c?.(e);}};return jsxRuntime.jsx(Y.Provider,{value:{...g,...x},children:jsxRuntime.jsxs("div",{ref:h,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(d),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(u=>jsxRuntime.jsx(X,{id:`drop-${u}-${e}`,position:u,activeClassName:r.dropPreview},u)),jsxRuntime.jsx(X,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})},ce=({children:e,className:t,style:n})=>{let o=react.useContext(Y);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};exports.DashboardProvider=A;exports.DragHandle=ce;exports.Pane=de;exports.PaneTree=Z;exports.addPane=B;exports.removePane=S;exports.splitPane=C;exports.swapPanes=E;exports.useDashboard=I;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var L=react.createContext(void 0);var N=()=>{let e=react.useContext(L);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function z(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=z(e.first,t),o=z(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function F(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},d={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:d,second:s?d:i,splitPercentage:50}}return e}return {...e,first:F(e.first,t,n,o,r)||e.first,second:F(e.second,t,n,o,r)||e.second}}function A(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:A(e.first,t,n)||e.first,second:A(e.second,t,n)||e.second}}function we(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}function H(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:H(e.first,t,n)||e.first,second:H(e.second,t,n)||e.second}:e}var q=8,B=8,Le=4;var ie=({activeId:e,render:t,className:n})=>{let o=react.useRef(null);return react.useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsxRuntime.jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},se=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:d,onRemove:s,dragActivationDistance:c=8,snapThreshold:u=8,children:m})=>{let[l,a]=react.useState(null),R=core.useSensors(core.useSensor(core.PointerSensor,{activationConstraint:{distance:c}})),b=g=>{a(g.active.id.toString());},S=g=>{a(null);let{active:Z,over:y}=g;if(!y)return;let h=Z.id.toString(),p=y.id.toString(),f=p.match(/^drop-center-(.+)$/);if(f){let[,T]=f;h!==T&&t(A(e,h,T));return}let x=p.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!x)return;let[,I,E]=x;if(h===E)return;let D=I==="left"||I==="right"?"row":"column",w=z(e,h),_=F(w,E,D,I,h);t(_);},P=react.useMemo(()=>({layout:e,onLayoutChange:t,renderPane:n,activeId:l,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:d,snapThreshold:u}),[e,t,n,l,i,r,s,d,u]);return jsxRuntime.jsxs(L.Provider,{value:P,children:[jsxRuntime.jsx(core.DndContext,{sensors:R,collisionDetection:core.pointerWithin,onDragStart:b,onDragEnd:S,children:m}),l&&o&&jsxRuntime.jsx(ie,{activeId:l,render:o,className:r.dragOverlay})]})};function U({containerRef:e,isRow:t,direction:n,splitPercentage:o,resizerSize:r,snapThreshold:i,layout:d,currentNode:s,onLayoutChange:c}){return react.useCallback(u=>{u.preventDefault();let m=e.current;if(!m)return;document.body.classList.add("zeugma-resizing");let l=document.createElement("style");l.id="zeugma-global-cursor-style",l.textContent=`
2
+ * {
3
+ cursor: ${t?"col-resize":"row-resize"} !important;
4
+ user-select: none !important;
5
+ }
6
+ `,document.head.appendChild(l);let a=m.getBoundingClientRect(),R=u.clientX,b=u.clientY,S=o,P=u.currentTarget;P.setAttribute("data-resizing","true");let Z=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(p=>p!==P&&p.getAttribute("data-direction")===n).map(p=>{let f=p.getBoundingClientRect();return t?f.left+f.width/2:f.top+f.height/2}),y=p=>{let f=t?(p.clientX-R)/a.width*100:(p.clientY-b)/a.height*100,x=S+f,I=t?a.left+(a.width-r)*(x/100)+r/2:a.top+(a.height-r)*(x/100)+r/2,E=1/0,D=null;for(let X of Z){let $=Math.abs(I-X);$<i&&$<E&&(E=$,D=X);}let w=x;D!==null&&(w=t?(D-r/2-a.left)/(a.width-r)*100:(D-r/2-a.top)/(a.height-r)*100);let _=Math.max(5,Math.min(95,w)),T=H(d,s,_);c(T);},h=()=>{document.body.classList.remove("zeugma-resizing"),P.removeAttribute("data-resizing");let p=document.getElementById("zeugma-global-cursor-style");p&&p.remove(),document.removeEventListener("pointermove",y),document.removeEventListener("pointerup",h);};document.addEventListener("pointermove",y),document.addEventListener("pointerup",h);},[e,t,n,o,r,i,d,s,c])}var ce=({currentNode:e,resizerSize:t,snapThreshold:n})=>{let{layout:o,onLayoutChange:r,classNames:i}=N(),d=react.useRef(null),{direction:s,first:c,second:u,splitPercentage:m}=e,l=s==="row",a=U({containerRef:d,isRow:l,direction:s,splitPercentage:m,resizerSize:t,snapThreshold:n??8,layout:o,currentNode:e,onLayoutChange:r});return jsxRuntime.jsxs("div",{ref:d,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${m} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(V,{tree:c,resizerSize:t,snapThreshold:n})}),jsxRuntime.jsx("div",{className:i.resizer,"data-direction":s,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:a,role:"separator","aria-valuenow":m,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-m} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(V,{tree:u,resizerSize:t,snapThreshold:n})})]})},V=({tree:e,resizerSize:t=4,snapThreshold:n})=>{let{layout:o,renderPane:r,fullscreenPaneId:i,snapThreshold:d}=N(),s=n!==void 0?n:d;if(i&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let c=e!==void 0?e:o;return c?c.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(c.paneId)}):jsxRuntime.jsx(ce,{currentNode:c,resizerSize:t,snapThreshold:s}):null};var M=react.createContext(null);var he={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"}},ve={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"}},Y=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:o,style:he[t]}),r&&jsxRuntime.jsx("div",{className:n,style:ve[t]})]})},be=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:d,onFullscreenChange:s}=N(),c=o!==null&&o!==e,{attributes:u,listeners:m,setNodeRef:l,isDragging:a}=core.useDraggable({id:e}),R=o===e||a,b=i===e,S={isDragging:R,isFullscreen:b,toggleFullscreen:()=>s?.(b?null:e),remove:()=>{b&&s?.(null),d?.(e);}},P=react.useMemo(()=>({...m,...u}),[m,u]);return jsxRuntime.jsx(M.Provider,{value:P,children:jsxRuntime.jsxs("div",{ref:l,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(S),c&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(g=>jsxRuntime.jsx(Y,{id:`drop-${g}-${e}`,position:g,activeClassName:r.dropPreview},g)),jsxRuntime.jsx(Y,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})};var De=({children:e,className:t,style:n})=>{let o=react.useContext(M);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=B;exports.DEFAULT_RESIZER_SIZE=Le;exports.DEFAULT_SNAP_THRESHOLD=q;exports.DashboardProvider=se;exports.DragHandle=De;exports.Pane=be;exports.PaneTree=V;exports.addPane=we;exports.removePane=z;exports.splitPane=F;exports.swapPanes=A;exports.updateSplitPercentage=H;exports.useDashboard=N;exports.useResizer=U;//# sourceMappingURL=index.cjs.map
2
7
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"kHA+BaA,CAAAA,CAAmBC,mBAAAA,CAAiD,MAAS,CAAA,CAE7EC,CAAAA,CAAe,IAAM,CAChC,IAAMC,EAAUC,gBAAAA,CAAWJ,CAAgB,EAC3C,GAAI,CAACG,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,sDAAsD,EAExE,OAAOA,CACT,EAGO,SAASE,CAAAA,CAAWC,EAAuBC,CAAAA,CAAqC,CACrF,GAAID,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,EAAK,IAAA,GAAS,MAAA,CAChB,OAAOA,CAAAA,CAAK,SAAWC,CAAAA,CAAa,IAAA,CAAOD,EAE7C,IAAME,CAAAA,CAAWH,EAAWC,CAAAA,CAAK,KAAA,CAAOC,CAAU,CAAA,CAC5CE,CAAAA,CAAYJ,EAAWC,CAAAA,CAAK,MAAA,CAAQC,CAAU,CAAA,CACpD,OAAIC,IAAa,IAAA,CAAaC,CAAAA,CAC1BA,CAAAA,GAAc,IAAA,CAAaD,EACxB,CAAE,GAAGF,EAAM,KAAA,CAAOE,CAAAA,CAAU,OAAQC,CAAU,CACvD,CAGO,SAASC,CAAAA,CACdJ,EACAK,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACiB,CACjB,GAAIR,CAAAA,GAAS,IAAA,CAAM,OAAO,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQQ,CAAU,CAAA,CAC5D,GAAIR,EAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,SAAWK,CAAAA,CAAU,CAC5B,IAAMI,CAAAA,CAAsB,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQD,CAAU,CAAA,CACxDE,EAAyB,CAAE,IAAA,CAAM,OAAQ,MAAA,CAAQL,CAAS,EAC1DM,CAAAA,CAAUJ,CAAAA,GAAc,QAAUA,CAAAA,GAAc,KAAA,CACtD,OAAO,CACL,IAAA,CAAM,QACN,SAAA,CAAAD,CAAAA,CACA,MAAOK,CAAAA,CAAUF,CAAAA,CAAYC,CAAAA,CAC7B,MAAA,CAAQC,EAAUD,CAAAA,CAAeD,CAAAA,CACjC,gBAAiB,EACnB,CACF,CACA,OAAOT,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOI,EAAUJ,CAAAA,CAAK,KAAA,CAAOK,EAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKR,EAAK,KAAA,CAChF,MAAA,CAAQI,EAAUJ,CAAAA,CAAK,MAAA,CAAQK,EAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKR,EAAK,MACpF,CACF,CAGO,SAASY,CAAAA,CAAUZ,EAAuBa,CAAAA,CAAaC,CAAAA,CAA8B,CAC1F,OAAId,IAAS,IAAA,CAAa,IAAA,CACtBA,EAAK,IAAA,GAAS,MAAA,CACZA,EAAK,MAAA,GAAWa,CAAAA,CAAY,CAAE,GAAGb,CAAAA,CAAM,OAAQc,CAAI,CAAA,CACnDd,EAAK,MAAA,GAAWc,CAAAA,CAAY,CAAE,GAAGd,CAAAA,CAAM,MAAA,CAAQa,CAAI,EAChDb,CAAAA,CAEF,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOY,EAAUZ,CAAAA,CAAK,KAAA,CAAOa,EAAKC,CAAG,CAAA,EAAKd,EAAK,KAAA,CAC/C,MAAA,CAAQY,EAAUZ,CAAAA,CAAK,MAAA,CAAQa,EAAKC,CAAG,CAAA,EAAKd,CAAAA,CAAK,MACnD,CACF,CAGO,SAASe,EAAQf,CAAAA,CAAuBQ,CAAAA,CAA6B,CAC1E,GAAIR,CAAAA,GAAS,KACX,OAAO,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQQ,CAAU,CAAA,CAG3C,SAASQ,EAAOC,CAAAA,CAAgBC,CAAAA,CAAkD,CAChF,OAAID,EAAK,IAAA,GAAS,MAAA,CAET,CACL,IAAA,CAAM,OAAA,CACN,UAHgCC,CAAAA,GAAoB,KAAA,CAAQ,SAAW,KAAA,CAIvE,eAAA,CAAiB,GACjB,KAAA,CAAOD,CAAAA,CACP,OAAQ,CAAE,IAAA,CAAM,OAAQ,MAAA,CAAQT,CAAU,CAC5C,CAAA,CAGK,CACL,GAAGS,CAAAA,CACH,OAAQD,CAAAA,CAAOC,CAAAA,CAAK,OAAQA,CAAAA,CAAK,SAAS,CAC5C,CACF,CAEA,OAAOD,CAAAA,CAAOhB,CAAAA,CAAM,IAAI,CAC1B,KAGMmB,CAAAA,CAID,CAAC,CAAE,QAAA,CAAAC,EAAU,MAAA,CAAAC,CAAAA,CAAQ,UAAAC,CAAU,CAAA,GAAM,CACxC,IAAMC,CAAAA,CAAMC,aAAuB,IAAI,CAAA,CAEvC,OAAAC,eAAAA,CAAU,IAAM,CACd,IAAMC,CAAAA,CAAcC,GAAoB,CAClCJ,CAAAA,CAAI,OAAA,GACNA,CAAAA,CAAI,QAAQ,KAAA,CAAM,SAAA,CAAY,aAAaI,CAAAA,CAAE,OAAA,CAAU,EAAE,CAAA,IAAA,EAAOA,CAAAA,CAAE,QAAU,EAAE,CAAA,GAAA,CAAA,EAElF,EACA,OAAA,QAAA,CAAS,gBAAA,CAAiB,cAAeD,CAAU,CAAA,CAC5C,IAAM,QAAA,CAAS,mBAAA,CAAoB,aAAA,CAAeA,CAAU,CACrE,CAAA,CAAG,EAAE,CAAA,CAGHE,cAAAA,CAAC,OACC,GAAA,CAAKL,CAAAA,CACL,SAAA,CAAWD,CAAAA,CACX,MAAO,CACL,QAAA,CAAU,QACV,GAAA,CAAK,CAAA,CACL,KAAM,CAAA,CACN,MAAA,CAAQ,IAAA,CACR,aAAA,CAAe,MACjB,CAAA,CAEC,QAAA,CAAAD,EAAOD,CAAQ,CAAA,CAClB,CAEJ,CAAA,CAeaS,CAAAA,CAAsD,CAAC,CAClE,MAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CACA,iBAAA,CAAAC,EACA,UAAA,CAAAC,CAAAA,CAAa,EAAC,CACd,iBAAAC,CAAAA,CAAmB,IAAA,CACnB,mBAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,sBAAA,CAAAC,CAAAA,CAAyB,EACzB,QAAA,CAAAC,CACF,IAAM,CACJ,GAAM,CAACnB,CAAAA,CAAUoB,CAAW,EAAIC,cAAAA,CAAwB,IAAI,CAAA,CAEtDC,CAAAA,CAAUC,gBACdC,cAAAA,CAAUC,kBAAAA,CAAe,CACvB,oBAAA,CAAsB,CAAE,SAAUP,CAAuB,CAC3D,CAAC,CACH,CAAA,CAEMQ,EAAmBC,CAAAA,EAA0B,CACjDP,EAAYO,CAAAA,CAAM,MAAA,CAAO,GAAG,QAAA,EAAU,EACxC,CAAA,CAEMC,EAAiBD,CAAAA,EAAwB,CAC7CP,EAAY,IAAI,CAAA,CAChB,GAAM,CAAE,MAAA,CAAAS,EAAQ,IAAA,CAAAC,CAAK,EAAIH,CAAAA,CACzB,GAAI,CAACG,CAAAA,CAAM,OAEX,IAAMC,CAAAA,CAAaF,CAAAA,CAAO,EAAA,CAAG,QAAA,GACvBG,CAAAA,CAAYF,CAAAA,CAAK,GAAG,QAAA,EAAS,CAG7BG,EAAYD,CAAAA,CAAU,KAAA,CAAM,oBAAoB,CAAA,CACtD,GAAIC,EAAW,CACb,GAAM,EAAGhD,CAAQ,EAAIgD,CAAAA,CACjBF,CAAAA,GAAe9C,CAAAA,EACjB0B,CAAAA,CAASnB,EAAUkB,CAAAA,CAAQqB,CAAAA,CAAY9C,CAAQ,CAAC,CAAA,CAElD,MACF,CAGA,IAAMiD,EAAQF,CAAAA,CAAU,KAAA,CAAM,qCAAqC,CAAA,CACnE,GAAI,CAACE,CAAAA,CAAO,OAEZ,GAAM,EAAGC,CAAAA,CAAUlD,CAAQ,EAAIiD,CAAAA,CAC/B,GAAIH,IAAe9C,CAAAA,CAAU,OAE7B,IAAMC,CAAAA,CAA4BiD,CAAAA,GAAa,QAAUA,CAAAA,GAAa,OAAA,CAAU,MAAQ,QAAA,CAClFC,CAAAA,CAAsBzD,EAAW+B,CAAAA,CAAQqB,CAAU,EAEnDM,CAAAA,CAAYrD,CAAAA,CAChBoD,CAAAA,CACAnD,CAAAA,CACAC,EACAiD,CAAAA,CACAJ,CACF,EACApB,CAAAA,CAAS0B,CAAS,EACpB,CAAA,CAEA,OACEC,eAAAA,CAAChE,CAAAA,CAAiB,SAAjB,CACC,KAAA,CAAO,CACL,MAAA,CAAAoC,CAAAA,CACA,eAAgBC,CAAAA,CAChB,UAAA,CAAAC,CAAAA,CACA,QAAA,CAAAZ,EACA,gBAAA,CAAAe,CAAAA,CACA,WAAAD,CAAAA,CACA,QAAA,CAAAG,EACA,kBAAA,CAAAD,CACF,EAEA,QAAA,CAAA,CAAAR,cAAAA,CAAC+B,gBAAA,CACC,OAAA,CAASjB,EACT,kBAAA,CAAoBkB,kBAAAA,CACpB,YAAad,CAAAA,CACb,SAAA,CAAWE,CAAAA,CAEV,QAAA,CAAAT,EACH,CAAA,CACCnB,CAAAA,EAAYa,GACXL,cAAAA,CAACT,CAAAA,CAAA,CACC,QAAA,CAAUC,CAAAA,CACV,OAAQa,CAAAA,CACR,SAAA,CAAWC,EAAW,WAAA,CACxB,CAAA,CAAA,CAEJ,CAEJ,ECjQA,SAAS2B,CAAAA,CACP7D,CAAAA,CACA8D,EACAC,CAAAA,CACiB,CACjB,OAAI/D,CAAAA,GAAS,IAAA,CAAa,KACtBA,CAAAA,GAAS8D,CAAAA,CACJ,CAAE,GAAG9D,CAAAA,CAAM,gBAAiB+D,CAAc,CAAA,CAE/C/D,CAAAA,CAAK,IAAA,GAAS,QACT,CACL,GAAGA,EACH,KAAA,CAAO6D,CAAAA,CAAsB7D,EAAK,KAAA,CAAO8D,CAAAA,CAAQC,CAAa,CAAA,EAAK/D,CAAAA,CAAK,MACxE,MAAA,CAAQ6D,CAAAA,CAAsB7D,EAAK,MAAA,CAAQ8D,CAAAA,CAAQC,CAAa,CAAA,EAAK/D,CAAAA,CAAK,MAC5E,CAAA,CAEKA,CACT,CAEO,IAAMgE,EAAoC,CAAC,CAAE,KAAAhE,CAAAA,CAAM,WAAA,CAAAiE,EAAc,CAAE,CAAA,GAAM,CAC9E,GAAM,CAAE,OAAAnC,CAAAA,CAAQ,cAAA,CAAAoC,EAAgB,UAAA,CAAAlC,CAAAA,CAAY,gBAAA,CAAAG,CAAAA,CAAkB,WAAAD,CAAW,CAAA,CAAItC,GAAa,CACpFuE,CAAAA,CAAe3C,aAAuB,IAAI,CAAA,CAGhD,GAAIW,CAAAA,EAAoB,CAACnC,EACvB,OACE4B,cAAAA,CAAC,OAAI,KAAA,CAAO,CAAE,MAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,UAAW,CAAA,CAC/D,QAAA,CAAAI,EAAWG,CAAgB,CAAA,CAC9B,EAIJ,IAAMiC,CAAAA,CAAcpE,IAAS,MAAA,CAAYA,CAAAA,CAAO8B,EAEhD,GAAI,CAACsC,EAAa,OAAO,IAAA,CAEzB,GAAIA,CAAAA,CAAY,IAAA,GAAS,MAAA,CACvB,OACExC,eAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAA,CAAO,MAAA,CAAQ,OAAQ,MAAA,CAAQ,QAAA,CAAU,UAAW,CAAA,CAC/D,SAAAI,CAAAA,CAAWoC,CAAAA,CAAY,MAAM,CAAA,CAChC,CAAA,CAIJ,GAAM,CAAE,SAAA,CAAA9D,CAAAA,CAAW,KAAA,CAAA+D,EAAO,MAAA,CAAAC,CAAAA,CAAQ,gBAAAC,CAAgB,CAAA,CAAIH,EAChDI,CAAAA,CAAQlE,CAAAA,GAAc,MAEtBmE,CAAAA,CAAqB9C,CAAAA,EAA0B,CACnDA,CAAAA,CAAE,cAAA,GACF,IAAM+C,CAAAA,CAAYP,EAAa,OAAA,CAC/B,GAAI,CAACO,CAAAA,CAAW,OAEhB,QAAA,CAAS,IAAA,CAAK,UAAU,GAAA,CAAI,iBAAiB,EAE7C,IAAMC,CAAAA,CAAOD,EAAU,qBAAA,EAAsB,CACvCE,EAASjD,CAAAA,CAAE,OAAA,CACXkD,EAASlD,CAAAA,CAAE,OAAA,CACXmD,EAAkBP,CAAAA,CAElBQ,CAAAA,CAAqBC,CAAAA,EAA4B,CACrD,IAAMC,CAAAA,CAAQT,CAAAA,CAAAA,CACRQ,EAAU,OAAA,CAAUJ,CAAAA,EAAUD,EAAK,KAAA,CAAS,GAAA,CAAA,CAC5CK,EAAU,OAAA,CAAUH,CAAAA,EAAUF,EAAK,MAAA,CAAU,GAAA,CAC7CZ,EAAgB,IAAA,CAAK,GAAA,CAAI,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,CAAIe,CAAAA,CAAkBG,CAAK,CAAC,CAAA,CACjExB,EAAYI,CAAAA,CAAsB/B,CAAAA,CAAQsC,EAAaL,CAAa,CAAA,CAC1EG,EAAeT,CAAS,EAC1B,EAEMyB,CAAAA,CAAkB,IAAM,CAC5B,QAAA,CAAS,IAAA,CAAK,UAAU,MAAA,CAAO,iBAAiB,CAAA,CAChD,QAAA,CAAS,oBAAoB,aAAA,CAAeH,CAAiB,EAC7D,QAAA,CAAS,mBAAA,CAAoB,YAAaG,CAAe,EAC3D,EAEA,QAAA,CAAS,gBAAA,CAAiB,cAAeH,CAAiB,CAAA,CAC1D,SAAS,gBAAA,CAAiB,WAAA,CAAaG,CAAe,EACxD,CAAA,CAEA,OACExB,eAAAA,CAAC,OACC,GAAA,CAAKS,CAAAA,CACL,MAAO,CACL,OAAA,CAAS,OACT,aAAA,CAAeK,CAAAA,CAAQ,MAAQ,QAAA,CAC/B,KAAA,CAAO,OACP,MAAA,CAAQ,MAAA,CACR,SAAU,QACZ,CAAA,CAEA,UAAA5C,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAM,CAAA,EAAG2C,CAAe,QAAS,QAAA,CAAU,QAAS,EAChE,QAAA,CAAA3C,cAAAA,CAACoC,EAAA,CAAS,IAAA,CAAMK,EAAO,WAAA,CAAaJ,CAAAA,CAAa,EACnD,CAAA,CACArC,cAAAA,CAAC,OACC,SAAA,CAAWM,CAAAA,CAAW,OAAA,CACtB,KAAA,CAAO,CACL,KAAA,CAAOsC,CAAAA,CAAQ,GAAGP,CAAW,CAAA,EAAA,CAAA,CAAO,OACpC,MAAA,CAAQO,CAAAA,CAAQ,MAAA,CAAS,CAAA,EAAGP,CAAW,CAAA,EAAA,CAAA,CACvC,MAAA,CAAQO,EAAQ,YAAA,CAAe,YAAA,CAC/B,SAAU,UAAA,CACV,MAAA,CAAQ,EAAA,CACR,UAAA,CAAY,OACZ,SAAA,CAAW,YAAA,CACX,WAAY,CACd,CAAA,CACA,cAAeC,CAAAA,CACf,IAAA,CAAK,YACL,eAAA,CAAeF,CAAAA,CACf,gBAAe,CAAA,CACf,eAAA,CAAe,GACjB,CAAA,CACA3C,cAAAA,CAAC,OAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAG,IAAM2C,CAAe,CAAA,KAAA,CAAA,CAAS,SAAU,QAAS,CAAA,CACtE,SAAA3C,cAAAA,CAACoC,CAAAA,CAAA,CAAS,IAAA,CAAMM,CAAAA,CAAQ,YAAaL,CAAAA,CAAa,CAAA,CACpD,GACF,CAEJ,ECxHA,IAAMkB,EAAmBxF,mBAAAA,CAA8C,IAAI,EAQrEyF,EAAAA,CAA2D,CAC/D,GAAA,CAAK,CACH,SAAU,UAAA,CACV,GAAA,CAAK,EACL,IAAA,CAAM,KAAA,CACN,MAAO,KAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,WACV,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,KAAA,CACN,MAAO,KAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,KAAM,CACJ,QAAA,CAAU,WACV,GAAA,CAAK,CAAA,CACL,OAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,MAAA,CACR,OAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,MAAA,CAAQ,EACR,KAAA,CAAO,CAAA,CACP,MAAO,KAAA,CACP,MAAA,CAAQ,OACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,EACA,MAAA,CAAQ,CACN,SAAU,UAAA,CACV,GAAA,CAAK,MACL,IAAA,CAAM,KAAA,CACN,MAAO,KAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CACF,EAEMC,EAAAA,CAAwD,CAC5D,GAAA,CAAK,CACH,SAAU,UAAA,CACV,GAAA,CAAK,EACL,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,UAAW,YACb,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,EACR,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,IAAA,CAAM,CACJ,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,KAAA,CACP,OAAQ,EAAA,CACR,aAAA,CAAe,OACf,SAAA,CAAW,YACb,EACA,KAAA,CAAO,CACL,SAAU,UAAA,CACV,GAAA,CAAK,EACL,MAAA,CAAQ,CAAA,CACR,MAAO,CAAA,CACP,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,UAAW,YACb,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,WACV,GAAA,CAAK,CAAA,CACL,KAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,CAAA,CACR,OAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,CACF,CAAA,CAEMC,EAAoC,CAAC,CAAE,GAAAC,CAAAA,CAAI,QAAA,CAAAC,EAAU,eAAA,CAAAC,CAAgB,IAAM,CAC/E,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,OAAAC,CAAO,CAAA,CAAIC,iBAAAA,CAAa,CAAE,GAAAL,CAAG,CAAC,EAClD,OACE7B,eAAAA,CAAAmC,oBAAA,CACE,QAAA,CAAA,CAAAjE,eAAC,KAAA,CAAA,CAAI,GAAA,CAAK8D,EAAY,KAAA,CAAON,EAAAA,CAAoBI,CAAQ,CAAA,CAAG,CAAA,CAC3DG,GAAU/D,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAW6D,CAAAA,CAAiB,MAAOJ,EAAAA,CAAiBG,CAAQ,EAAG,CAAA,CAAA,CACjF,CAEJ,EAeaM,EAAAA,CAA4B,CAAC,CAAE,EAAA,CAAAP,CAAAA,CAAI,SAAAhD,CAAAA,CAAU,KAAA,CAAAwD,CAAM,CAAA,GAAM,CACpE,GAAM,CAAE,QAAA,CAAA3E,CAAAA,CAAU,UAAA,CAAAc,EAAY,gBAAA,CAAAC,CAAAA,CAAkB,SAAAE,CAAAA,CAAU,kBAAA,CAAAD,CAAmB,CAAA,CAAIxC,CAAAA,GAC3EoG,CAAAA,CAAgB5E,CAAAA,GAAa,MAAQA,CAAAA,GAAamE,CAAAA,CAElD,CAAE,UAAA,CAAAU,CAAAA,CAAY,UAAAC,CAAAA,CAAW,UAAA,CAAAR,CAAAA,CAAY,UAAA,CAAAS,CAAW,CAAA,CAAIC,iBAAAA,CAAa,CAAE,EAAA,CAAAb,CAAG,CAAC,CAAA,CACvEc,CAAAA,CAAWjF,CAAAA,GAAamE,CAAAA,EAAMY,EAC9BG,CAAAA,CAAenE,CAAAA,GAAqBoD,EAEpCgB,CAAAA,CAA+B,CACnC,WAAYF,CAAAA,CACZ,YAAA,CAAAC,CAAAA,CACA,gBAAA,CAAkB,IAAMlE,CAAAA,GAAqBkE,CAAAA,CAAe,KAAOf,CAAE,CAAA,CACrE,OAAQ,IAAM,CACRe,GACFlE,CAAAA,GAAqB,IAAI,EAE3BC,CAAAA,GAAWkD,CAAE,EACf,CACF,CAAA,CAEA,OACE3D,cAAAA,CAACuD,CAAAA,CAAiB,QAAA,CAAjB,CAA0B,MAAO,CAAE,GAAGe,EAAW,GAAGD,CAAW,EAC9D,QAAA,CAAAvC,eAAAA,CAAC,OACC,GAAA,CAAKgC,CAAAA,CACL,UAAWxD,CAAAA,CAAW,IAAA,CACtB,MAAO,CAAE,QAAA,CAAU,WAAY,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,GAAG6D,CAAM,CAAA,CAEtE,UAAAxD,CAAAA,CAASgE,CAAW,EAEpBP,CAAAA,EACCtC,eAAAA,CAAC,OACC,KAAA,CAAO,CACL,SAAU,UAAA,CACV,GAAA,CAAK,EACL,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,CAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MACjB,EAEE,QAAA,CAAA,CAAA,CAAC,KAAA,CAAO,SAAU,MAAA,CAAQ,OAAO,EAAY,GAAA,CAAK8C,CAAAA,EAClD5E,eAAC0D,CAAAA,CAAA,CAEC,GAAI,CAAA,KAAA,EAAQkB,CAAG,IAAIjB,CAAE,CAAA,CAAA,CACrB,QAAA,CAAUiB,CAAAA,CACV,gBAAiBtE,CAAAA,CAAW,WAAA,CAAA,CAHvBsE,CAIP,CACD,CAAA,CACD5E,eAAC0D,CAAAA,CAAA,CACC,GAAI,CAAA,YAAA,EAAeC,CAAE,GACrB,QAAA,CAAS,QAAA,CACT,gBAAiBrD,CAAAA,CAAW,WAAA,CAC9B,GACF,CAAA,CAAA,CAEJ,CAAA,CACF,CAEJ,CAAA,CAWauE,GAAwC,CAAC,CAAE,SAAAlE,CAAAA,CAAU,SAAA,CAAAjB,EAAW,KAAA,CAAAyE,CAAM,IAAM,CACvF,IAAMW,EAAY5G,gBAAAA,CAAWqF,CAAgB,EAC7C,GAAI,CAACuB,EACH,MAAM,IAAI,KAAA,CAAM,2CAA2C,EAE7D,OACE9E,cAAAA,CAAC,OACC,SAAA,CAAWN,CAAAA,CACX,MAAO,CAAE,MAAA,CAAQ,OAAQ,UAAA,CAAY,MAAA,CAAQ,GAAGyE,CAAM,CAAA,CACrD,GAAGW,CAAAA,CAEH,QAAA,CAAAnE,EACH,CAEJ","file":"index.cjs","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } 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, PaneNode } from '../types'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\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}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\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\n// Tree Helper: Remove a pane and consolidate the tree\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// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : 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// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\n}\n\n// Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree\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/** 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 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 = 8,\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 setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\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 return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\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 draggingId,\n )\n onChange(newLayout)\n }\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext\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, { useRef } from 'react'\nimport { useDashboard } from './dashboard-provider'\nimport { TreeNode, SplitNode } from '../types'\n\ninterface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n}\n\nfunction 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\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard()\n const containerRef = useRef<HTMLDivElement>(null)\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 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 const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\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 newPercentage = Math.max(5, Math.min(95, startPercentage + delta))\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage)\n onLayoutChange(newLayout)\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\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 tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\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 <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n )\n}\n","import React, { createContext, useContext } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from './dashboard-provider'\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null)\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\nexport interface PaneRenderProps {\n isDragging: boolean\n isFullscreen: boolean\n toggleFullscreen: () => void\n remove: () => void\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 { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = 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 renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\n },\n }\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\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\n/**\n * Place inside a Pane to make an element the drag handle.\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/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","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","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","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","contextValue","useMemo","jsxs","DndContext","pointerWithin","useResizer","containerRef","isRow","splitPercentage","resizerSize","currentNode","onLayoutChange","useCallback","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","pos","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode } 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 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}\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,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : 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 if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\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","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 } 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 } from '../../../shared/model'\nimport { removePane, splitPane, swapPanes } from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames } 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 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 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 setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\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 return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\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 draggingId,\n )\n onChange(newLayout)\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 }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\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, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\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}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n}: UseResizerProps) {\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 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 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(5, Math.min(95, snappedPercentage))\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\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\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 ],\n )\n}\n","import React, { useRef } from 'react'\nimport { useDashboard } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\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}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({ currentNode, resizerSize, snapThreshold }) => {\n const { layout, onLayoutChange, classNames } = useDashboard()\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 })\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 tree={first} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n </div>\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 <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n}) => {\n const {\n layout,\n renderPane,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\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 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 currentNode={currentNode} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n )\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'\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 { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = 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 renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\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
@@ -30,12 +30,11 @@ interface DashboardContextValue {
30
30
  classNames: ZeugmaClassNames;
31
31
  onRemove?: (paneId: string) => void;
32
32
  onFullscreenChange?: (paneId: string | null) => void;
33
+ snapThreshold?: number;
33
34
  }
35
+
34
36
  declare const useDashboard: () => DashboardContextValue;
35
- declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
36
- declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
37
- declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
38
- declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
37
+
39
38
  interface DashboardProviderProps {
40
39
  layout: TreeNode | null;
41
40
  onChange: (newLayout: TreeNode | null) => void;
@@ -46,14 +45,30 @@ interface DashboardProviderProps {
46
45
  onFullscreenChange?: (paneId: string | null) => void;
47
46
  onRemove?: (paneId: string) => void;
48
47
  dragActivationDistance?: number;
48
+ snapThreshold?: number;
49
49
  children: ReactNode;
50
50
  }
51
51
  declare const DashboardProvider: React.FC<DashboardProviderProps>;
52
52
 
53
+ interface UseResizerProps {
54
+ containerRef: React.RefObject<HTMLDivElement | null>;
55
+ isRow: boolean;
56
+ direction: SplitDirection;
57
+ splitPercentage: number;
58
+ resizerSize: number;
59
+ snapThreshold: number;
60
+ layout: TreeNode | null;
61
+ currentNode: SplitNode;
62
+ onLayoutChange: (newLayout: TreeNode | null) => void;
63
+ }
64
+ declare function useResizer({ containerRef, isRow, direction, splitPercentage, resizerSize, snapThreshold, layout, currentNode, onLayoutChange, }: UseResizerProps): (e: React.PointerEvent<HTMLDivElement>) => void;
65
+
53
66
  interface PaneTreeProps {
54
67
  tree?: TreeNode | null;
55
68
  /** Size of the resizer in pixels (default 4) */
56
69
  resizerSize?: number;
70
+ /** Threshold in pixels to snap to adjacent resizer edges (default 8) */
71
+ snapThreshold?: number;
57
72
  }
58
73
  declare const PaneTree: React.FC<PaneTreeProps>;
59
74
 
@@ -63,15 +78,14 @@ interface PaneRenderProps {
63
78
  toggleFullscreen: () => void;
64
79
  remove: () => void;
65
80
  }
81
+
66
82
  interface PaneProps {
67
83
  id: string;
68
84
  children: (props: PaneRenderProps) => React.ReactNode;
69
85
  style?: React.CSSProperties;
70
86
  }
71
87
  declare const Pane: React.FC<PaneProps>;
72
- /**
73
- * Place inside a Pane to make an element the drag handle.
74
- */
88
+
75
89
  interface DragHandleProps {
76
90
  children: React.ReactNode;
77
91
  className?: string;
@@ -79,4 +93,29 @@ interface DragHandleProps {
79
93
  }
80
94
  declare const DragHandle: React.FC<DragHandleProps>;
81
95
 
82
- export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, useDashboard };
96
+ declare const DEFAULT_SNAP_THRESHOLD = 8;
97
+ declare const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8;
98
+ declare const DEFAULT_RESIZER_SIZE = 4;
99
+
100
+ /**
101
+ * Tree Helper: Remove a pane and consolidate the tree structure.
102
+ */
103
+ declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
104
+ /**
105
+ * Tree Helper: Insert a pane by splitting an existing target node.
106
+ */
107
+ declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
108
+ /**
109
+ * Tree Helper: Swap the position of two panes in the tree structure.
110
+ */
111
+ declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
112
+ /**
113
+ * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.
114
+ */
115
+ declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
116
+ /**
117
+ * Tree Helper: Update split percentage recursively.
118
+ */
119
+ declare function updateSplitPercentage(tree: TreeNode | null, target: SplitNode, newPercentage: number): TreeNode | null;
120
+
121
+ export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, updateSplitPercentage, useDashboard, useResizer };
package/dist/index.d.ts CHANGED
@@ -30,12 +30,11 @@ interface DashboardContextValue {
30
30
  classNames: ZeugmaClassNames;
31
31
  onRemove?: (paneId: string) => void;
32
32
  onFullscreenChange?: (paneId: string | null) => void;
33
+ snapThreshold?: number;
33
34
  }
35
+
34
36
  declare const useDashboard: () => DashboardContextValue;
35
- declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
36
- declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
37
- declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
38
- declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
37
+
39
38
  interface DashboardProviderProps {
40
39
  layout: TreeNode | null;
41
40
  onChange: (newLayout: TreeNode | null) => void;
@@ -46,14 +45,30 @@ interface DashboardProviderProps {
46
45
  onFullscreenChange?: (paneId: string | null) => void;
47
46
  onRemove?: (paneId: string) => void;
48
47
  dragActivationDistance?: number;
48
+ snapThreshold?: number;
49
49
  children: ReactNode;
50
50
  }
51
51
  declare const DashboardProvider: React.FC<DashboardProviderProps>;
52
52
 
53
+ interface UseResizerProps {
54
+ containerRef: React.RefObject<HTMLDivElement | null>;
55
+ isRow: boolean;
56
+ direction: SplitDirection;
57
+ splitPercentage: number;
58
+ resizerSize: number;
59
+ snapThreshold: number;
60
+ layout: TreeNode | null;
61
+ currentNode: SplitNode;
62
+ onLayoutChange: (newLayout: TreeNode | null) => void;
63
+ }
64
+ declare function useResizer({ containerRef, isRow, direction, splitPercentage, resizerSize, snapThreshold, layout, currentNode, onLayoutChange, }: UseResizerProps): (e: React.PointerEvent<HTMLDivElement>) => void;
65
+
53
66
  interface PaneTreeProps {
54
67
  tree?: TreeNode | null;
55
68
  /** Size of the resizer in pixels (default 4) */
56
69
  resizerSize?: number;
70
+ /** Threshold in pixels to snap to adjacent resizer edges (default 8) */
71
+ snapThreshold?: number;
57
72
  }
58
73
  declare const PaneTree: React.FC<PaneTreeProps>;
59
74
 
@@ -63,15 +78,14 @@ interface PaneRenderProps {
63
78
  toggleFullscreen: () => void;
64
79
  remove: () => void;
65
80
  }
81
+
66
82
  interface PaneProps {
67
83
  id: string;
68
84
  children: (props: PaneRenderProps) => React.ReactNode;
69
85
  style?: React.CSSProperties;
70
86
  }
71
87
  declare const Pane: React.FC<PaneProps>;
72
- /**
73
- * Place inside a Pane to make an element the drag handle.
74
- */
88
+
75
89
  interface DragHandleProps {
76
90
  children: React.ReactNode;
77
91
  className?: string;
@@ -79,4 +93,29 @@ interface DragHandleProps {
79
93
  }
80
94
  declare const DragHandle: React.FC<DragHandleProps>;
81
95
 
82
- export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, useDashboard };
96
+ declare const DEFAULT_SNAP_THRESHOLD = 8;
97
+ declare const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8;
98
+ declare const DEFAULT_RESIZER_SIZE = 4;
99
+
100
+ /**
101
+ * Tree Helper: Remove a pane and consolidate the tree structure.
102
+ */
103
+ declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
104
+ /**
105
+ * Tree Helper: Insert a pane by splitting an existing target node.
106
+ */
107
+ declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
108
+ /**
109
+ * Tree Helper: Swap the position of two panes in the tree structure.
110
+ */
111
+ declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
112
+ /**
113
+ * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.
114
+ */
115
+ declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
116
+ /**
117
+ * Tree Helper: Update split percentage recursively.
118
+ */
119
+ declare function updateSplitPercentage(tree: TreeNode | null, target: SplitNode, newPercentage: number): TreeNode | null;
120
+
121
+ export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, updateSplitPercentage, useDashboard, useResizer };
package/dist/index.js CHANGED
@@ -1,2 +1,7 @@
1
- import {createContext,useContext,useState,useRef,useEffect}from'react';import {useSensors,useSensor,PointerSensor,DndContext,pointerWithin,useDraggable,useDroppable}from'@dnd-kit/core';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var O=createContext(void 0),I=()=>{let e=useContext(O);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function S(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=S(e.first,t),o=S(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function C(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},c={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:c,second:s?c:i,splitPercentage:50}}return e}return {...e,first:C(e.first,t,n,o,r)||e.first,second:C(e.second,t,n,o,r)||e.second}}function E(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:E(e.first,t,n)||e.first,second:E(e.second,t,n)||e.second}}function B(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}var j=({activeId:e,render:t,className:n})=>{let o=useRef(null);return useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},A=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:c,onRemove:s,dragActivationDistance:a=8,children:x})=>{let[g,h]=useState(null),p=useSensors(useSensor(PointerSensor,{activationConstraint:{distance:a}})),l=d=>{h(d.active.id.toString());},f=d=>{h(null);let{active:u,over:N}=d;if(!N)return;let v=u.id.toString(),y=N.id.toString(),R=y.match(/^drop-center-(.+)$/);if(R){let[,M]=R;v!==M&&t(E(e,v,M));return}let D=y.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!D)return;let[,P,w]=D;if(v===w)return;let z=P==="left"||P==="right"?"row":"column",L=S(e,v),T=C(L,w,z,P,v);t(T);};return jsxs(O.Provider,{value:{layout:e,onLayoutChange:t,renderPane:n,activeId:g,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:c},children:[jsx(DndContext,{sensors:p,collisionDetection:pointerWithin,onDragStart:l,onDragEnd:f,children:x}),g&&o&&jsx(j,{activeId:g,render:o,className:r.dragOverlay})]})};function $(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:$(e.first,t,n)||e.first,second:$(e.second,t,n)||e.second}:e}var Z=({tree:e,resizerSize:t=4})=>{let{layout:n,onLayoutChange:o,renderPane:r,fullscreenPaneId:i,classNames:c}=I(),s=useRef(null);if(i&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let a=e!==void 0?e:n;if(!a)return null;if(a.type==="pane")return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(a.paneId)});let{direction:x,first:g,second:h,splitPercentage:p}=a,l=x==="row",f=d=>{d.preventDefault();let u=s.current;if(!u)return;document.body.classList.add("zeugma-resizing");let N=u.getBoundingClientRect(),v=d.clientX,y=d.clientY,R=p,D=w=>{let z=l?(w.clientX-v)/N.width*100:(w.clientY-y)/N.height*100,L=Math.max(5,Math.min(95,R+z)),T=$(n,a,L);o(T);},P=()=>{document.body.classList.remove("zeugma-resizing"),document.removeEventListener("pointermove",D),document.removeEventListener("pointerup",P);};document.addEventListener("pointermove",D),document.addEventListener("pointerup",P);};return jsxs("div",{ref:s,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${p} 1 0%`,overflow:"hidden"},children:jsx(Z,{tree:g,resizerSize:t})}),jsx("div",{className:c.resizer,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:f,role:"separator","aria-valuenow":p,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-p} 1 0%`,overflow:"hidden"},children:jsx(Z,{tree:h,resizerSize:t})})]})};var Y=createContext(null),ae={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"}},le={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"}},X=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:o,style:ae[t]}),r&&jsx("div",{className:n,style:le[t]})]})},de=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:c,onFullscreenChange:s}=I(),a=o!==null&&o!==e,{attributes:x,listeners:g,setNodeRef:h,isDragging:p}=useDraggable({id:e}),l=o===e||p,f=i===e,d={isDragging:l,isFullscreen:f,toggleFullscreen:()=>s?.(f?null:e),remove:()=>{f&&s?.(null),c?.(e);}};return jsx(Y.Provider,{value:{...g,...x},children:jsxs("div",{ref:h,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(d),a&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(u=>jsx(X,{id:`drop-${u}-${e}`,position:u,activeClassName:r.dropPreview},u)),jsx(X,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})},ce=({children:e,className:t,style:n})=>{let o=useContext(Y);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};export{A as DashboardProvider,ce as DragHandle,de as Pane,Z as PaneTree,B as addPane,S as removePane,C as splitPane,E as swapPanes,I as useDashboard};//# sourceMappingURL=index.js.map
1
+ import {createContext,useContext,useState,useMemo,useCallback,useRef,useEffect}from'react';import {useSensors,useSensor,PointerSensor,DndContext,pointerWithin,useDraggable,useDroppable}from'@dnd-kit/core';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var L=createContext(void 0);var N=()=>{let e=useContext(L);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function z(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=z(e.first,t),o=z(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function F(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},d={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:d,second:s?d:i,splitPercentage:50}}return e}return {...e,first:F(e.first,t,n,o,r)||e.first,second:F(e.second,t,n,o,r)||e.second}}function A(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:A(e.first,t,n)||e.first,second:A(e.second,t,n)||e.second}}function we(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}function H(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:H(e.first,t,n)||e.first,second:H(e.second,t,n)||e.second}:e}var q=8,B=8,Le=4;var ie=({activeId:e,render:t,className:n})=>{let o=useRef(null);return useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},se=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:d,onRemove:s,dragActivationDistance:c=8,snapThreshold:u=8,children:m})=>{let[l,a]=useState(null),R=useSensors(useSensor(PointerSensor,{activationConstraint:{distance:c}})),b=g=>{a(g.active.id.toString());},S=g=>{a(null);let{active:Z,over:y}=g;if(!y)return;let h=Z.id.toString(),p=y.id.toString(),f=p.match(/^drop-center-(.+)$/);if(f){let[,T]=f;h!==T&&t(A(e,h,T));return}let x=p.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!x)return;let[,I,E]=x;if(h===E)return;let D=I==="left"||I==="right"?"row":"column",w=z(e,h),_=F(w,E,D,I,h);t(_);},P=useMemo(()=>({layout:e,onLayoutChange:t,renderPane:n,activeId:l,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:d,snapThreshold:u}),[e,t,n,l,i,r,s,d,u]);return jsxs(L.Provider,{value:P,children:[jsx(DndContext,{sensors:R,collisionDetection:pointerWithin,onDragStart:b,onDragEnd:S,children:m}),l&&o&&jsx(ie,{activeId:l,render:o,className:r.dragOverlay})]})};function U({containerRef:e,isRow:t,direction:n,splitPercentage:o,resizerSize:r,snapThreshold:i,layout:d,currentNode:s,onLayoutChange:c}){return useCallback(u=>{u.preventDefault();let m=e.current;if(!m)return;document.body.classList.add("zeugma-resizing");let l=document.createElement("style");l.id="zeugma-global-cursor-style",l.textContent=`
2
+ * {
3
+ cursor: ${t?"col-resize":"row-resize"} !important;
4
+ user-select: none !important;
5
+ }
6
+ `,document.head.appendChild(l);let a=m.getBoundingClientRect(),R=u.clientX,b=u.clientY,S=o,P=u.currentTarget;P.setAttribute("data-resizing","true");let Z=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(p=>p!==P&&p.getAttribute("data-direction")===n).map(p=>{let f=p.getBoundingClientRect();return t?f.left+f.width/2:f.top+f.height/2}),y=p=>{let f=t?(p.clientX-R)/a.width*100:(p.clientY-b)/a.height*100,x=S+f,I=t?a.left+(a.width-r)*(x/100)+r/2:a.top+(a.height-r)*(x/100)+r/2,E=1/0,D=null;for(let X of Z){let $=Math.abs(I-X);$<i&&$<E&&(E=$,D=X);}let w=x;D!==null&&(w=t?(D-r/2-a.left)/(a.width-r)*100:(D-r/2-a.top)/(a.height-r)*100);let _=Math.max(5,Math.min(95,w)),T=H(d,s,_);c(T);},h=()=>{document.body.classList.remove("zeugma-resizing"),P.removeAttribute("data-resizing");let p=document.getElementById("zeugma-global-cursor-style");p&&p.remove(),document.removeEventListener("pointermove",y),document.removeEventListener("pointerup",h);};document.addEventListener("pointermove",y),document.addEventListener("pointerup",h);},[e,t,n,o,r,i,d,s,c])}var ce=({currentNode:e,resizerSize:t,snapThreshold:n})=>{let{layout:o,onLayoutChange:r,classNames:i}=N(),d=useRef(null),{direction:s,first:c,second:u,splitPercentage:m}=e,l=s==="row",a=U({containerRef:d,isRow:l,direction:s,splitPercentage:m,resizerSize:t,snapThreshold:n??8,layout:o,currentNode:e,onLayoutChange:r});return jsxs("div",{ref:d,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${m} 1 0%`,overflow:"hidden"},children:jsx(V,{tree:c,resizerSize:t,snapThreshold:n})}),jsx("div",{className:i.resizer,"data-direction":s,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:a,role:"separator","aria-valuenow":m,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-m} 1 0%`,overflow:"hidden"},children:jsx(V,{tree:u,resizerSize:t,snapThreshold:n})})]})},V=({tree:e,resizerSize:t=4,snapThreshold:n})=>{let{layout:o,renderPane:r,fullscreenPaneId:i,snapThreshold:d}=N(),s=n!==void 0?n:d;if(i&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let c=e!==void 0?e:o;return c?c.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(c.paneId)}):jsx(ce,{currentNode:c,resizerSize:t,snapThreshold:s}):null};var M=createContext(null);var he={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"}},ve={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"}},Y=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:o,style:he[t]}),r&&jsx("div",{className:n,style:ve[t]})]})},be=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:d,onFullscreenChange:s}=N(),c=o!==null&&o!==e,{attributes:u,listeners:m,setNodeRef:l,isDragging:a}=useDraggable({id:e}),R=o===e||a,b=i===e,S={isDragging:R,isFullscreen:b,toggleFullscreen:()=>s?.(b?null:e),remove:()=>{b&&s?.(null),d?.(e);}},P=useMemo(()=>({...m,...u}),[m,u]);return jsx(M.Provider,{value:P,children:jsxs("div",{ref:l,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(S),c&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(g=>jsx(Y,{id:`drop-${g}-${e}`,position:g,activeClassName:r.dropPreview},g)),jsx(Y,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})};var De=({children:e,className:t,style:n})=>{let o=useContext(M);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};export{B as DEFAULT_DRAG_ACTIVATION_DISTANCE,Le as DEFAULT_RESIZER_SIZE,q as DEFAULT_SNAP_THRESHOLD,se as DashboardProvider,De as DragHandle,be as Pane,V as PaneTree,we as addPane,z as removePane,F as splitPane,A as swapPanes,H as updateSplitPercentage,N as useDashboard,U as useResizer};//# sourceMappingURL=index.js.map
2
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } 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, PaneNode } from '../types'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\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}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\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\n// Tree Helper: Remove a pane and consolidate the tree\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// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : 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// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\n}\n\n// Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree\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/** 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 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 = 8,\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 setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\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 return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\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 draggingId,\n )\n onChange(newLayout)\n }\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext\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, { useRef } from 'react'\nimport { useDashboard } from './dashboard-provider'\nimport { TreeNode, SplitNode } from '../types'\n\ninterface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n}\n\nfunction 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\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard()\n const containerRef = useRef<HTMLDivElement>(null)\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 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 const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\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 newPercentage = Math.max(5, Math.min(95, startPercentage + delta))\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage)\n onLayoutChange(newLayout)\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\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 tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\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 <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n )\n}\n","import React, { createContext, useContext } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from './dashboard-provider'\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null)\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\nexport interface PaneRenderProps {\n isDragging: boolean\n isFullscreen: boolean\n toggleFullscreen: () => void\n remove: () => void\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 { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = 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 renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\n },\n }\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\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\n/**\n * Place inside a Pane to make an element the drag handle.\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/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","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","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","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","contextValue","useMemo","jsxs","DndContext","pointerWithin","useResizer","containerRef","isRow","splitPercentage","resizerSize","currentNode","onLayoutChange","useCallback","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","pos","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode } 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 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}\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,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : 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 if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\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","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 } 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 } from '../../../shared/model'\nimport { removePane, splitPane, swapPanes } from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames } 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 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 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 setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\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 return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\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 draggingId,\n )\n onChange(newLayout)\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 }),\n [\n layout,\n onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\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, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\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}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n}: UseResizerProps) {\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 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 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(5, Math.min(95, snappedPercentage))\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\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\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 ],\n )\n}\n","import React, { useRef } from 'react'\nimport { useDashboard } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\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}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({ currentNode, resizerSize, snapThreshold }) => {\n const { layout, onLayoutChange, classNames } = useDashboard()\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 })\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 tree={first} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n </div>\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 <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n}) => {\n const {\n layout,\n renderPane,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\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 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 currentNode={currentNode} resizerSize={resizerSize} snapThreshold={snapThreshold} />\n )\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'\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 { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = 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 renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\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.2.0",
3
+ "version": "0.3.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,
@@ -28,7 +28,7 @@
28
28
  "bugs": {
29
29
  "url": "https://github.com/yusufarsln98/react-zeugma/issues"
30
30
  },
31
- "homepage": "https://github.com/yusufarsln98/react-zeugma#readme",
31
+ "homepage": "https://react-zeugma.vercel.app",
32
32
  "publishConfig": {
33
33
  "access": "public",
34
34
  "registry": "https://registry.npmjs.org/"
@@ -56,8 +56,6 @@
56
56
  "typecheck": "tsc --noEmit",
57
57
  "format": "prettier --write \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
58
58
  "format:check": "prettier --check \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
59
- "demo": "npm run dev --workspace=homepage",
60
- "build:demo": "npm run build && npm run build --workspace=homepage",
61
59
  "storybook": "storybook dev -p 6006",
62
60
  "build:storybook": "storybook build -o storybook-static",
63
61
  "prepare": "husky",
@@ -68,10 +66,6 @@
68
66
  "react": "^18.0.0 || ^19.0.0",
69
67
  "react-dom": "^18.0.0 || ^19.0.0"
70
68
  },
71
- "workspaces": [
72
- ".",
73
- "homepage"
74
- ],
75
69
  "dependencies": {
76
70
  "@dnd-kit/core": "^6.3.1",
77
71
  "@dnd-kit/sortable": "^10.0.0",