react-zeugma 0.8.1 → 1.0.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
@@ -262,7 +262,7 @@ export interface ResizerRenderProps {
262
262
  onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void
263
263
  }
264
264
 
265
- export interface DashboardContextValue {
265
+ export interface DashboardStateValue {
266
266
  layout: TreeNode | null
267
267
  onLayoutChange: (newLayout: TreeNode | null) => void
268
268
  renderPane: (paneId: string) => ReactNode
@@ -278,6 +278,9 @@ export interface DashboardContextValue {
278
278
  renderResizer?: (props: ResizerRenderProps) => ReactNode
279
279
  minSplitPercentage?: number
280
280
  maxSplitPercentage?: number
281
+ }
282
+
283
+ export interface DashboardActionsValue {
281
284
  removePane: (paneId: string) => void
282
285
  addPane: (paneId: string) => void
283
286
  swapPanes: (paneIdA: string, paneIdB: string) => void
@@ -293,6 +296,8 @@ export interface DashboardContextValue {
293
296
  updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
294
297
  ) => void
295
298
  }
299
+
300
+ export type DashboardContextValue = DashboardStateValue & DashboardActionsValue
296
301
  ```
297
302
 
298
303
  ---
@@ -432,7 +437,13 @@ Import these helpers from `react-zeugma` to manipulate the tree layout programma
432
437
  - **`findPane(tree: TreeNode | null, paneId: string): PaneNode | null`**
433
438
  Recursively searches the layout tree and returns the target `PaneNode` if found, or `null` otherwise.
434
439
 
435
- Alternatively, you can consume the convenient mutation helpers directly from the **`useDashboard()`** context hook inside pane components without importing utilities:
440
+ Alternatively, you can consume state and mutation helpers directly from the context hooks:
441
+
442
+ - **`useDashboardState()`**: Returns the reactive state values (e.g., `layout`, `activeId`, `classNames`). Consumers of this hook will re-render whenever layout state updates.
443
+ - **`useDashboardActions()`**: Returns the stable layout mutation actions (e.g., `removePane`, `splitPane`). Because these actions have a permanent identity, consumers of this hook **will not** re-render when layout state changes, providing a significant performance optimization.
444
+ - **`useDashboard()`**: Returns both state and actions (backward compatible; equivalent to the union of both).
445
+
446
+ The actions returned by `useDashboardActions()` (or the combined `useDashboard()`) are:
436
447
 
437
448
  - **`removePane(paneId: string) => void`**
438
449
  - **`addPane(paneId: string) => void`**
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
- 'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var j=react.createContext(void 0);var C=()=>{let e=react.useContext(j);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function I(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=I(e.first,t),o=I(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function X(e,t,n,o,r){if(e===null)return typeof r=="string"?{type:"pane",paneId:r}:r;if(e.type==="pane"){if(e.paneId===t){let s=typeof r=="string"?{type:"pane",paneId:r}:r,a=o==="left"||o==="top";return {type:"split",direction:n,first:a?s:e,second:a?e:s,splitPercentage:50}}return e}return {...e,first:X(e.first,t,n,o,r)||e.first,second:X(e.second,t,n,o,r)||e.second}}function se(e,t,n){if(e===null)return null;let o=y(e,t),r=y(e,n);if(!o||!r)return e;function s(a){return a.type==="pane"?a.paneId===t?{...r}:a.paneId===n?{...o}:a:{...a,first:s(a.first),second:s(a.second)}}return s(e)}function ve(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 Z(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:Z(e.first,t,n)||e.first,second:Z(e.second,t,n)||e.second}:e}function he(e,t,n){let o=y(e,t)??{type:"pane",paneId:t},r=I(e,t);if(r===null)return {...o};let s=n==="left"||n==="right"?"row":"column",a=n==="left"||n==="top",f={...o};return {type:"split",direction:s,first:a?f:r,second:a?r:f,splitPercentage:50}}function y(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:y(e.first,t)??y(e.second,t)}function ee(e,t,n){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let o=n(e.metadata);if(o===void 0){let{metadata:r,...s}=e;return s}return {...e,metadata:o}}return e}return {...e,first:ee(e.first,t,n)??e.first,second:ee(e.second,t,n)??e.second}}var ye=8,ze=8,mt=4;var Ae=({activeId:e,render:t,className:n})=>{let o=react.useRef(null);return react.useEffect(()=>{let r=s=>{o.current&&(o.current.style.transform=`translate(${s.clientX+12}px, ${s.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)})},de=class extends core.PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},He=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:s=null,onFullscreenChange:a,onRemove:f,dragActivationDistance:x=8,snapThreshold:P=8,onDragStart:b,onDragEnd:l,onResizeStart:u,onResize:h,onResizeEnd:D,renderResizer:R,minSplitPercentage:v=5,maxSplitPercentage:S=95,children:A})=>{let[i,g]=react.useState(e),[$,w]=react.useState(e);e!==$&&(g(e),w(e));let[T,ne]=react.useState(null),re=core.useSensors(core.useSensor(de,{activationConstraint:{distance:x}})),G=p=>{let d=p.active.id.toString();ne(d),b&&b(d);},q=p=>{ne(null);let{active:d,over:c}=p,m=d.id.toString();if(!c){l&&l(m,null,null);return}let V=c.id.toString(),K=V.match(/^drop-root-(left|right|top|bottom)$/);if(K){let[,L]=K,W=he(i,m,L);g(W),t(W),l&&l(m,"root",{type:"split",direction:L==="left"||L==="right"?"row":"column",position:L});return}let B=V.match(/^drop-center-(.+)$/);if(B){let[,L]=B;if(m!==L){let W=se(i,m,L);g(W),t(W);}l&&l(m,L,{type:"swap",position:"center"});return}let fe=V.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!fe){l&&l(m,null,null);return}let[,Q,ie]=fe;if(m===ie){l&&l(m,null,null);return}let me=Q==="left"||Q==="right"?"row":"column",xe=y(i,m)??{type:"pane",paneId:m},Se=I(i,m),ge=X(Se,ie,me,Q,xe);g(ge),t(ge),l&&l(m,ie,{type:"split",direction:me,position:Q});},_=react.useCallback(p=>{g(p);},[]),N=react.useCallback(p=>{let d=I(i,p);g(d),t(d);},[i,t]),z=react.useCallback(p=>{let d=ve(i,p);g(d),t(d);},[i,t]),H=react.useCallback((p,d)=>{let c=se(i,p,d);g(c),t(c);},[i,t]),J=react.useCallback((p,d,c,m)=>{let V=y(i,m)??{type:"pane",paneId:m},K=I(i,m),B=X(K,p,d,c,V);g(B),t(B);},[i,t]),k=react.useCallback((p,d)=>{let c=Z(i,p,d);g(c),t(c);},[i,t]),F=react.useCallback((p,d)=>{let c=ee(i,p,d);g(c),t(c);},[i,t]),O=react.useCallback((p,d)=>{let c=Z(i,p,d);g(c),t(c),D&&D(p,d);},[i,t,D]),U=react.useMemo(()=>({layout:i,onLayoutChange:_,renderPane:n,activeId:T,fullscreenPaneId:s,classNames:r,onRemove:f,onFullscreenChange:a,snapThreshold:P,onResizeStart:u,onResize:h,onResizeEnd:O,renderResizer:R,minSplitPercentage:v,maxSplitPercentage:S,removePane:N,addPane:z,swapPanes:H,splitPane:J,updateSplitPercentage:k,updatePaneMetadata:F}),[i,_,n,T,s,r,f,a,P,u,h,O,R,v,S,N,z,H,J,k,F]);return jsxRuntime.jsxs(j.Provider,{value:U,children:[jsxRuntime.jsx(core.DndContext,{id:"zeugma-dnd-context",sensors:re,collisionDetection:core.pointerWithin,onDragStart:G,onDragEnd:q,children:A}),T&&o&&jsxRuntime.jsx(Ae,{activeId:T,render:o,className:r.dragOverlay})]})};var ke={top:{position:"absolute",top:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"32px",zIndex:30,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"32px",zIndex:30,pointerEvents:"auto"}},Oe={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"}},Ue=({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:ke[t]}),r&&jsxRuntime.jsx("div",{className:n,style:Oe[t]})]})},Pe=({activeId:e,hasOtherPanes:t,dropPreviewClassName:n})=>!e||!t?null:jsxRuntime.jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:30,pointerEvents:"none"},children:["top","bottom","left","right"].map(o=>jsxRuntime.jsx(Ue,{id:`drop-root-${o}`,position:o,activeClassName:n},o))});function pe({containerRef:e,isRow:t,direction:n,splitPercentage:o,resizerSize:r,snapThreshold:s,layout:a,currentNode:f,onLayoutChange:x,onResizeStart:P,onResizeEnd:b}){let{onResizeStart:l,onResize:u,onResizeEnd:h,minSplitPercentage:D=5,maxSplitPercentage:R=95}=C();return react.useCallback(v=>{v.preventDefault();let S=e.current;if(!S)return;document.body.classList.add("zeugma-resizing");let A=document.createElement("style");A.id="zeugma-global-cursor-style",A.textContent=`
1
+ 'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var ie=react.createContext(void 0),se=react.createContext(void 0);var M=()=>{let e=react.useContext(ie);if(!e)throw new Error("useDashboardState must be used within a DashboardProvider");return e},fe=()=>{let e=react.useContext(se);if(!e)throw new Error("useDashboardActions must be used within a DashboardProvider");return e};function E(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let r=E(e.first,t),n=E(e.second,t);return r===null?n:n===null?r:{...e,first:r,second:n}}function te(e,t,r,n,o){if(e===null)return typeof o=="string"?{type:"pane",paneId:o}:o;if(e.type==="pane"){if(e.paneId===t){let i=typeof o=="string"?{type:"pane",paneId:o}:o,s=n==="left"||n==="top";return {type:"split",direction:r,first:s?i:e,second:s?e:i,splitPercentage:50}}return e}return {...e,first:te(e.first,t,r,n,o)||e.first,second:te(e.second,t,r,n,o)||e.second}}function ge(e,t,r){if(e===null)return null;let n=I(e,t),o=I(e,r);if(!n||!o)return e;function i(s){return s.type==="pane"?s.paneId===t?{...o}:s.paneId===r?{...n}:s:{...s,first:i(s.first),second:i(s.second)}}return i(e)}function ye(e,t){if(e===null)return {type:"pane",paneId:t};function r(n,o){return n.type==="pane"?{type:"split",direction:o==="row"?"column":"row",splitPercentage:50,first:n,second:{type:"pane",paneId:t}}:{...n,second:r(n.second,n.direction)}}return r(e,null)}function $(e,t,r){return e===null?null:e===t?{...e,splitPercentage:r}:e.type==="split"?{...e,first:$(e.first,t,r)||e.first,second:$(e.second,t,r)||e.second}:e}function ze(e,t,r){let n=I(e,t)??{type:"pane",paneId:t},o=E(e,t);if(o===null)return {...n};let i=r==="left"||r==="right"?"row":"column",s=r==="left"||r==="top",p={...n};return {type:"split",direction:i,first:s?p:o,second:s?o:p,splitPercentage:50}}function I(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:I(e.first,t)??I(e.second,t)}function ae(e,t,r){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let n=r(e.metadata);if(n===void 0){let{metadata:o,...i}=e;return i}return {...e,metadata:n}}return e}return {...e,first:ae(e.first,t,r)??e.first,second:ae(e.second,t,r)??e.second}}var Ze=8,He=8,Dt=4;var Be=({activeId:e,render:t,className:r})=>{let n=react.useRef(null);return react.useEffect(()=>{let o=i=>{n.current&&(n.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",o),()=>document.removeEventListener("pointermove",o)},[]),jsxRuntime.jsx("div",{ref:n,className:r,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},he=class extends core.PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},We=({layout:e,onChange:t,renderPane:r,renderDragOverlay:n,classNames:o={},fullscreenPaneId:i=null,onFullscreenChange:s,onRemove:p,dragActivationDistance:x=8,snapThreshold:b=8,onDragStart:P,onDragEnd:a,onResizeStart:u,onResize:R,onResizeEnd:C,renderResizer:N,minSplitPercentage:g=5,maxSplitPercentage:m=95,children:V})=>{let[d,h]=react.useState(e),O=react.useRef(e);e!==O.current&&(O.current=e,h(e));let[S,_]=react.useState(null),w=react.useRef(d);w.current=d;let y=react.useRef(t);y.current=t;let F=react.useRef(r);F.current=r;let k=react.useRef(C);k.current=C;let W=react.useCallback(l=>F.current(l),[]),D=react.useMemo(()=>o,[o.pane,o.dropPreview,o.swapPreview,o.dragOverlay,o.resizer]),z=core.useSensors(core.useSensor(he,{activationConstraint:{distance:x}})),X=l=>{let c=l.active.id.toString();_(c),P&&P(c);},pe=l=>{_(null);let{active:c,over:v}=l,f=c.id.toString();if(!v){a&&a(f,null,null);return}let Q=v.id.toString(),oe=Q.match(/^drop-root-(left|right|top|bottom)$/);if(oe){let[,A]=oe,ee=ze(d,f,A);h(ee),t(ee),a&&a(f,"root",{type:"split",direction:A==="left"||A==="right"?"row":"column",position:A});return}let j=Q.match(/^drop-center-(.+)$/);if(j){let[,A]=j;if(f!==A){let ee=ge(d,f,A);h(ee),t(ee);}a&&a(f,A,{type:"swap",position:"center"});return}let xe=Q.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!xe){a&&a(f,null,null);return}let[,re,ue]=xe;if(f===ue){a&&a(f,null,null);return}let Ne=re==="left"||re==="right"?"row":"column",Me=I(d,f)??{type:"pane",paneId:f},Fe=E(d,f),Se=te(Fe,ue,Ne,re,Me);h(Se),t(Se),a&&a(f,ue,{type:"split",direction:Ne,position:re});},Y=react.useCallback(l=>{h(l);},[]),Z=react.useCallback(l=>{let c=E(w.current,l);h(c),y.current(c);},[]),G=react.useCallback(l=>{let c=ye(w.current,l);h(c),y.current(c);},[]),H=react.useCallback((l,c)=>{let v=ge(w.current,l,c);h(v),y.current(v);},[]),q=react.useCallback((l,c,v,f)=>{let Q=I(w.current,f)??{type:"pane",paneId:f},oe=E(w.current,f),j=te(oe,l,c,v,Q);h(j),y.current(j);},[]),J=react.useCallback((l,c)=>{let v=$(w.current,l,c);h(v),y.current(v);},[]),K=react.useCallback((l,c)=>{let v=ae(w.current,l,c);h(v),y.current(v);},[]),U=react.useCallback((l,c)=>{let v=$(w.current,l,c);h(v),y.current(v),k.current&&k.current(l,c);},[]),Le=react.useMemo(()=>({layout:d,onLayoutChange:Y,renderPane:W,activeId:S,fullscreenPaneId:i,classNames:D,onRemove:p,onFullscreenChange:s,snapThreshold:b,onResizeStart:u,onResize:R,onResizeEnd:U,renderResizer:N,minSplitPercentage:g,maxSplitPercentage:m}),[d,S,i,D,p,s,b,u,R,N,g,m,Y,W,U]),Ae=react.useMemo(()=>({removePane:Z,addPane:G,swapPanes:H,splitPane:q,updateSplitPercentage:J,updatePaneMetadata:K}),[Z,G,H,q,J,K]);return jsxRuntime.jsx(se.Provider,{value:Ae,children:jsxRuntime.jsxs(ie.Provider,{value:Le,children:[jsxRuntime.jsx(core.DndContext,{id:"zeugma-dnd-context",sensors:z,collisionDetection:core.pointerWithin,onDragStart:X,onDragEnd:pe,children:V}),S&&n&&jsxRuntime.jsx(Be,{activeId:S,render:n,className:o.dragOverlay})]})})};var Ge={top:{position:"absolute",top:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"32px",zIndex:30,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"32px",zIndex:30,pointerEvents:"auto"}},qe={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"}},Je=({id:e,position:t,activeClassName:r})=>{let{setNodeRef:n,isOver:o}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:n,style:Ge[t]}),o&&jsxRuntime.jsx("div",{className:r,style:qe[t]})]})},Ce=({activeId:e,hasOtherPanes:t,dropPreviewClassName:r})=>!e||!t?null:jsxRuntime.jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:30,pointerEvents:"none"},children:["top","bottom","left","right"].map(n=>jsxRuntime.jsx(Je,{id:`drop-root-${n}`,position:n,activeClassName:r},n))});function ve({containerRef:e,isRow:t,direction:r,splitPercentage:n,resizerSize:o,snapThreshold:i,layout:s,currentNode:p,onLayoutChange:x,onResizeStart:b,onResizeEnd:P}){let{onResizeStart:a,onResize:u,onResizeEnd:R,minSplitPercentage:C=5,maxSplitPercentage:N=95}=M();return react.useCallback(g=>{g.preventDefault();let m=e.current;if(!m)return;document.body.classList.add("zeugma-resizing");let V=document.createElement("style");V.id="zeugma-global-cursor-style",V.textContent=`
2
2
  * {
3
3
  cursor: ${t?"col-resize":"row-resize"} !important;
4
4
  user-select: none !important;
5
5
  }
6
- `,document.head.appendChild(A),P&&P(),l&&l(f);let i=S.getBoundingClientRect(),g=v.clientX,$=v.clientY,w=o,T=v.currentTarget;T.setAttribute("data-resizing","true");let re=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(N=>N!==T&&N.getAttribute("data-direction")===n).map(N=>{let z=N.getBoundingClientRect();return t?z.left+z.width/2:z.top+z.height/2}),G=w,q=N=>{let z=t?(N.clientX-g)/i.width*100:(N.clientY-$)/i.height*100,H=w+z,J=t?i.left+(i.width-r)*(H/100)+r/2:i.top+(i.height-r)*(H/100)+r/2,k=1/0,F=null;for(let d of re){let c=Math.abs(J-d);c<s&&c<k&&(k=c,F=d);}let O=H;F!==null&&(O=t?(F-r/2-i.left)/(i.width-r)*100:(F-r/2-i.top)/(i.height-r)*100);let U=Math.max(D,Math.min(R,O));G=U;let p=Z(a,f,U);x(p),u&&u(f,U);},_=()=>{document.body.classList.remove("zeugma-resizing"),T.removeAttribute("data-resizing");let N=document.getElementById("zeugma-global-cursor-style");N&&N.remove(),document.removeEventListener("pointermove",q),document.removeEventListener("pointerup",_),b&&b(),h&&h(f,G);};document.addEventListener("pointermove",q),document.addEventListener("pointerup",_);},[e,t,n,o,r,s,a,f,x,P,b,l,u,h,D,R])}var qe=({currentNode:e,resizerSize:t,snapThreshold:n,renderResizer:o})=>{let{layout:r,onLayoutChange:s,classNames:a,renderResizer:f}=C(),[x,P]=react.useState(false),b=o||f,l=react.useRef(null),{direction:u,first:h,second:D,splitPercentage:R}=e,v=u==="row",S=pe({containerRef:l,isRow:v,direction:u,splitPercentage:R,resizerSize:t,snapThreshold:n??8,layout:r,currentNode:e,onLayoutChange:s,onResizeStart:()=>P(true),onResizeEnd:()=>P(false)});return jsxRuntime.jsxs("div",{ref:l,style:{display:"flex",flexDirection:v?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${R} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(ce,{tree:h,resizerSize:t,snapThreshold:n,renderResizer:o})}),b?b({direction:u,splitPercentage:R,resizerSize:t,isResizing:x,onPointerDown:S}):jsxRuntime.jsx("div",{className:a.resizer,"data-direction":u,style:{width:v?`${t}px`:"100%",height:v?"100%":`${t}px`,cursor:v?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:S,role:"separator","aria-valuenow":R,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-R} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(ce,{tree:D,resizerSize:t,snapThreshold:n,renderResizer:o})})]})},ce=({tree:e,resizerSize:t=4,snapThreshold:n,renderResizer:o})=>{let{layout:r,renderPane:s,activeId:a,classNames:f,fullscreenPaneId:x,snapThreshold:P}=C(),b=n!==void 0?n:P,l=react.useMemo(()=>a?I(r,a)!==null:false,[r,a]);if(x&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:s(x)});let u=e!==void 0?e:r;if(!u)return null;let h=()=>u.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:s(u.paneId)}):jsxRuntime.jsx(qe,{currentNode:u,resizerSize:t,snapThreshold:b,renderResizer:o});return e===void 0?jsxRuntime.jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[h(),jsxRuntime.jsx(Pe,{activeId:a,hasOtherPanes:l,dropPreviewClassName:f.dropPreview})]}):h()};var oe=react.createContext(null);var je={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"}},et={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"}},Ne=({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:je[t]}),r&&jsxRuntime.jsx("div",{className:n,style:et[t]})]})},tt=({id:e,children:t,style:n})=>{let{layout:o,activeId:r,classNames:s,fullscreenPaneId:a,onRemove:f,onFullscreenChange:x,removePane:P,updatePaneMetadata:b}=C(),l=r!==null&&r!==e,{attributes:u,listeners:h,setNodeRef:D,isDragging:R}=core.useDraggable({id:e}),v=r===e||R,S=a===e,i=react.useMemo(()=>y(o,e),[o,e])?.metadata,g={isDragging:v,isFullscreen:S,toggleFullscreen:()=>x?.(S?null:e),remove:()=>{S&&x?.(null),f?f(e):P(e);},metadata:i,updateMetadata:w=>{b(e,w);}},$=react.useMemo(()=>({...h,...u}),[h,u]);return jsxRuntime.jsx(oe.Provider,{value:$,children:jsxRuntime.jsxs("div",{ref:D,className:s.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(g),l&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(w=>jsxRuntime.jsx(Ne,{id:`drop-${w}-${e}`,position:w,activeClassName:s.dropPreview},w)),jsxRuntime.jsx(Ne,{id:`drop-center-${e}`,position:"center",activeClassName:s.swapPreview})]})]})})};var rt=({children:e,className:t,style:n})=>{let o=react.useContext(oe);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=ze;exports.DEFAULT_RESIZER_SIZE=mt;exports.DEFAULT_SNAP_THRESHOLD=ye;exports.DashboardProvider=He;exports.DragHandle=rt;exports.Pane=tt;exports.PaneTree=ce;exports.addPane=ve;exports.findPane=y;exports.removePane=I;exports.splitPane=X;exports.splitRoot=he;exports.swapPanes=se;exports.updatePaneMetadata=ee;exports.updateSplitPercentage=Z;exports.useDashboard=C;exports.useResizer=pe;//# sourceMappingURL=index.cjs.map
6
+ `,document.head.appendChild(V),b&&b(),a&&a(p);let d=m.getBoundingClientRect(),h=g.clientX,O=g.clientY,S=n,_=g.currentTarget;_.setAttribute("data-resizing","true");let y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(D=>D!==_&&D.getAttribute("data-direction")===r).map(D=>{let z=D.getBoundingClientRect();return t?z.left+z.width/2:z.top+z.height/2}),F=S,k=D=>{let z=t?(D.clientX-h)/d.width*100:(D.clientY-O)/d.height*100,X=S+z,pe=t?d.left+(d.width-o)*(X/100)+o/2:d.top+(d.height-o)*(X/100)+o/2,Y=1/0,Z=null;for(let K of y){let U=Math.abs(pe-K);U<i&&U<Y&&(Y=U,Z=K);}let G=X;Z!==null&&(G=t?(Z-o/2-d.left)/(d.width-o)*100:(Z-o/2-d.top)/(d.height-o)*100);let H=Math.max(C,Math.min(N,G));F=H;let q=m.children[0],J=m.children[m.children.length-1];q&&J&&(q.style.flex=`${H} 1 0%`,J.style.flex=`${100-H} 1 0%`),u&&u(p,H);},W=()=>{document.body.classList.remove("zeugma-resizing"),_.removeAttribute("data-resizing");let D=document.getElementById("zeugma-global-cursor-style");D&&D.remove(),document.removeEventListener("pointermove",k),document.removeEventListener("pointerup",W);let z=$(s,p,F);console.log("onLayoutChange (finalized) called with percentage:",F),x(z),P&&P(),R&&R(p,F);};document.addEventListener("pointermove",k),document.addEventListener("pointerup",W);},[e,t,r,n,o,i,s,p,x,b,P,a,u,R,C,N])}var ot=({currentNode:e,resizerSize:t,snapThreshold:r,renderResizer:n})=>{let{layout:o,onLayoutChange:i,classNames:s,renderResizer:p}=M(),[x,b]=react.useState(false),P=n||p,a=react.useRef(null),{direction:u,first:R,second:C,splitPercentage:N}=e,g=u==="row",m=ve({containerRef:a,isRow:g,direction:u,splitPercentage:N,resizerSize:t,snapThreshold:r??8,layout:o,currentNode:e,onLayoutChange:i,onResizeStart:()=>b(true),onResizeEnd:()=>b(false)});return jsxRuntime.jsxs("div",{ref:a,style:{display:"flex",flexDirection:g?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${N} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(be,{tree:R,resizerSize:t,snapThreshold:r,renderResizer:n})}),P?P({direction:u,splitPercentage:N,resizerSize:t,isResizing:x,onPointerDown:m}):jsxRuntime.jsx("div",{className:s.resizer,"data-direction":u,style:{width:g?`${t}px`:"100%",height:g?"100%":`${t}px`,cursor:g?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:m,role:"separator","aria-valuenow":N,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-N} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(be,{tree:C,resizerSize:t,snapThreshold:r,renderResizer:n})})]})},be=({tree:e,resizerSize:t=4,snapThreshold:r,renderResizer:n})=>{let{layout:o,renderPane:i,activeId:s,classNames:p,fullscreenPaneId:x,snapThreshold:b}=M(),P=r!==void 0?r:b,a=react.useMemo(()=>e!==void 0||!s?false:E(o,s)!==null,[e,o,s]);if(x&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(x)});let u=e!==void 0?e:o;if(!u)return null;let R=()=>u.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(u.paneId)}):jsxRuntime.jsx(ot,{currentNode:u,resizerSize:t,snapThreshold:P,renderResizer:n});return e===void 0?jsxRuntime.jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[R(),jsxRuntime.jsx(Ce,{activeId:s,hasOtherPanes:a,dropPreviewClassName:p.dropPreview})]}):R()};var ce=react.createContext(null);var at={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:"25%",left:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:"25%",right:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},dt={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"}},Te=({id:e,position:t,activeClassName:r})=>{let{setNodeRef:n,isOver:o}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:n,style:at[t]}),o&&jsxRuntime.jsx("div",{className:r,style:dt[t]})]})},lt=({id:e,children:t,style:r})=>{let{layout:n,activeId:o,classNames:i,fullscreenPaneId:s,onRemove:p,onFullscreenChange:x}=M(),{removePane:b,updatePaneMetadata:P}=fe(),a=o!==null&&o!==e,{attributes:u,listeners:R,setNodeRef:C,isDragging:N}=core.useDraggable({id:e}),g=o===e||N,m=s===e,d=react.useMemo(()=>I(n,e),[n,e])?.metadata,h=react.useMemo(()=>({isDragging:g,isFullscreen:m,toggleFullscreen:()=>x?.(m?null:e),remove:()=>{m&&x?.(null),p?p(e):b(e);},metadata:d,updateMetadata:S=>{P(e,S);}}),[g,m,x,e,p,b,d,P]),O=react.useMemo(()=>({...R,...u}),[R,u]);return jsxRuntime.jsx(ce.Provider,{value:O,children:jsxRuntime.jsxs("div",{ref:C,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...r},children:[t(h),a&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsxRuntime.jsx(Te,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsxRuntime.jsx(Te,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var ut=({children:e,className:t,style:r})=>{let n=react.useContext(ce);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...r},...n,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=He;exports.DEFAULT_RESIZER_SIZE=Dt;exports.DEFAULT_SNAP_THRESHOLD=Ze;exports.DashboardProvider=We;exports.DragHandle=ut;exports.Pane=lt;exports.PaneTree=be;exports.addPane=ye;exports.findPane=I;exports.removePane=E;exports.splitPane=te;exports.splitRoot=ze;exports.swapPanes=ge;exports.updatePaneMetadata=ae;exports.updateSplitPercentage=$;exports.useDashboardActions=fe;exports.useDashboardState=M;exports.useResizer=ve;//# sourceMappingURL=index.cjs.map
7
7
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","SmartPointerSensor","PointerSensor","event","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","localLayout","setLocalLayout","useState","prevLayout","setPrevLayout","setActiveId","sensors","useSensors","useSensor","handleDragStart","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleLocalLayoutChange","useCallback","handleRemovePane","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","handleResizeEnd","finalLayout","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\nclass SmartPointerSensor extends PointerSensor {\n static activators = [\n {\n eventName: 'onPointerDown' as const,\n handler: ({ nativeEvent: event }: { nativeEvent: PointerEvent }) => {\n const element = event.target as HTMLElement | null\n if (element?.closest('.drag-cancel')) {\n return false\n }\n return true\n },\n },\n ]\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [localLayout, setLocalLayout] = useState<TreeNode | null>(layout)\n const [prevLayout, setPrevLayout] = useState<TreeNode | null>(layout)\n\n if (layout !== prevLayout) {\n setLocalLayout(layout)\n setPrevLayout(layout)\n }\n\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(SmartPointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n localLayout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n const newLayout = swapPanes(localLayout, draggingId, targetId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(localLayout, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(localLayout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleLocalLayoutChange = useCallback((newLayout: TreeNode | null) => {\n setLocalLayout(newLayout)\n }, [])\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(localLayout, paneId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(localLayout, paneId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(localLayout, paneIdA, paneIdB)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(localLayout, paneToAdd) ?? {\n type: 'pane',\n paneId: paneToAdd,\n }\n const treeWithoutDragging = removePane(localLayout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(localLayout, currentNode, percentage)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(localLayout, paneId, updater)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleResizeEnd = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const finalLayout = updateSplitPercentage(localLayout, currentNode, percentage)\n setLocalLayout(finalLayout)\n onChange(finalLayout)\n if (onResizeEnd) {\n onResizeEnd(currentNode, percentage)\n }\n },\n [localLayout, onChange, onResizeEnd],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout: localLayout,\n onLayoutChange: handleLocalLayoutChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd: handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n localLayout,\n handleLocalLayoutChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardStateContext","createContext","DashboardActionsContext","useDashboardState","state","useContext","useDashboardActions","actions","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","SmartPointerSensor","PointerSensor","event","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","localLayout","setLocalLayout","useState","prevLayoutRef","setActiveId","layoutRef","onChangeRef","renderPaneRef","onResizeEndPropRef","stableRenderPane","useCallback","stableClassNames","useMemo","sensors","useSensors","useSensor","handleDragStart","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleLocalLayoutChange","handleRemovePane","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","handleResizeEnd","finalLayout","stateValue","actionsValue","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","firstChild","secondChild","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","contextValue","DragHandle","dragProps"],"mappings":"8GA6DO,IAAMA,GAAwBC,mBAAAA,CAA+C,MAAS,CAAA,CAChFC,EAAAA,CAA0BD,mBAAAA,CAAiD,MAAS,ECrD1F,IAAME,CAAAA,CAAoB,IAA2B,CAC1D,IAAMC,CAAAA,CAAQC,gBAAAA,CAAWL,EAAqB,CAAA,CAC9C,GAAI,CAACI,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,2DAA2D,EAE7E,OAAOA,CACT,CAAA,CAGaE,EAAAA,CAAsB,IAA6B,CAC9D,IAAMC,CAAAA,CAAUF,gBAAAA,CAAWH,EAAuB,CAAA,CAClD,GAAI,CAACK,EACH,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA,CAE/E,OAAOA,CACT,ECnBO,SAASC,EAAWC,CAAAA,CAAuBC,CAAAA,CAAqC,CACrF,GAAID,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,CAAAA,CAAK,IAAA,GAAS,MAAA,CAChB,OAAOA,EAAK,MAAA,GAAWC,CAAAA,CAAa,IAAA,CAAOD,CAAAA,CAE7C,IAAME,CAAAA,CAAWH,EAAWC,CAAAA,CAAK,KAAA,CAAOC,CAAU,CAAA,CAC5CE,CAAAA,CAAYJ,CAAAA,CAAWC,EAAK,MAAA,CAAQC,CAAU,EACpD,OAAIC,CAAAA,GAAa,KAAaC,CAAAA,CAC1BA,CAAAA,GAAc,IAAA,CAAaD,CAAAA,CACxB,CAAE,GAAGF,EAAM,KAAA,CAAOE,CAAAA,CAAU,MAAA,CAAQC,CAAU,CACvD,CAKO,SAASC,EAAAA,CACdJ,CAAAA,CACAK,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAIR,CAAAA,GAAS,IAAA,CACX,OAAO,OAAOQ,CAAAA,EAAc,SAAW,CAAE,IAAA,CAAM,MAAA,CAAQ,MAAA,CAAQA,CAAU,CAAA,CAAIA,EAE/E,GAAIR,CAAAA,CAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,EAAK,MAAA,GAAWK,CAAAA,CAAU,CAC5B,IAAMI,CAAAA,CACJ,OAAOD,GAAc,QAAA,CAAW,CAAE,IAAA,CAAM,MAAA,CAAQ,MAAA,CAAQA,CAAU,EAAIA,CAAAA,CAClEE,CAAAA,CAAUH,CAAAA,GAAc,MAAA,EAAUA,CAAAA,GAAc,KAAA,CACtD,OAAO,CACL,IAAA,CAAM,OAAA,CACN,SAAA,CAAAD,CAAAA,CACA,KAAA,CAAOI,EAAUD,CAAAA,CAAYT,CAAAA,CAC7B,MAAA,CAAQU,CAAAA,CAAUV,CAAAA,CAAOS,CAAAA,CACzB,gBAAiB,EACnB,CACF,CACA,OAAOT,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOI,EAAAA,CAAUJ,CAAAA,CAAK,MAAOK,CAAAA,CAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKR,CAAAA,CAAK,MAChF,MAAA,CAAQI,EAAAA,CAAUJ,CAAAA,CAAK,MAAA,CAAQK,CAAAA,CAAUC,CAAAA,CAAWC,EAAWC,CAAS,CAAA,EAAKR,EAAK,MACpF,CACF,CAKO,SAASW,EAAAA,CAAUX,CAAAA,CAAuBY,CAAAA,CAAaC,CAAAA,CAA8B,CAC1F,GAAIb,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAG1B,IAAMc,CAAAA,CAAQC,EAASf,CAAAA,CAAMY,CAAG,CAAA,CAC1BI,CAAAA,CAAQD,CAAAA,CAASf,CAAAA,CAAMa,CAAG,CAAA,CAChC,GAAI,CAACC,CAAAA,EAAS,CAACE,CAAAA,CAAO,OAAOhB,CAAAA,CAG7B,SAASiB,CAAAA,CAAKC,CAAAA,CAA0B,CACtC,OAAIA,EAAK,IAAA,GAAS,MAAA,CACZA,CAAAA,CAAK,MAAA,GAAWN,CAAAA,CAAY,CAAE,GAAGI,CAAO,CAAA,CACxCE,CAAAA,CAAK,MAAA,GAAWL,CAAAA,CAAY,CAAE,GAAGC,CAAO,CAAA,CACrCI,EAEF,CACL,GAAGA,EACH,KAAA,CAAOD,CAAAA,CAAKC,CAAAA,CAAK,KAAK,CAAA,CACtB,MAAA,CAAQD,EAAKC,CAAAA,CAAK,MAAM,CAC1B,CACF,CAEA,OAAOD,EAAKjB,CAAI,CAClB,CAKO,SAASmB,EAAAA,CAAQnB,CAAAA,CAAuBQ,EAA6B,CAC1E,GAAIR,CAAAA,GAAS,IAAA,CACX,OAAO,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQQ,CAAU,CAAA,CAG3C,SAASY,CAAAA,CAAOF,EAAgBG,CAAAA,CAAkD,CAChF,OAAIH,CAAAA,CAAK,IAAA,GAAS,MAAA,CAET,CACL,IAAA,CAAM,OAAA,CACN,SAAA,CAHgCG,CAAAA,GAAoB,KAAA,CAAQ,QAAA,CAAW,MAIvE,eAAA,CAAiB,EAAA,CACjB,MAAOH,CAAAA,CACP,MAAA,CAAQ,CAAE,IAAA,CAAM,MAAA,CAAQ,MAAA,CAAQV,CAAU,CAC5C,CAAA,CAGK,CACL,GAAGU,CAAAA,CACH,MAAA,CAAQE,CAAAA,CAAOF,CAAAA,CAAK,MAAA,CAAQA,EAAK,SAAS,CAC5C,CACF,CAEA,OAAOE,CAAAA,CAAOpB,EAAM,IAAI,CAC1B,CAKO,SAASsB,CAAAA,CACdtB,CAAAA,CACAuB,EACAC,CAAAA,CACiB,CACjB,OAAIxB,CAAAA,GAAS,IAAA,CAAa,IAAA,CACtBA,IAASuB,CAAAA,CACJ,CAAE,GAAGvB,CAAAA,CAAM,eAAA,CAAiBwB,CAAc,EAE/CxB,CAAAA,CAAK,IAAA,GAAS,OAAA,CACT,CACL,GAAGA,CAAAA,CACH,MAAOsB,CAAAA,CAAsBtB,CAAAA,CAAK,KAAA,CAAOuB,CAAAA,CAAQC,CAAa,CAAA,EAAKxB,EAAK,KAAA,CACxE,MAAA,CAAQsB,CAAAA,CAAsBtB,CAAAA,CAAK,MAAA,CAAQuB,CAAAA,CAAQC,CAAa,CAAA,EAAKxB,CAAAA,CAAK,MAC5E,CAAA,CAEKA,CACT,CAKO,SAASyB,EAAAA,CACdzB,CAAAA,CACA0B,CAAAA,CACAnB,CAAAA,CACiB,CAEjB,IAAMoB,EAA4BZ,CAAAA,CAASf,CAAAA,CAAM0B,CAAU,CAAA,EAAK,CAC9D,IAAA,CAAM,OACN,MAAA,CAAQA,CACV,CAAA,CACME,CAAAA,CAAsB7B,CAAAA,CAAWC,CAAAA,CAAM0B,CAAU,CAAA,CACvD,GAAIE,CAAAA,GAAwB,IAAA,CAC1B,OAAO,CAAE,GAAGD,CAAgB,CAAA,CAG9B,IAAMrB,CAAAA,CAA4BC,CAAAA,GAAc,MAAA,EAAUA,IAAc,OAAA,CAAU,KAAA,CAAQ,SACpFG,CAAAA,CAAUH,CAAAA,GAAc,QAAUA,CAAAA,GAAc,KAAA,CAChDsB,CAAAA,CAAwB,CAAE,GAAGF,CAAgB,EAEnD,OAAO,CACL,IAAA,CAAM,OAAA,CACN,SAAA,CAAArB,CAAAA,CACA,MAAOI,CAAAA,CAAUmB,CAAAA,CAAcD,CAAAA,CAC/B,MAAA,CAAQlB,CAAAA,CAAUkB,CAAAA,CAAsBC,EACxC,eAAA,CAAiB,EACnB,CACF,CAKO,SAASd,CAAAA,CAASf,EAAuB8B,CAAAA,CAAiC,CAC/E,OAAI9B,CAAAA,GAAS,IAAA,CAAa,IAAA,CACtBA,EAAK,IAAA,GAAS,MAAA,CACTA,CAAAA,CAAK,MAAA,GAAW8B,CAAAA,CAAS9B,CAAAA,CAAO,KAElCe,CAAAA,CAASf,CAAAA,CAAK,KAAA,CAAO8B,CAAM,CAAA,EAAKf,CAAAA,CAASf,EAAK,MAAA,CAAQ8B,CAAM,CACrE,CAKO,SAASC,GACd/B,CAAAA,CACA8B,CAAAA,CACAE,CAAAA,CACiB,CACjB,GAAIhC,CAAAA,GAAS,KAAM,OAAO,IAAA,CAC1B,GAAIA,CAAAA,CAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,MAAA,GAAW8B,CAAAA,CAAQ,CAC1B,IAAMG,EAAcD,CAAAA,CAAQhC,CAAAA,CAAK,QAAQ,CAAA,CACzC,GAAIiC,CAAAA,GAAgB,OAAW,CAE7B,GAAM,CAAE,QAAA,CAAUC,CAAAA,CAAG,GAAGC,CAAK,CAAA,CAAInC,CAAAA,CACjC,OAAOmC,CACT,CACA,OAAO,CAAE,GAAGnC,CAAAA,CAAM,QAAA,CAAUiC,CAAY,CAC1C,CACA,OAAOjC,CACT,CACA,OAAO,CACL,GAAGA,EACH,KAAA,CAAO+B,EAAAA,CAAmB/B,CAAAA,CAAK,KAAA,CAAO8B,CAAAA,CAAQE,CAAO,GAAKhC,CAAAA,CAAK,KAAA,CAC/D,MAAA,CAAQ+B,EAAAA,CAAmB/B,CAAAA,CAAK,MAAA,CAAQ8B,EAAQE,CAAO,CAAA,EAAKhC,CAAAA,CAAK,MACnE,CACF,KCvMaoC,EAAAA,CAAyB,CAAA,CACzBC,EAAAA,CAAmC,CAAA,CACnCC,EAAAA,CAAuB,EC4BpC,IAAMC,EAAAA,CAID,CAAC,CAAE,QAAA,CAAAC,CAAAA,CAAU,MAAA,CAAAC,CAAAA,CAAQ,SAAA,CAAAC,CAAU,CAAA,GAAM,CACxC,IAAMC,CAAAA,CAAMC,YAAAA,CAAuB,IAAI,EAEvC,OAAAC,eAAAA,CAAU,IAAM,CACd,IAAMC,CAAAA,CAAcC,GAAoB,CAClCJ,CAAAA,CAAI,OAAA,GACNA,CAAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,UAAY,CAAA,UAAA,EAAaI,CAAAA,CAAE,OAAA,CAAU,EAAE,CAAA,IAAA,EAAOA,CAAAA,CAAE,QAAU,EAAE,CAAA,GAAA,CAAA,EAElF,CAAA,CACA,OAAA,QAAA,CAAS,gBAAA,CAAiB,aAAA,CAAeD,CAAU,CAAA,CAC5C,IAAM,QAAA,CAAS,mBAAA,CAAoB,aAAA,CAAeA,CAAU,CACrE,CAAA,CAAG,EAAE,CAAA,CAGHE,cAAAA,CAAC,KAAA,CAAA,CACC,IAAKL,CAAAA,CACL,SAAA,CAAWD,CAAAA,CACX,KAAA,CAAO,CACL,QAAA,CAAU,QACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,MAAA,CAAQ,IAAA,CACR,cAAe,MACjB,CAAA,CAEC,SAAAD,CAAAA,CAAOD,CAAQ,EAClB,CAEJ,CAAA,CAEMS,EAAAA,CAAN,cAAiCC,kBAAc,CAC7C,OAAO,UAAA,CAAa,CAClB,CACE,SAAA,CAAW,eAAA,CACX,OAAA,CAAS,CAAC,CAAE,WAAA,CAAaC,CAAM,CAAA,GAEzB,CADYA,CAAAA,CAAM,QACT,OAAA,CAAQ,cAAc,CAKvC,CACF,CACF,CAAA,CAgCaC,GAAsD,CAAC,CAClE,MAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CACA,iBAAA,CAAAC,CAAAA,CACA,UAAA,CAAAC,CAAAA,CAAa,GACb,gBAAA,CAAAC,CAAAA,CAAmB,IAAA,CACnB,kBAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,sBAAA,CAAAC,CAAAA,CAAyB,EACzB,aAAA,CAAAC,CAAAA,CAAgB,EAChB,WAAA,CAAAC,CAAAA,CACA,SAAA,CAAAC,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,kBAAA,CAAAC,EAAqB,CAAA,CACrB,kBAAA,CAAAC,CAAAA,CAAqB,EAAA,CACrB,QAAA,CAAAC,CACF,IAAM,CACJ,GAAM,CAACC,CAAAA,CAAaC,CAAc,CAAA,CAAIC,eAA0BrB,CAAM,CAAA,CAChEsB,CAAAA,CAAgB/B,YAAAA,CAAOS,CAAM,CAAA,CAE/BA,IAAWsB,CAAAA,CAAc,OAAA,GAC3BA,CAAAA,CAAc,OAAA,CAAUtB,CAAAA,CACxBoB,CAAAA,CAAepB,CAAM,CAAA,CAAA,CAGvB,GAAM,CAACb,CAAAA,CAAUoC,CAAW,CAAA,CAAIF,eAAwB,IAAI,CAAA,CAGtDG,EAAYjC,YAAAA,CAAO4B,CAAW,EACpCK,CAAAA,CAAU,OAAA,CAAUL,CAAAA,CAEpB,IAAMM,CAAAA,CAAclC,YAAAA,CAAOU,CAAQ,CAAA,CACnCwB,CAAAA,CAAY,OAAA,CAAUxB,CAAAA,CAEtB,IAAMyB,CAAAA,CAAgBnC,aAAOW,CAAU,CAAA,CACvCwB,CAAAA,CAAc,OAAA,CAAUxB,CAAAA,CAExB,IAAMyB,EAAqBpC,YAAAA,CAAOuB,CAAW,CAAA,CAC7Ca,CAAAA,CAAmB,OAAA,CAAUb,CAAAA,CAG7B,IAAMc,CAAAA,CAAmBC,iBAAAA,CAAapD,CAAAA,EAAmBiD,CAAAA,CAAc,OAAA,CAAQjD,CAAM,EAAG,EAAE,CAAA,CAGpFqD,CAAAA,CAAmBC,aAAAA,CACvB,IAAM3B,EACN,CACEA,CAAAA,CAAW,IAAA,CACXA,CAAAA,CAAW,WAAA,CACXA,CAAAA,CAAW,YACXA,CAAAA,CAAW,WAAA,CACXA,CAAAA,CAAW,OACb,CACF,CAAA,CAEM4B,EAAUC,eAAAA,CACdC,cAAAA,CAAUtC,EAAAA,CAAoB,CAC5B,oBAAA,CAAsB,CAAE,SAAUY,CAAuB,CAC3D,CAAC,CACH,CAAA,CAEM2B,CAAAA,CAAmBrC,GAA0B,CACjD,IAAMzB,CAAAA,CAAayB,CAAAA,CAAM,MAAA,CAAO,EAAA,CAAG,UAAS,CAC5CyB,CAAAA,CAAYlD,CAAU,CAAA,CAClBqC,CAAAA,EACFA,CAAAA,CAAYrC,CAAU,EAE1B,CAAA,CAEM+D,EAAAA,CAAiBtC,CAAAA,EAAwB,CAC7CyB,CAAAA,CAAY,IAAI,CAAA,CAChB,GAAM,CAAE,MAAA,CAAAc,CAAAA,CAAQ,IAAA,CAAAC,CAAK,CAAA,CAAIxC,CAAAA,CACnBzB,CAAAA,CAAagE,CAAAA,CAAO,EAAA,CAAG,QAAA,GAE7B,GAAI,CAACC,EAAM,CACL3B,CAAAA,EACFA,EAAUtC,CAAAA,CAAY,IAAA,CAAM,IAAI,CAAA,CAElC,MACF,CAEA,IAAMkE,CAAAA,CAAYD,CAAAA,CAAK,EAAA,CAAG,QAAA,EAAS,CAG7BE,EAAAA,CAAYD,EAAU,KAAA,CAAM,qCAAqC,CAAA,CACvE,GAAIC,EAAAA,CAAW,CACb,GAAM,EAAGC,CAAQ,CAAA,CAAID,EAAAA,CACfE,EAAAA,CAAYtE,GAChB+C,CAAAA,CACA9C,CAAAA,CACAoE,CACF,CAAA,CACArB,CAAAA,CAAesB,EAAS,EACxBzC,CAAAA,CAASyC,EAAS,CAAA,CAEd/B,CAAAA,EAGFA,CAAAA,CAAUtC,CAAAA,CAAY,OAAQ,CAC5B,IAAA,CAAM,OAAA,CACN,SAAA,CAHAoE,CAAAA,GAAa,MAAA,EAAUA,IAAa,OAAA,CAAU,KAAA,CAAQ,SAItD,QAAA,CAAUA,CACZ,CAAC,CAAA,CAEH,MACF,CAGA,IAAME,CAAAA,CAAYJ,CAAAA,CAAU,MAAM,oBAAoB,CAAA,CACtD,GAAII,CAAAA,CAAW,CACb,GAAM,EAAG3F,CAAQ,CAAA,CAAI2F,CAAAA,CACrB,GAAItE,CAAAA,GAAerB,EAAU,CAC3B,IAAM0F,EAAAA,CAAYpF,EAAAA,CAAU6D,CAAAA,CAAa9C,CAAAA,CAAYrB,CAAQ,CAAA,CAC7DoE,CAAAA,CAAesB,EAAS,CAAA,CACxBzC,CAAAA,CAASyC,EAAS,EACpB,CACI/B,CAAAA,EACFA,CAAAA,CAAUtC,CAAAA,CAAYrB,CAAAA,CAAU,CAAE,KAAM,MAAA,CAAQ,QAAA,CAAU,QAAS,CAAC,CAAA,CAEtE,MACF,CAGA,IAAM4F,EAAAA,CAAQL,EAAU,KAAA,CAAM,qCAAqC,EACnE,GAAI,CAACK,EAAAA,CAAO,CACNjC,CAAAA,EACFA,CAAAA,CAAUtC,EAAY,IAAA,CAAM,IAAI,CAAA,CAElC,MACF,CAEA,GAAM,EAAGoE,EAAAA,CAAUzF,EAAQ,CAAA,CAAI4F,EAAAA,CAC/B,GAAIvE,IAAerB,EAAAA,CAAU,CACvB2D,CAAAA,EACFA,CAAAA,CAAUtC,CAAAA,CAAY,IAAA,CAAM,IAAI,CAAA,CAElC,MACF,CAEA,IAAMpB,EAAAA,CAA4BwF,EAAAA,GAAa,QAAUA,EAAAA,GAAa,OAAA,CAAU,KAAA,CAAQ,QAAA,CAClFnE,EAAAA,CAAkBZ,CAAAA,CAASyD,EAAa9C,CAAU,CAAA,EAAK,CAC3D,IAAA,CAAM,MAAA,CACN,MAAA,CAAQA,CACV,CAAA,CACME,EAAAA,CAAsB7B,CAAAA,CAAWyE,CAAAA,CAAa9C,CAAU,CAAA,CAExDqE,GAAY3F,EAAAA,CAChBwB,EAAAA,CACAvB,EAAAA,CACAC,EAAAA,CACAwF,EAAAA,CACAnE,EACF,EACA8C,CAAAA,CAAesB,EAAS,CAAA,CACxBzC,CAAAA,CAASyC,EAAS,CAAA,CACd/B,GACFA,CAAAA,CAAUtC,CAAAA,CAAYrB,EAAAA,CAAU,CAC9B,IAAA,CAAM,OAAA,CACN,UAAAC,EAAAA,CACA,QAAA,CAAUwF,EACZ,CAAC,EAEL,CAAA,CAEMI,EAA0BhB,iBAAAA,CAAaa,CAAAA,EAA+B,CAC1EtB,CAAAA,CAAesB,CAAS,EAC1B,EAAG,EAAE,CAAA,CAECI,CAAAA,CAAmBjB,iBAAAA,CAAapD,CAAAA,EAAmB,CACvD,IAAMiE,CAAAA,CAAYhG,CAAAA,CAAW8E,CAAAA,CAAU,OAAA,CAAS/C,CAAM,EACtD2C,CAAAA,CAAesB,CAAS,EACxBjB,CAAAA,CAAY,OAAA,CAAQiB,CAAS,EAC/B,CAAA,CAAG,EAAE,CAAA,CAECK,CAAAA,CAAgBlB,kBAAapD,CAAAA,EAAmB,CACpD,IAAMiE,CAAAA,CAAY5E,EAAAA,CAAQ0D,CAAAA,CAAU,QAAS/C,CAAM,CAAA,CACnD2C,CAAAA,CAAesB,CAAS,CAAA,CACxBjB,CAAAA,CAAY,QAAQiB,CAAS,EAC/B,CAAA,CAAG,EAAE,CAAA,CAECM,EAAkBnB,iBAAAA,CAAY,CAACoB,CAAAA,CAAiBC,CAAAA,GAAoB,CACxE,IAAMR,EAAYpF,EAAAA,CAAUkE,CAAAA,CAAU,OAAA,CAASyB,CAAAA,CAASC,CAAO,CAAA,CAC/D9B,EAAesB,CAAS,CAAA,CACxBjB,CAAAA,CAAY,OAAA,CAAQiB,CAAS,EAC/B,EAAG,EAAE,EAECS,CAAAA,CAAkBtB,iBAAAA,CACtB,CACE7E,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,GACG,CACH,IAAMmB,EAAkBZ,CAAAA,CAAS8D,CAAAA,CAAU,OAAA,CAASrE,CAAS,CAAA,EAAK,CAChE,KAAM,MAAA,CACN,MAAA,CAAQA,CACV,CAAA,CACMoB,EAAAA,CAAsB7B,CAAAA,CAAW8E,EAAU,OAAA,CAASrE,CAAS,CAAA,CAC7DuF,CAAAA,CAAY3F,EAAAA,CAChBwB,EAAAA,CACAvB,EACAC,CAAAA,CACAC,CAAAA,CACAoB,CACF,CAAA,CACA8C,CAAAA,CAAesB,CAAS,EACxBjB,CAAAA,CAAY,OAAA,CAAQiB,CAAS,EAC/B,CAAA,CACA,EACF,CAAA,CAEMU,CAAAA,CAA8BvB,iBAAAA,CAAY,CAACwB,CAAAA,CAAwBC,CAAAA,GAAuB,CAC9F,IAAMZ,CAAAA,CAAYzE,EAAsBuD,CAAAA,CAAU,OAAA,CAAS6B,EAAaC,CAAU,CAAA,CAClFlC,CAAAA,CAAesB,CAAS,CAAA,CACxBjB,CAAAA,CAAY,QAAQiB,CAAS,EAC/B,CAAA,CAAG,EAAE,CAAA,CAECa,EAA2B1B,iBAAAA,CAC/B,CACEpD,CAAAA,CACAE,CAAAA,GAGG,CACH,IAAM+D,EAAYhE,EAAAA,CAAmB8C,CAAAA,CAAU,OAAA,CAAS/C,CAAAA,CAAQE,CAAO,CAAA,CACvEyC,EAAesB,CAAS,CAAA,CACxBjB,CAAAA,CAAY,OAAA,CAAQiB,CAAS,EAC/B,EACA,EACF,CAAA,CAEMc,CAAAA,CAAkB3B,iBAAAA,CAAY,CAACwB,EAAwBC,CAAAA,GAAuB,CAClF,IAAMG,CAAAA,CAAcxF,CAAAA,CAAsBuD,CAAAA,CAAU,QAAS6B,CAAAA,CAAaC,CAAU,CAAA,CACpFlC,CAAAA,CAAeqC,CAAW,CAAA,CAC1BhC,EAAY,OAAA,CAAQgC,CAAW,CAAA,CAC3B9B,CAAAA,CAAmB,OAAA,EACrBA,CAAAA,CAAmB,QAAQ0B,CAAAA,CAAaC,CAAU,EAEtD,CAAA,CAAG,EAAE,EAGCI,EAAAA,CAAa3B,aAAAA,CACjB,KAAO,CACL,MAAA,CAAQZ,CAAAA,CACR,eAAgB0B,CAAAA,CAChB,UAAA,CAAYjB,CAAAA,CACZ,QAAA,CAAAzC,CAAAA,CACA,gBAAA,CAAAkB,EACA,UAAA,CAAYyB,CAAAA,CACZ,QAAA,CAAAvB,CAAAA,CACA,kBAAA,CAAAD,CAAAA,CACA,cAAAG,CAAAA,CACA,aAAA,CAAAG,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,WAAA,CAAa2C,EACb,aAAA,CAAAzC,CAAAA,CACA,kBAAA,CAAAC,CAAAA,CACA,kBAAA,CAAAC,CACF,GACA,CACEE,CAAAA,CACAhC,EACAkB,CAAAA,CACAyB,CAAAA,CACAvB,EACAD,CAAAA,CACAG,CAAAA,CACAG,CAAAA,CACAC,CAAAA,CACAE,CAAAA,CACAC,CAAAA,CACAC,EAEA4B,CAAAA,CACAjB,CAAAA,CACA4B,CACF,CACF,CAAA,CAGMG,EAAAA,CAAe5B,cACnB,KAAO,CACL,UAAA,CAAYe,CAAAA,CACZ,OAAA,CAASC,CAAAA,CACT,UAAWC,CAAAA,CACX,SAAA,CAAWG,CAAAA,CACX,qBAAA,CAAuBC,CAAAA,CACvB,kBAAA,CAAoBG,CACtB,CAAA,CAAA,CACA,CACET,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAG,CAAAA,CACAC,EACAG,CACF,CACF,CAAA,CAEA,OACE5D,cAAAA,CAACvD,EAAAA,CAAwB,SAAxB,CAAiC,KAAA,CAAOuH,EAAAA,CACvC,QAAA,CAAAC,eAAAA,CAAC1H,EAAAA,CAAsB,SAAtB,CAA+B,KAAA,CAAOwH,GACrC,QAAA,CAAA,CAAA/D,cAAAA,CAACkE,gBAAA,CACC,EAAA,CAAG,oBAAA,CACH,OAAA,CAAS7B,CAAAA,CACT,kBAAA,CAAoB8B,mBACpB,WAAA,CAAa3B,CAAAA,CACb,SAAA,CAAWC,EAAAA,CAEV,QAAA,CAAAlB,CAAAA,CACH,EACC/B,CAAAA,EAAYgB,CAAAA,EACXR,cAAAA,CAACT,EAAAA,CAAA,CACC,QAAA,CAAUC,EACV,MAAA,CAAQgB,CAAAA,CACR,SAAA,CAAWC,CAAAA,CAAW,WAAA,CACxB,CAAA,CAAA,CAEJ,EACF,CAEJ,EC/aA,IAAM2D,EAAAA,CAA+D,CACnE,GAAA,CAAK,CACH,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,IAAA,CAAM,EACN,KAAA,CAAO,CAAA,CACP,OAAQ,MAAA,CACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,OAAQ,CACN,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,CAAA,CACP,MAAA,CAAQ,MAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,IAAA,CAAM,CACJ,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,OACP,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,MAAO,CAAA,CACP,KAAA,CAAO,MAAA,CACP,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CACF,CAAA,CAEMC,EAAAA,CAA4D,CAChE,GAAA,CAAK,CACH,SAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,UAAW,YACb,CAAA,CACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,OAAQ,CAAA,CACR,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,CAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,EACA,IAAA,CAAM,CACJ,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,OAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,KAAA,CACP,OAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,MAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,EACR,KAAA,CAAO,CAAA,CACP,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CACF,CAAA,CAQaC,EAAAA,CAA4C,CAAC,CAAE,EAAA,CAAAC,CAAAA,CAAI,QAAA,CAAAC,CAAAA,CAAU,eAAA,CAAAC,CAAgB,CAAA,GAAM,CAC9F,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,OAAAC,CAAO,CAAA,CAAIC,iBAAAA,CAAa,CAAE,EAAA,CAAAL,CAAG,CAAC,CAAA,CAClD,OACEN,gBAAAY,mBAAAA,CAAA,CACE,UAAA7E,cAAAA,CAAC,KAAA,CAAA,CAAI,GAAA,CAAK0E,CAAAA,CAAY,KAAA,CAAON,EAAAA,CAAwBI,CAAQ,CAAA,CAAG,CAAA,CAC/DG,CAAAA,EAAU3E,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAWyE,EAAiB,KAAA,CAAOJ,EAAAA,CAAqBG,CAAQ,CAAA,CAAG,CAAA,CAAA,CACrF,CAEJ,EAQaM,EAAAA,CAA8C,CAAC,CAC1D,QAAA,CAAAtF,CAAAA,CACA,aAAA,CAAAuF,EACA,oBAAA,CAAAC,CACF,CAAA,GACM,CAACxF,CAAAA,EAAY,CAACuF,EAAsB,IAAA,CAGtC/E,cAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,QAAA,CAAU,WACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,CAAA,CACP,OAAQ,CAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MACjB,EAEE,QAAA,CAAA,CAAC,KAAA,CAAO,QAAA,CAAU,MAAA,CAAQ,OAAO,CAAA,CAAY,IAAKiF,CAAAA,EAClDjF,cAAAA,CAACsE,EAAAA,CAAA,CAEC,EAAA,CAAI,CAAA,UAAA,EAAaW,CAAG,CAAA,CAAA,CACpB,QAAA,CAAUA,CAAAA,CACV,eAAA,CAAiBD,CAAAA,CAAAA,CAHZC,CAIP,CACD,CAAA,CACH,CAAA,CCnHG,SAASC,EAAAA,CAAW,CACzB,YAAA,CAAAC,CAAAA,CACA,KAAA,CAAAC,CAAAA,CACA,UAAA9H,CAAAA,CACA,eAAA,CAAA+H,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,aAAA,CAAAxE,EACA,MAAA,CAAAT,CAAAA,CACA,WAAA,CAAAqD,CAAAA,CACA,cAAA,CAAA6B,CAAAA,CACA,cAAeC,CAAAA,CACf,WAAA,CAAaC,CACf,CAAA,CAAoB,CAClB,GAAM,CACJ,aAAA,CAAeC,CAAAA,CACf,QAAA,CAAUC,CAAAA,CACV,WAAA,CAAaC,CAAAA,CACb,mBAAAvE,CAAAA,CAAqB,CAAA,CACrB,kBAAA,CAAAC,CAAAA,CAAqB,EACvB,CAAA,CAAI5E,GAAkB,CAEtB,OAAOwF,iBAAAA,CACJnC,CAAAA,EAA0C,CACzCA,CAAAA,CAAE,gBAAe,CACjB,IAAM8F,CAAAA,CAAYV,CAAAA,CAAa,OAAA,CAC/B,GAAI,CAACU,CAAAA,CAAW,OAEhB,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,iBAAiB,CAAA,CAG7C,IAAMC,CAAAA,CAAU,QAAA,CAAS,aAAA,CAAc,OAAO,EAC9CA,CAAAA,CAAQ,EAAA,CAAK,4BAAA,CACbA,CAAAA,CAAQ,WAAA,CAAc;AAAA;AAAA,gBAAA,EAEVV,CAAAA,CAAQ,aAAe,YAAY,CAAA;AAAA;AAAA;AAAA,IAAA,CAAA,CAI/C,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYU,CAAO,EAE7BN,CAAAA,EACFA,CAAAA,EAAmB,CAEjBE,CAAAA,EACFA,EAAoBhC,CAAW,CAAA,CAGjC,IAAMqC,CAAAA,CAAOF,EAAU,qBAAA,EAAsB,CACvCG,CAAAA,CAASjG,CAAAA,CAAE,QACXkG,CAAAA,CAASlG,CAAAA,CAAE,OAAA,CACXmG,CAAAA,CAAkBb,EAGlBc,CAAAA,CAAYpG,CAAAA,CAAE,aAAA,CACpBoG,CAAAA,CAAU,aAAa,eAAA,CAAiB,MAAM,CAAA,CAM9C,IAAMC,EAJgB,KAAA,CAAM,IAAA,CAC1B,QAAA,CAAS,gBAAA,CAAiB,uCAAuC,CACnE,CAAA,CAAE,MAAA,CAAQC,GAAOA,CAAAA,GAAOF,CAAAA,EAAaE,CAAAA,CAAG,YAAA,CAAa,gBAAgB,CAAA,GAAM/I,CAAS,CAAA,CAE/C,GAAA,CAAK+I,GAAO,CAC/C,IAAMC,CAAAA,CAAID,CAAAA,CAAG,uBAAsB,CACnC,OAAOjB,CAAAA,CAAQkB,CAAAA,CAAE,KAAOA,CAAAA,CAAE,KAAA,CAAQ,CAAA,CAAIA,CAAAA,CAAE,IAAMA,CAAAA,CAAE,MAAA,CAAS,CAC3D,CAAC,EAEGC,CAAAA,CAAoBL,CAAAA,CAElBM,CAAAA,CAAqBC,CAAAA,EAA4B,CACrD,IAAMC,CAAAA,CAAQtB,CAAAA,CAAAA,CACRqB,EAAU,OAAA,CAAUT,CAAAA,EAAUD,CAAAA,CAAK,KAAA,CAAS,KAC5CU,CAAAA,CAAU,OAAA,CAAUR,CAAAA,EAAUF,CAAAA,CAAK,OAAU,GAAA,CAC7CY,CAAAA,CAAqBT,CAAAA,CAAkBQ,CAAAA,CAGvCE,GAAcxB,CAAAA,CAChBW,CAAAA,CAAK,IAAA,CAAA,CAAQA,CAAAA,CAAK,MAAQT,CAAAA,GAAgBqB,CAAAA,CAAqB,GAAA,CAAA,CAAOrB,CAAAA,CAAc,EACpFS,CAAAA,CAAK,GAAA,CAAA,CAAOA,CAAAA,CAAK,MAAA,CAAST,IAAgBqB,CAAAA,CAAqB,GAAA,CAAA,CAAOrB,CAAAA,CAAc,CAAA,CAEpFuB,CAAAA,CAAkB,CAAA,CAAA,CAAA,CAClBC,CAAAA,CAA4B,IAAA,CAEhC,QAAW7B,CAAAA,IAAOmB,CAAAA,CAAgB,CAChC,IAAMW,EAAO,IAAA,CAAK,GAAA,CAAIH,EAAAA,CAAc3B,CAAG,EACnC8B,CAAAA,CAAOjG,CAAAA,EAAiBiG,CAAAA,CAAOF,CAAAA,GACjCA,EAAkBE,CAAAA,CAClBD,CAAAA,CAAa7B,CAAAA,EAEjB,CAEA,IAAI+B,CAAAA,CAAoBL,CAAAA,CACpBG,CAAAA,GAAe,IAAA,GACjBE,EAAoB5B,CAAAA,CAAAA,CACd0B,CAAAA,CAAaxB,CAAAA,CAAc,CAAA,CAAIS,EAAK,IAAA,GAASA,CAAAA,CAAK,KAAA,CAAQT,CAAAA,CAAAA,CAAgB,GAAA,CAAA,CAC1EwB,CAAAA,CAAaxB,CAAAA,CAAc,CAAA,CAAIS,EAAK,GAAA,GAAQA,CAAAA,CAAK,MAAA,CAAST,CAAAA,CAAAA,CAAgB,KAGlF,IAAM2B,CAAAA,CAAkB,IAAA,CAAK,GAAA,CAC3B5F,EACA,IAAA,CAAK,GAAA,CAAIC,CAAAA,CAAoB0F,CAAiB,CAChD,CAAA,CACAT,CAAAA,CAAoBU,CAAAA,CAGpB,IAAMC,EAAarB,CAAAA,CAAU,QAAA,CAAS,CAAC,CAAA,CACjCsB,EAActB,CAAAA,CAAU,QAAA,CAASA,CAAAA,CAAU,QAAA,CAAS,OAAS,CAAC,CAAA,CAChEqB,CAAAA,EAAcC,CAAAA,GAChBD,CAAAA,CAAW,KAAA,CAAM,IAAA,CAAO,CAAA,EAAGD,CAAe,CAAA,KAAA,CAAA,CAC1CE,CAAAA,CAAY,KAAA,CAAM,IAAA,CAAO,GAAG,GAAA,CAAMF,CAAe,CAAA,KAAA,CAAA,CAAA,CAG/CtB,CAAAA,EACFA,EAAejC,CAAAA,CAAauD,CAAe,EAE/C,CAAA,CAEMG,EAAkB,IAAM,CAC5B,QAAA,CAAS,IAAA,CAAK,UAAU,MAAA,CAAO,iBAAiB,CAAA,CAChDjB,CAAAA,CAAU,gBAAgB,eAAe,CAAA,CAEzC,IAAMkB,CAAAA,CAAc,SAAS,cAAA,CAAe,4BAA4B,CAAA,CACpEA,CAAAA,EACFA,CAAAA,CAAY,MAAA,EAAO,CAGrB,QAAA,CAAS,oBAAoB,aAAA,CAAeb,CAAiB,CAAA,CAC7D,QAAA,CAAS,oBAAoB,WAAA,CAAaY,CAAe,CAAA,CAGzD,IAAMrE,EAAYzE,CAAAA,CAAsB+B,CAAAA,CAAQqD,CAAAA,CAAa6C,CAAiB,EAC9E,OAAA,CAAQ,GAAA,CAAI,oDAAA,CAAsDA,CAAiB,EACnFhB,CAAAA,CAAexC,CAAS,CAAA,CAEpB0C,CAAAA,EACFA,GAAiB,CAEfG,CAAAA,EACFA,CAAAA,CAAkBlC,CAAAA,CAAa6C,CAAiB,EAEpD,CAAA,CAEA,QAAA,CAAS,gBAAA,CAAiB,aAAA,CAAeC,CAAiB,CAAA,CAC1D,QAAA,CAAS,iBAAiB,WAAA,CAAaY,CAAe,EACxD,CAAA,CACA,CACEjC,CAAAA,CACAC,CAAAA,CACA9H,CAAAA,CACA+H,CAAAA,CACAC,EACAxE,CAAAA,CACAT,CAAAA,CACAqD,CAAAA,CACA6B,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAvE,EACAC,CACF,CACF,CACF,KC9JMgG,EAAAA,CAAsC,CAAC,CAC3C,WAAA,CAAA5D,EACA,WAAA,CAAA4B,CAAAA,CACA,aAAA,CAAAxE,CAAAA,CACA,cAAeyG,CACjB,CAAA,GAAM,CACJ,GAAM,CACJ,MAAA,CAAAlH,CAAAA,CACA,cAAA,CAAAkF,CAAAA,CACA,WAAA9E,CAAAA,CACA,aAAA,CAAe+G,CACjB,CAAA,CAAI9K,GAAkB,CAChB,CAAC+K,CAAAA,CAAYC,CAAa,EAAIhG,cAAAA,CAAS,KAAK,CAAA,CAE5CN,CAAAA,CAAgBmG,CAAAA,EAAqBC,CAAAA,CAErCrC,CAAAA,CAAevF,YAAAA,CAAuB,IAAI,CAAA,CAC1C,CAAE,SAAA,CAAAtC,CAAAA,CAAW,MAAAqK,CAAAA,CAAO,MAAA,CAAAC,CAAAA,CAAQ,eAAA,CAAAvC,CAAgB,CAAA,CAAI3B,CAAAA,CAChD0B,CAAAA,CAAQ9H,CAAAA,GAAc,MAEtBuK,CAAAA,CAAoB3C,EAAAA,CAAW,CACnC,YAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,SAAA,CAAA9H,CAAAA,CACA,gBAAA+H,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,aAAA,CAAexE,GAAiB,CAAA,CAChC,MAAA,CAAAT,CAAAA,CACA,WAAA,CAAAqD,CAAAA,CACA,cAAA,CAAA6B,CAAAA,CACA,aAAA,CAAe,IAAMmC,CAAAA,CAAc,IAAI,CAAA,CACvC,WAAA,CAAa,IAAMA,CAAAA,CAAc,KAAK,CACxC,CAAC,EAED,OACEzD,eAAAA,CAAC,KAAA,CAAA,CACC,GAAA,CAAKkB,EACL,KAAA,CAAO,CACL,OAAA,CAAS,MAAA,CACT,cAAeC,CAAAA,CAAQ,KAAA,CAAQ,QAAA,CAC/B,KAAA,CAAO,OACP,MAAA,CAAQ,MAAA,CACR,QAAA,CAAU,QACZ,EAEA,QAAA,CAAA,CAAApF,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAGqF,CAAe,QAAS,QAAA,CAAU,QAAS,CAAA,CAChE,QAAA,CAAArF,eAAC8H,EAAAA,CAAA,CACC,IAAA,CAAMH,CAAAA,CACN,YAAarC,CAAAA,CACb,aAAA,CAAexE,CAAAA,CACf,aAAA,CAAeyG,EACjB,CAAA,CACF,CAAA,CACCnG,CAAAA,CACCA,CAAAA,CAAc,CACZ,SAAA,CAAA9D,CAAAA,CACA,eAAA,CAAA+H,CAAAA,CACA,YAAAC,CAAAA,CACA,UAAA,CAAAmC,CAAAA,CACA,aAAA,CAAeI,CACjB,CAAC,CAAA,CAED7H,cAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAWS,CAAAA,CAAW,OAAA,CACtB,gBAAA,CAAgBnD,EAChB,KAAA,CAAO,CACL,KAAA,CAAO8H,CAAAA,CAAQ,GAAGE,CAAW,CAAA,EAAA,CAAA,CAAO,MAAA,CACpC,MAAA,CAAQF,EAAQ,MAAA,CAAS,CAAA,EAAGE,CAAW,CAAA,EAAA,CAAA,CACvC,OAAQF,CAAAA,CAAQ,YAAA,CAAe,YAAA,CAC/B,QAAA,CAAU,WACV,MAAA,CAAQ,EAAA,CACR,UAAA,CAAY,MAAA,CACZ,UAAW,YAAA,CACX,UAAA,CAAY,CACd,CAAA,CACA,cAAeyC,CAAAA,CACf,IAAA,CAAK,WAAA,CACL,eAAA,CAAexC,CAAAA,CACf,eAAA,CAAe,CAAA,CACf,eAAA,CAAe,GACjB,CAAA,CAEFrF,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAG,GAAA,CAAMqF,CAAe,QAAS,QAAA,CAAU,QAAS,CAAA,CACtE,QAAA,CAAArF,eAAC8H,EAAAA,CAAA,CACC,IAAA,CAAMF,CAAAA,CACN,YAAatC,CAAAA,CACb,aAAA,CAAexE,CAAAA,CACf,aAAA,CAAeyG,EACjB,CAAA,CACF,CAAA,CAAA,CACF,CAEJ,CAAA,CAEaO,GAAoC,CAAC,CAChD,IAAA,CAAA9K,CAAAA,CACA,WAAA,CAAAsI,CAAAA,CAAc,CAAA,CACd,aAAA,CAAeyC,EACf,aAAA,CAAA3G,CACF,CAAA,GAAM,CACJ,GAAM,CACJ,MAAA,CAAAf,CAAAA,CACA,UAAA,CAAAE,EACA,QAAA,CAAAf,CAAAA,CACA,UAAA,CAAAiB,CAAAA,CACA,iBAAAC,CAAAA,CACA,aAAA,CAAesH,CACjB,CAAA,CAAItL,GAAkB,CAEhBoE,CAAAA,CAAgBiH,CAAAA,GAAsB,MAAA,CAAYA,EAAoBC,CAAAA,CAEtEjD,CAAAA,CAAgB3C,aAAAA,CAAQ,IACxBpF,IAAS,MAAA,EAAa,CAACwC,CAAAA,CAAiB,KAAA,CACrCzC,EAAWsD,CAAAA,CAAQb,CAAQ,CAAA,GAAM,IAAA,CACvC,CAACxC,CAAAA,CAAMqD,CAAAA,CAAQb,CAAQ,CAAC,EAG3B,GAAIkB,CAAAA,EAAoB,CAAC1D,CAAAA,CACvB,OACEgD,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,MAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,UAAW,CAAA,CAC/D,QAAA,CAAAO,CAAAA,CAAWG,CAAgB,EAC9B,CAAA,CAIJ,IAAMgD,CAAAA,CAAc1G,CAAAA,GAAS,OAAYA,CAAAA,CAAOqD,CAAAA,CAEhD,GAAI,CAACqD,CAAAA,CAAa,OAAO,IAAA,CAEzB,IAAMuE,EAAgB,IAChBvE,CAAAA,CAAY,IAAA,GAAS,MAAA,CAErB1D,eAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAA,CAAO,OAAQ,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,UAAW,EAC/D,QAAA,CAAAO,CAAAA,CAAWmD,CAAAA,CAAY,MAAM,EAChC,CAAA,CAKF1D,cAAAA,CAACsH,EAAAA,CAAA,CACC,YAAa5D,CAAAA,CACb,WAAA,CAAa4B,CAAAA,CACb,aAAA,CAAexE,EACf,aAAA,CAAeM,CAAAA,CACjB,CAAA,CAKJ,OAAIpE,CAAAA,GAAS,MAAA,CAETiH,eAAAA,CAAC,KAAA,CAAA,CACC,UAAU,uBAAA,CACV,KAAA,CAAO,CACL,QAAA,CAAU,WACV,KAAA,CAAO,MAAA,CACP,MAAA,CAAQ,MAAA,CACR,SAAU,QACZ,CAAA,CAEC,QAAA,CAAA,CAAAgE,CAAAA,GACDjI,cAAAA,CAAC8E,EAAAA,CAAA,CACC,QAAA,CAAUtF,EACV,aAAA,CAAeuF,CAAAA,CACf,oBAAA,CAAsBtE,CAAAA,CAAW,YACnC,CAAA,CAAA,CACF,CAAA,CAIGwH,CAAAA,EACT,EChMO,IAAMC,EAAAA,CAAmB1L,mBAAAA,CAA8C,IAAI,ECWlF,IAAM2L,EAAAA,CAA2D,CAC/D,GAAA,CAAK,CACH,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,IAAA,CAAM,KAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,CAAA,CACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,MAAA,CAAQ,CAAA,CACR,KAAM,KAAA,CACN,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,EACA,IAAA,CAAM,CACJ,QAAA,CAAU,UAAA,CACV,IAAK,KAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CACA,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,KAAA,CACL,MAAO,CAAA,CACP,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,MACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MACjB,EACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,IAAK,KAAA,CACL,IAAA,CAAM,KAAA,CACN,KAAA,CAAO,MACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CACF,CAAA,CAEMC,EAAAA,CAAwD,CAC5D,GAAA,CAAK,CACH,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,MAAO,CAAA,CACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,GACR,aAAA,CAAe,MAAA,CACf,SAAA,CAAW,YACb,EACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,OAAQ,CAAA,CACR,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,KAAM,CACJ,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,MAAA,CAAQ,CAAA,CACR,IAAA,CAAM,EACN,KAAA,CAAO,KAAA,CACP,MAAA,CAAQ,EAAA,CACR,cAAe,MAAA,CACf,SAAA,CAAW,YACb,CAAA,CACA,MAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,EACL,MAAA,CAAQ,CAAA,CACR,KAAA,CAAO,CAAA,CACP,MAAO,KAAA,CACP,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,OACf,SAAA,CAAW,YACb,CAAA,CACA,MAAA,CAAQ,CACN,QAAA,CAAU,UAAA,CACV,GAAA,CAAK,CAAA,CACL,KAAM,CAAA,CACN,KAAA,CAAO,CAAA,CACP,MAAA,CAAQ,EACR,MAAA,CAAQ,EAAA,CACR,aAAA,CAAe,MAAA,CACf,UAAW,YACb,CACF,CAAA,CAEMC,EAAAA,CAAoC,CAAC,CAAE,EAAA,CAAA9D,CAAAA,CAAI,QAAA,CAAAC,EAAU,eAAA,CAAAC,CAAgB,CAAA,GAAM,CAC/E,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,MAAA,CAAAC,CAAO,CAAA,CAAIC,iBAAAA,CAAa,CAAE,EAAA,CAAAL,CAAG,CAAC,CAAA,CAClD,OACEN,eAAAA,CAAAY,mBAAAA,CAAA,CACE,QAAA,CAAA,CAAA7E,cAAAA,CAAC,OAAI,GAAA,CAAK0E,CAAAA,CAAY,KAAA,CAAOyD,EAAAA,CAAoB3D,CAAQ,CAAA,CAAG,CAAA,CAC3DG,CAAAA,EAAU3E,cAAAA,CAAC,OAAI,SAAA,CAAWyE,CAAAA,CAAiB,KAAA,CAAO2D,EAAAA,CAAiB5D,CAAQ,CAAA,CAAG,CAAA,CAAA,CACjF,CAEJ,CAAA,CAQa8D,GAA4B,CAAC,CAAE,EAAA,CAAA/D,CAAAA,CAAI,SAAAhD,CAAAA,CAAU,KAAA,CAAAgH,CAAM,CAAA,GAAM,CACpE,GAAM,CAAE,MAAA,CAAAlI,CAAAA,CAAQ,QAAA,CAAAb,CAAAA,CAAU,UAAA,CAAAiB,CAAAA,CAAY,iBAAAC,CAAAA,CAAkB,QAAA,CAAAE,CAAAA,CAAU,kBAAA,CAAAD,CAAmB,CAAA,CACnFjE,CAAAA,EAAkB,CACd,CAAE,WAAAK,CAAAA,CAAY,kBAAA,CAAAgC,CAAmB,CAAA,CAAIlC,IAAoB,CACzD2L,CAAAA,CAAgBhJ,CAAAA,GAAa,IAAA,EAAQA,IAAa+E,CAAAA,CAElD,CAAE,UAAA,CAAAkE,CAAAA,CAAY,UAAAC,CAAAA,CAAW,UAAA,CAAAhE,CAAAA,CAAY,UAAA,CAAAiE,CAAW,CAAA,CAAIC,iBAAAA,CAAa,CAAE,EAAA,CAAArE,CAAG,CAAC,CAAA,CACvEsE,CAAAA,CAAWrJ,IAAa+E,CAAAA,EAAMoE,CAAAA,CAC9BG,CAAAA,CAAepI,CAAAA,GAAqB6D,EAGpCwE,CAAAA,CADW3G,aAAAA,CAAQ,IAAMrE,CAAAA,CAASsC,EAAQkE,CAAE,CAAA,CAAG,CAAClE,CAAAA,CAAQkE,CAAE,CAAC,CAAA,EACtC,QAAA,CAErByE,CAAAA,CAA+B5G,cACnC,KAAO,CACL,UAAA,CAAYyG,CAAAA,CACZ,aAAAC,CAAAA,CACA,gBAAA,CAAkB,IAAMnI,CAAAA,GAAqBmI,EAAe,IAAA,CAAOvE,CAAE,CAAA,CACrE,MAAA,CAAQ,IAAM,CACRuE,CAAAA,EACFnI,CAAAA,GAAqB,IAAI,CAAA,CAEvBC,CAAAA,CACFA,CAAAA,CAAS2D,CAAE,EAEXxH,CAAAA,CAAWwH,CAAE,EAEjB,CAAA,CACA,SAAAwE,CAAAA,CACA,cAAA,CAAiB/J,CAAAA,EAAY,CAC3BD,EAAmBwF,CAAAA,CAAIvF,CAAO,EAChC,CACF,GACA,CACE6J,CAAAA,CACAC,CAAAA,CACAnI,CAAAA,CACA4D,EACA3D,CAAAA,CACA7D,CAAAA,CACAgM,CAAAA,CACAhK,CACF,CACF,CAAA,CAGMkK,CAAAA,CAAe7G,aAAAA,CACnB,KAAO,CACL,GAAGsG,CAAAA,CACH,GAAGD,CACL,CAAA,CAAA,CACA,CAACC,CAAAA,CAAWD,CAAU,CACxB,CAAA,CAEA,OACEzI,cAAAA,CAACkI,EAAAA,CAAiB,SAAjB,CAA0B,KAAA,CAAOe,CAAAA,CAChC,QAAA,CAAAhF,gBAAC,KAAA,CAAA,CACC,GAAA,CAAKS,CAAAA,CACL,SAAA,CAAWjE,EAAW,IAAA,CACtB,KAAA,CAAO,CAAE,QAAA,CAAU,WAAY,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,GAAG8H,CAAM,CAAA,CAEtE,QAAA,CAAA,CAAAhH,CAAAA,CAASyH,CAAW,CAAA,CAEpBR,CAAAA,EACCvE,eAAAA,CAAC,OACC,KAAA,CAAO,CACL,QAAA,CAAU,UAAA,CACV,IAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,KAAA,CAAO,EACP,MAAA,CAAQ,CAAA,CACR,MAAA,CAAQ,EAAA,CACR,cAAe,MACjB,CAAA,CAEE,QAAA,CAAA,CAAA,CAAC,KAAA,CAAO,SAAU,MAAA,CAAQ,OAAO,CAAA,CAAY,GAAA,CAAKgB,GAClDjF,cAAAA,CAACqI,EAAAA,CAAA,CAEC,EAAA,CAAI,QAAQpD,CAAG,CAAA,CAAA,EAAIV,CAAE,CAAA,CAAA,CACrB,QAAA,CAAUU,CAAAA,CACV,eAAA,CAAiBxE,CAAAA,CAAW,aAHvBwE,CAIP,CACD,CAAA,CACDjF,cAAAA,CAACqI,GAAA,CACC,EAAA,CAAI,CAAA,YAAA,EAAe9D,CAAE,GACrB,QAAA,CAAS,QAAA,CACT,eAAA,CAAiB9D,CAAAA,CAAW,YAC9B,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,CAAA,CACF,CAEJ,ECtNO,IAAMyI,EAAAA,CAAwC,CAAC,CAAE,QAAA,CAAA3H,CAAAA,CAAU,SAAA,CAAA7B,EAAW,KAAA,CAAA6I,CAAM,CAAA,GAAM,CACvF,IAAMY,CAAAA,CAAYvM,gBAAAA,CAAWsL,EAAgB,CAAA,CAC7C,GAAI,CAACiB,CAAAA,CACH,MAAM,IAAI,MAAM,2CAA2C,CAAA,CAE7D,OACEnJ,cAAAA,CAAC,OACC,SAAA,CAAWN,CAAAA,CACX,KAAA,CAAO,CAAE,OAAQ,MAAA,CAAQ,UAAA,CAAY,MAAA,CAAQ,GAAG6I,CAAM,CAAA,CACrD,GAAGY,CAAAA,CAEH,QAAA,CAAA5H,EACH,CAEJ","file":"index.cjs","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\n/**\n * State context — holds reactive values that change during runtime.\n * All consumers of this context will re-render when any of these values change.\n */\nexport interface DashboardStateValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n}\n\n/**\n * Actions context — holds stable dispatch functions with permanent identity.\n * Consumers of only this context will never re-render from layout/drag state changes.\n */\nexport interface DashboardActionsValue {\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\nexport const DashboardStateContext = createContext<DashboardStateValue | undefined>(undefined)\nexport const DashboardActionsContext = createContext<DashboardActionsValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport {\n DashboardStateContext,\n DashboardActionsContext,\n DashboardStateValue,\n DashboardActionsValue,\n} from './context'\n\n/** Returns only reactive state. Use when you need layout, activeId, classNames, etc. */\nexport const useDashboardState = (): DashboardStateValue => {\n const state = useContext(DashboardStateContext)\n if (!state) {\n throw new Error('useDashboardState must be used within a DashboardProvider')\n }\n return state\n}\n\n/** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */\nexport const useDashboardActions = (): DashboardActionsValue => {\n const actions = useContext(DashboardActionsContext)\n if (!actions) {\n throw new Error('useDashboardActions must be used within a DashboardProvider')\n }\n return actions\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport {\n DashboardStateContext,\n DashboardActionsContext,\n ZeugmaClassNames,\n ResizerRenderProps,\n} 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\nclass SmartPointerSensor extends PointerSensor {\n static activators = [\n {\n eventName: 'onPointerDown' as const,\n handler: ({ nativeEvent: event }: { nativeEvent: PointerEvent }) => {\n const element = event.target as HTMLElement | null\n if (element?.closest('.drag-cancel')) {\n return false\n }\n return true\n },\n },\n ]\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [localLayout, setLocalLayout] = useState<TreeNode | null>(layout)\n const prevLayoutRef = useRef(layout)\n\n if (layout !== prevLayoutRef.current) {\n prevLayoutRef.current = layout\n setLocalLayout(layout)\n }\n\n const [activeId, setActiveId] = useState<string | null>(null)\n\n // Refs for stable closure access — prevents callback identity changes on every layout update\n const layoutRef = useRef(localLayout)\n layoutRef.current = localLayout\n\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n\n const renderPaneRef = useRef(renderPane)\n renderPaneRef.current = renderPane\n\n const onResizeEndPropRef = useRef(onResizeEnd)\n onResizeEndPropRef.current = onResizeEnd\n\n // Stable renderPane wrapper — immune to consumer passing inline functions\n const stableRenderPane = useCallback((paneId: string) => renderPaneRef.current(paneId), [])\n\n // Shallow-memoize classNames by individual fields to avoid identity busting from inline objects\n const stableClassNames = useMemo(\n () => classNames,\n [\n classNames.pane,\n classNames.dropPreview,\n classNames.swapPreview,\n classNames.dragOverlay,\n classNames.resizer,\n ],\n )\n\n const sensors = useSensors(\n useSensor(SmartPointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n localLayout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n const newLayout = swapPanes(localLayout, draggingId, targetId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(localLayout, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(localLayout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleLocalLayoutChange = useCallback((newLayout: TreeNode | null) => {\n setLocalLayout(newLayout)\n }, [])\n\n const handleRemovePane = useCallback((paneId: string) => {\n const newLayout = removePane(layoutRef.current, paneId)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleAddPane = useCallback((paneId: string) => {\n const newLayout = addPane(layoutRef.current, paneId)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleSwapPanes = useCallback((paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layoutRef.current, paneIdA, paneIdB)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(layoutRef.current, paneToAdd) ?? {\n type: 'pane',\n paneId: paneToAdd,\n }\n const treeWithoutDragging = removePane(layoutRef.current, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n },\n [],\n )\n\n const handleUpdateSplitPercentage = useCallback((currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layoutRef.current, currentNode, percentage)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layoutRef.current, paneId, updater)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n },\n [],\n )\n\n const handleResizeEnd = useCallback((currentNode: SplitNode, percentage: number) => {\n const finalLayout = updateSplitPercentage(layoutRef.current, currentNode, percentage)\n setLocalLayout(finalLayout)\n onChangeRef.current(finalLayout)\n if (onResizeEndPropRef.current) {\n onResizeEndPropRef.current(currentNode, percentage)\n }\n }, [])\n\n // State context — reactive values that change during runtime\n const stateValue = useMemo(\n () => ({\n layout: localLayout,\n onLayoutChange: handleLocalLayoutChange,\n renderPane: stableRenderPane,\n activeId,\n fullscreenPaneId,\n classNames: stableClassNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd: handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n }),\n [\n localLayout,\n activeId,\n fullscreenPaneId,\n stableClassNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n // Stable callbacks (empty deps) — included for exhaustive-deps lint rule\n handleLocalLayoutChange,\n stableRenderPane,\n handleResizeEnd,\n ],\n )\n\n // Actions context — stable dispatch functions that never change identity\n const actionsValue = useMemo(\n () => ({\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardActionsContext.Provider value={actionsValue}>\n <DashboardStateContext.Provider value={stateValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardStateContext.Provider>\n </DashboardActionsContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboardState } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboardState()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n\n // Imperatively update the sibling pane container flex sizes during drag\n const firstChild = container.children[0] as HTMLElement\n const secondChild = container.children[container.children.length - 1] as HTMLElement\n if (firstChild && secondChild) {\n firstChild.style.flex = `${finalPercentage} 1 0%`\n secondChild.style.flex = `${100 - finalPercentage} 1 0%`\n }\n\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n // Write to React state once resizing completes\n const newLayout = updateSplitPercentage(layout, currentNode, currentPercentage)\n console.log('onLayoutChange (finalized) called with percentage:', currentPercentage)\n onLayoutChange(newLayout)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboardState, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const {\n layout,\n onLayoutChange,\n classNames,\n renderResizer: contextRenderResizer,\n } = useDashboardState()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboardState()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (tree !== undefined || !activeId) return false\n return removePane(layout, activeId) !== null\n }, [tree, layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboardState, useDashboardActions } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: '25%',\n left: 0,\n width: '25%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: '25%',\n right: 0,\n width: '25%',\n height: '50%',\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 { layout, activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } =\n useDashboardState()\n const { removePane, updatePaneMetadata } = useDashboardActions()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = useMemo(\n () => ({\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }),\n [\n dragging,\n isFullscreen,\n onFullscreenChange,\n id,\n onRemove,\n removePane,\n metadata,\n updatePaneMetadata,\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
@@ -29,7 +29,11 @@ interface ResizerRenderProps {
29
29
  isResizing: boolean;
30
30
  onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void;
31
31
  }
32
- interface DashboardContextValue {
32
+ /**
33
+ * State context — holds reactive values that change during runtime.
34
+ * All consumers of this context will re-render when any of these values change.
35
+ */
36
+ interface DashboardStateValue {
33
37
  layout: TreeNode | null;
34
38
  onLayoutChange: (newLayout: TreeNode | null) => void;
35
39
  renderPane: (paneId: string) => ReactNode;
@@ -45,6 +49,12 @@ interface DashboardContextValue {
45
49
  renderResizer?: (props: ResizerRenderProps) => ReactNode;
46
50
  minSplitPercentage?: number;
47
51
  maxSplitPercentage?: number;
52
+ }
53
+ /**
54
+ * Actions context — holds stable dispatch functions with permanent identity.
55
+ * Consumers of only this context will never re-render from layout/drag state changes.
56
+ */
57
+ interface DashboardActionsValue {
48
58
  removePane: (paneId: string) => void;
49
59
  addPane: (paneId: string) => void;
50
60
  swapPanes: (paneIdA: string, paneIdB: string) => void;
@@ -53,7 +63,10 @@ interface DashboardContextValue {
53
63
  updatePaneMetadata: (paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
54
64
  }
55
65
 
56
- declare const useDashboard: () => DashboardContextValue;
66
+ /** Returns only reactive state. Use when you need layout, activeId, classNames, etc. */
67
+ declare const useDashboardState: () => DashboardStateValue;
68
+ /** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */
69
+ declare const useDashboardActions: () => DashboardActionsValue;
57
70
 
58
71
  interface DashboardProviderProps {
59
72
  layout: TreeNode | null;
@@ -168,4 +181,4 @@ declare function findPane(tree: TreeNode | null, paneId: string): PaneNode | nul
168
181
  */
169
182
  declare function updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null;
170
183
 
171
- export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboard, useResizer };
184
+ export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardActionsValue, DashboardProvider, type DashboardStateValue, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboardActions, useDashboardState, useResizer };
package/dist/index.d.ts CHANGED
@@ -29,7 +29,11 @@ interface ResizerRenderProps {
29
29
  isResizing: boolean;
30
30
  onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void;
31
31
  }
32
- interface DashboardContextValue {
32
+ /**
33
+ * State context — holds reactive values that change during runtime.
34
+ * All consumers of this context will re-render when any of these values change.
35
+ */
36
+ interface DashboardStateValue {
33
37
  layout: TreeNode | null;
34
38
  onLayoutChange: (newLayout: TreeNode | null) => void;
35
39
  renderPane: (paneId: string) => ReactNode;
@@ -45,6 +49,12 @@ interface DashboardContextValue {
45
49
  renderResizer?: (props: ResizerRenderProps) => ReactNode;
46
50
  minSplitPercentage?: number;
47
51
  maxSplitPercentage?: number;
52
+ }
53
+ /**
54
+ * Actions context — holds stable dispatch functions with permanent identity.
55
+ * Consumers of only this context will never re-render from layout/drag state changes.
56
+ */
57
+ interface DashboardActionsValue {
48
58
  removePane: (paneId: string) => void;
49
59
  addPane: (paneId: string) => void;
50
60
  swapPanes: (paneIdA: string, paneIdB: string) => void;
@@ -53,7 +63,10 @@ interface DashboardContextValue {
53
63
  updatePaneMetadata: (paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
54
64
  }
55
65
 
56
- declare const useDashboard: () => DashboardContextValue;
66
+ /** Returns only reactive state. Use when you need layout, activeId, classNames, etc. */
67
+ declare const useDashboardState: () => DashboardStateValue;
68
+ /** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */
69
+ declare const useDashboardActions: () => DashboardActionsValue;
57
70
 
58
71
  interface DashboardProviderProps {
59
72
  layout: TreeNode | null;
@@ -168,4 +181,4 @@ declare function findPane(tree: TreeNode | null, paneId: string): PaneNode | nul
168
181
  */
169
182
  declare function updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null;
170
183
 
171
- export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardContextValue, DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboard, useResizer };
184
+ export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, type DashboardActionsValue, DashboardProvider, type DashboardStateValue, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type ResizerRenderProps, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useDashboardActions, useDashboardState, useResizer };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import {createContext,useContext,useState,useCallback,useMemo,useRef,useEffect}from'react';import {useSensors,useSensor,DndContext,pointerWithin,useDraggable,PointerSensor,useDroppable}from'@dnd-kit/core';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var j=createContext(void 0);var C=()=>{let e=useContext(j);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function I(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=I(e.first,t),o=I(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function X(e,t,n,o,r){if(e===null)return typeof r=="string"?{type:"pane",paneId:r}:r;if(e.type==="pane"){if(e.paneId===t){let s=typeof r=="string"?{type:"pane",paneId:r}:r,a=o==="left"||o==="top";return {type:"split",direction:n,first:a?s:e,second:a?e:s,splitPercentage:50}}return e}return {...e,first:X(e.first,t,n,o,r)||e.first,second:X(e.second,t,n,o,r)||e.second}}function se(e,t,n){if(e===null)return null;let o=y(e,t),r=y(e,n);if(!o||!r)return e;function s(a){return a.type==="pane"?a.paneId===t?{...r}:a.paneId===n?{...o}:a:{...a,first:s(a.first),second:s(a.second)}}return s(e)}function ve(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 Z(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:Z(e.first,t,n)||e.first,second:Z(e.second,t,n)||e.second}:e}function he(e,t,n){let o=y(e,t)??{type:"pane",paneId:t},r=I(e,t);if(r===null)return {...o};let s=n==="left"||n==="right"?"row":"column",a=n==="left"||n==="top",f={...o};return {type:"split",direction:s,first:a?f:r,second:a?r:f,splitPercentage:50}}function y(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:y(e.first,t)??y(e.second,t)}function ee(e,t,n){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let o=n(e.metadata);if(o===void 0){let{metadata:r,...s}=e;return s}return {...e,metadata:o}}return e}return {...e,first:ee(e.first,t,n)??e.first,second:ee(e.second,t,n)??e.second}}var ye=8,ze=8,mt=4;var Ae=({activeId:e,render:t,className:n})=>{let o=useRef(null);return useEffect(()=>{let r=s=>{o.current&&(o.current.style.transform=`translate(${s.clientX+12}px, ${s.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)})},de=class extends PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},He=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:s=null,onFullscreenChange:a,onRemove:f,dragActivationDistance:x=8,snapThreshold:P=8,onDragStart:b,onDragEnd:l,onResizeStart:u,onResize:h,onResizeEnd:D,renderResizer:R,minSplitPercentage:v=5,maxSplitPercentage:S=95,children:A})=>{let[i,g]=useState(e),[$,w]=useState(e);e!==$&&(g(e),w(e));let[T,ne]=useState(null),re=useSensors(useSensor(de,{activationConstraint:{distance:x}})),G=p=>{let d=p.active.id.toString();ne(d),b&&b(d);},q=p=>{ne(null);let{active:d,over:c}=p,m=d.id.toString();if(!c){l&&l(m,null,null);return}let V=c.id.toString(),K=V.match(/^drop-root-(left|right|top|bottom)$/);if(K){let[,L]=K,W=he(i,m,L);g(W),t(W),l&&l(m,"root",{type:"split",direction:L==="left"||L==="right"?"row":"column",position:L});return}let B=V.match(/^drop-center-(.+)$/);if(B){let[,L]=B;if(m!==L){let W=se(i,m,L);g(W),t(W);}l&&l(m,L,{type:"swap",position:"center"});return}let fe=V.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!fe){l&&l(m,null,null);return}let[,Q,ie]=fe;if(m===ie){l&&l(m,null,null);return}let me=Q==="left"||Q==="right"?"row":"column",xe=y(i,m)??{type:"pane",paneId:m},Se=I(i,m),ge=X(Se,ie,me,Q,xe);g(ge),t(ge),l&&l(m,ie,{type:"split",direction:me,position:Q});},_=useCallback(p=>{g(p);},[]),N=useCallback(p=>{let d=I(i,p);g(d),t(d);},[i,t]),z=useCallback(p=>{let d=ve(i,p);g(d),t(d);},[i,t]),H=useCallback((p,d)=>{let c=se(i,p,d);g(c),t(c);},[i,t]),J=useCallback((p,d,c,m)=>{let V=y(i,m)??{type:"pane",paneId:m},K=I(i,m),B=X(K,p,d,c,V);g(B),t(B);},[i,t]),k=useCallback((p,d)=>{let c=Z(i,p,d);g(c),t(c);},[i,t]),F=useCallback((p,d)=>{let c=ee(i,p,d);g(c),t(c);},[i,t]),O=useCallback((p,d)=>{let c=Z(i,p,d);g(c),t(c),D&&D(p,d);},[i,t,D]),U=useMemo(()=>({layout:i,onLayoutChange:_,renderPane:n,activeId:T,fullscreenPaneId:s,classNames:r,onRemove:f,onFullscreenChange:a,snapThreshold:P,onResizeStart:u,onResize:h,onResizeEnd:O,renderResizer:R,minSplitPercentage:v,maxSplitPercentage:S,removePane:N,addPane:z,swapPanes:H,splitPane:J,updateSplitPercentage:k,updatePaneMetadata:F}),[i,_,n,T,s,r,f,a,P,u,h,O,R,v,S,N,z,H,J,k,F]);return jsxs(j.Provider,{value:U,children:[jsx(DndContext,{id:"zeugma-dnd-context",sensors:re,collisionDetection:pointerWithin,onDragStart:G,onDragEnd:q,children:A}),T&&o&&jsx(Ae,{activeId:T,render:o,className:r.dragOverlay})]})};var ke={top:{position:"absolute",top:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"32px",zIndex:30,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"32px",zIndex:30,pointerEvents:"auto"}},Oe={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"}},Ue=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:o,style:ke[t]}),r&&jsx("div",{className:n,style:Oe[t]})]})},Pe=({activeId:e,hasOtherPanes:t,dropPreviewClassName:n})=>!e||!t?null:jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:30,pointerEvents:"none"},children:["top","bottom","left","right"].map(o=>jsx(Ue,{id:`drop-root-${o}`,position:o,activeClassName:n},o))});function pe({containerRef:e,isRow:t,direction:n,splitPercentage:o,resizerSize:r,snapThreshold:s,layout:a,currentNode:f,onLayoutChange:x,onResizeStart:P,onResizeEnd:b}){let{onResizeStart:l,onResize:u,onResizeEnd:h,minSplitPercentage:D=5,maxSplitPercentage:R=95}=C();return useCallback(v=>{v.preventDefault();let S=e.current;if(!S)return;document.body.classList.add("zeugma-resizing");let A=document.createElement("style");A.id="zeugma-global-cursor-style",A.textContent=`
1
+ import {createContext,useContext,useState,useRef,useCallback,useMemo,useEffect}from'react';import {useSensors,useSensor,DndContext,pointerWithin,useDraggable,PointerSensor,useDroppable}from'@dnd-kit/core';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var ie=createContext(void 0),se=createContext(void 0);var M=()=>{let e=useContext(ie);if(!e)throw new Error("useDashboardState must be used within a DashboardProvider");return e},fe=()=>{let e=useContext(se);if(!e)throw new Error("useDashboardActions must be used within a DashboardProvider");return e};function E(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let r=E(e.first,t),n=E(e.second,t);return r===null?n:n===null?r:{...e,first:r,second:n}}function te(e,t,r,n,o){if(e===null)return typeof o=="string"?{type:"pane",paneId:o}:o;if(e.type==="pane"){if(e.paneId===t){let i=typeof o=="string"?{type:"pane",paneId:o}:o,s=n==="left"||n==="top";return {type:"split",direction:r,first:s?i:e,second:s?e:i,splitPercentage:50}}return e}return {...e,first:te(e.first,t,r,n,o)||e.first,second:te(e.second,t,r,n,o)||e.second}}function ge(e,t,r){if(e===null)return null;let n=I(e,t),o=I(e,r);if(!n||!o)return e;function i(s){return s.type==="pane"?s.paneId===t?{...o}:s.paneId===r?{...n}:s:{...s,first:i(s.first),second:i(s.second)}}return i(e)}function ye(e,t){if(e===null)return {type:"pane",paneId:t};function r(n,o){return n.type==="pane"?{type:"split",direction:o==="row"?"column":"row",splitPercentage:50,first:n,second:{type:"pane",paneId:t}}:{...n,second:r(n.second,n.direction)}}return r(e,null)}function $(e,t,r){return e===null?null:e===t?{...e,splitPercentage:r}:e.type==="split"?{...e,first:$(e.first,t,r)||e.first,second:$(e.second,t,r)||e.second}:e}function ze(e,t,r){let n=I(e,t)??{type:"pane",paneId:t},o=E(e,t);if(o===null)return {...n};let i=r==="left"||r==="right"?"row":"column",s=r==="left"||r==="top",p={...n};return {type:"split",direction:i,first:s?p:o,second:s?o:p,splitPercentage:50}}function I(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:I(e.first,t)??I(e.second,t)}function ae(e,t,r){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let n=r(e.metadata);if(n===void 0){let{metadata:o,...i}=e;return i}return {...e,metadata:n}}return e}return {...e,first:ae(e.first,t,r)??e.first,second:ae(e.second,t,r)??e.second}}var Ze=8,He=8,Dt=4;var Be=({activeId:e,render:t,className:r})=>{let n=useRef(null);return useEffect(()=>{let o=i=>{n.current&&(n.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",o),()=>document.removeEventListener("pointermove",o)},[]),jsx("div",{ref:n,className:r,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},he=class extends PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},We=({layout:e,onChange:t,renderPane:r,renderDragOverlay:n,classNames:o={},fullscreenPaneId:i=null,onFullscreenChange:s,onRemove:p,dragActivationDistance:x=8,snapThreshold:b=8,onDragStart:P,onDragEnd:a,onResizeStart:u,onResize:R,onResizeEnd:C,renderResizer:N,minSplitPercentage:g=5,maxSplitPercentage:m=95,children:V})=>{let[d,h]=useState(e),O=useRef(e);e!==O.current&&(O.current=e,h(e));let[S,_]=useState(null),w=useRef(d);w.current=d;let y=useRef(t);y.current=t;let F=useRef(r);F.current=r;let k=useRef(C);k.current=C;let W=useCallback(l=>F.current(l),[]),D=useMemo(()=>o,[o.pane,o.dropPreview,o.swapPreview,o.dragOverlay,o.resizer]),z=useSensors(useSensor(he,{activationConstraint:{distance:x}})),X=l=>{let c=l.active.id.toString();_(c),P&&P(c);},pe=l=>{_(null);let{active:c,over:v}=l,f=c.id.toString();if(!v){a&&a(f,null,null);return}let Q=v.id.toString(),oe=Q.match(/^drop-root-(left|right|top|bottom)$/);if(oe){let[,A]=oe,ee=ze(d,f,A);h(ee),t(ee),a&&a(f,"root",{type:"split",direction:A==="left"||A==="right"?"row":"column",position:A});return}let j=Q.match(/^drop-center-(.+)$/);if(j){let[,A]=j;if(f!==A){let ee=ge(d,f,A);h(ee),t(ee);}a&&a(f,A,{type:"swap",position:"center"});return}let xe=Q.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!xe){a&&a(f,null,null);return}let[,re,ue]=xe;if(f===ue){a&&a(f,null,null);return}let Ne=re==="left"||re==="right"?"row":"column",Me=I(d,f)??{type:"pane",paneId:f},Fe=E(d,f),Se=te(Fe,ue,Ne,re,Me);h(Se),t(Se),a&&a(f,ue,{type:"split",direction:Ne,position:re});},Y=useCallback(l=>{h(l);},[]),Z=useCallback(l=>{let c=E(w.current,l);h(c),y.current(c);},[]),G=useCallback(l=>{let c=ye(w.current,l);h(c),y.current(c);},[]),H=useCallback((l,c)=>{let v=ge(w.current,l,c);h(v),y.current(v);},[]),q=useCallback((l,c,v,f)=>{let Q=I(w.current,f)??{type:"pane",paneId:f},oe=E(w.current,f),j=te(oe,l,c,v,Q);h(j),y.current(j);},[]),J=useCallback((l,c)=>{let v=$(w.current,l,c);h(v),y.current(v);},[]),K=useCallback((l,c)=>{let v=ae(w.current,l,c);h(v),y.current(v);},[]),U=useCallback((l,c)=>{let v=$(w.current,l,c);h(v),y.current(v),k.current&&k.current(l,c);},[]),Le=useMemo(()=>({layout:d,onLayoutChange:Y,renderPane:W,activeId:S,fullscreenPaneId:i,classNames:D,onRemove:p,onFullscreenChange:s,snapThreshold:b,onResizeStart:u,onResize:R,onResizeEnd:U,renderResizer:N,minSplitPercentage:g,maxSplitPercentage:m}),[d,S,i,D,p,s,b,u,R,N,g,m,Y,W,U]),Ae=useMemo(()=>({removePane:Z,addPane:G,swapPanes:H,splitPane:q,updateSplitPercentage:J,updatePaneMetadata:K}),[Z,G,H,q,J,K]);return jsx(se.Provider,{value:Ae,children:jsxs(ie.Provider,{value:Le,children:[jsx(DndContext,{id:"zeugma-dnd-context",sensors:z,collisionDetection:pointerWithin,onDragStart:X,onDragEnd:pe,children:V}),S&&n&&jsx(Be,{activeId:S,render:n,className:o.dragOverlay})]})})};var Ge={top:{position:"absolute",top:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"32px",zIndex:30,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"32px",zIndex:30,pointerEvents:"auto"}},qe={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"}},Je=({id:e,position:t,activeClassName:r})=>{let{setNodeRef:n,isOver:o}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:n,style:Ge[t]}),o&&jsx("div",{className:r,style:qe[t]})]})},Ce=({activeId:e,hasOtherPanes:t,dropPreviewClassName:r})=>!e||!t?null:jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:30,pointerEvents:"none"},children:["top","bottom","left","right"].map(n=>jsx(Je,{id:`drop-root-${n}`,position:n,activeClassName:r},n))});function ve({containerRef:e,isRow:t,direction:r,splitPercentage:n,resizerSize:o,snapThreshold:i,layout:s,currentNode:p,onLayoutChange:x,onResizeStart:b,onResizeEnd:P}){let{onResizeStart:a,onResize:u,onResizeEnd:R,minSplitPercentage:C=5,maxSplitPercentage:N=95}=M();return useCallback(g=>{g.preventDefault();let m=e.current;if(!m)return;document.body.classList.add("zeugma-resizing");let V=document.createElement("style");V.id="zeugma-global-cursor-style",V.textContent=`
2
2
  * {
3
3
  cursor: ${t?"col-resize":"row-resize"} !important;
4
4
  user-select: none !important;
5
5
  }
6
- `,document.head.appendChild(A),P&&P(),l&&l(f);let i=S.getBoundingClientRect(),g=v.clientX,$=v.clientY,w=o,T=v.currentTarget;T.setAttribute("data-resizing","true");let re=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(N=>N!==T&&N.getAttribute("data-direction")===n).map(N=>{let z=N.getBoundingClientRect();return t?z.left+z.width/2:z.top+z.height/2}),G=w,q=N=>{let z=t?(N.clientX-g)/i.width*100:(N.clientY-$)/i.height*100,H=w+z,J=t?i.left+(i.width-r)*(H/100)+r/2:i.top+(i.height-r)*(H/100)+r/2,k=1/0,F=null;for(let d of re){let c=Math.abs(J-d);c<s&&c<k&&(k=c,F=d);}let O=H;F!==null&&(O=t?(F-r/2-i.left)/(i.width-r)*100:(F-r/2-i.top)/(i.height-r)*100);let U=Math.max(D,Math.min(R,O));G=U;let p=Z(a,f,U);x(p),u&&u(f,U);},_=()=>{document.body.classList.remove("zeugma-resizing"),T.removeAttribute("data-resizing");let N=document.getElementById("zeugma-global-cursor-style");N&&N.remove(),document.removeEventListener("pointermove",q),document.removeEventListener("pointerup",_),b&&b(),h&&h(f,G);};document.addEventListener("pointermove",q),document.addEventListener("pointerup",_);},[e,t,n,o,r,s,a,f,x,P,b,l,u,h,D,R])}var qe=({currentNode:e,resizerSize:t,snapThreshold:n,renderResizer:o})=>{let{layout:r,onLayoutChange:s,classNames:a,renderResizer:f}=C(),[x,P]=useState(false),b=o||f,l=useRef(null),{direction:u,first:h,second:D,splitPercentage:R}=e,v=u==="row",S=pe({containerRef:l,isRow:v,direction:u,splitPercentage:R,resizerSize:t,snapThreshold:n??8,layout:r,currentNode:e,onLayoutChange:s,onResizeStart:()=>P(true),onResizeEnd:()=>P(false)});return jsxs("div",{ref:l,style:{display:"flex",flexDirection:v?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${R} 1 0%`,overflow:"hidden"},children:jsx(ce,{tree:h,resizerSize:t,snapThreshold:n,renderResizer:o})}),b?b({direction:u,splitPercentage:R,resizerSize:t,isResizing:x,onPointerDown:S}):jsx("div",{className:a.resizer,"data-direction":u,style:{width:v?`${t}px`:"100%",height:v?"100%":`${t}px`,cursor:v?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:S,role:"separator","aria-valuenow":R,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-R} 1 0%`,overflow:"hidden"},children:jsx(ce,{tree:D,resizerSize:t,snapThreshold:n,renderResizer:o})})]})},ce=({tree:e,resizerSize:t=4,snapThreshold:n,renderResizer:o})=>{let{layout:r,renderPane:s,activeId:a,classNames:f,fullscreenPaneId:x,snapThreshold:P}=C(),b=n!==void 0?n:P,l=useMemo(()=>a?I(r,a)!==null:false,[r,a]);if(x&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:s(x)});let u=e!==void 0?e:r;if(!u)return null;let h=()=>u.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:s(u.paneId)}):jsx(qe,{currentNode:u,resizerSize:t,snapThreshold:b,renderResizer:o});return e===void 0?jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[h(),jsx(Pe,{activeId:a,hasOtherPanes:l,dropPreviewClassName:f.dropPreview})]}):h()};var oe=createContext(null);var je={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"}},et={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"}},Ne=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:o,style:je[t]}),r&&jsx("div",{className:n,style:et[t]})]})},tt=({id:e,children:t,style:n})=>{let{layout:o,activeId:r,classNames:s,fullscreenPaneId:a,onRemove:f,onFullscreenChange:x,removePane:P,updatePaneMetadata:b}=C(),l=r!==null&&r!==e,{attributes:u,listeners:h,setNodeRef:D,isDragging:R}=useDraggable({id:e}),v=r===e||R,S=a===e,i=useMemo(()=>y(o,e),[o,e])?.metadata,g={isDragging:v,isFullscreen:S,toggleFullscreen:()=>x?.(S?null:e),remove:()=>{S&&x?.(null),f?f(e):P(e);},metadata:i,updateMetadata:w=>{b(e,w);}},$=useMemo(()=>({...h,...u}),[h,u]);return jsx(oe.Provider,{value:$,children:jsxs("div",{ref:D,className:s.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(g),l&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(w=>jsx(Ne,{id:`drop-${w}-${e}`,position:w,activeClassName:s.dropPreview},w)),jsx(Ne,{id:`drop-center-${e}`,position:"center",activeClassName:s.swapPreview})]})]})})};var rt=({children:e,className:t,style:n})=>{let o=useContext(oe);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{ze as DEFAULT_DRAG_ACTIVATION_DISTANCE,mt as DEFAULT_RESIZER_SIZE,ye as DEFAULT_SNAP_THRESHOLD,He as DashboardProvider,rt as DragHandle,tt as Pane,ce as PaneTree,ve as addPane,y as findPane,I as removePane,X as splitPane,he as splitRoot,se as swapPanes,ee as updatePaneMetadata,Z as updateSplitPercentage,C as useDashboard,pe as useResizer};//# sourceMappingURL=index.js.map
6
+ `,document.head.appendChild(V),b&&b(),a&&a(p);let d=m.getBoundingClientRect(),h=g.clientX,O=g.clientY,S=n,_=g.currentTarget;_.setAttribute("data-resizing","true");let y=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(D=>D!==_&&D.getAttribute("data-direction")===r).map(D=>{let z=D.getBoundingClientRect();return t?z.left+z.width/2:z.top+z.height/2}),F=S,k=D=>{let z=t?(D.clientX-h)/d.width*100:(D.clientY-O)/d.height*100,X=S+z,pe=t?d.left+(d.width-o)*(X/100)+o/2:d.top+(d.height-o)*(X/100)+o/2,Y=1/0,Z=null;for(let K of y){let U=Math.abs(pe-K);U<i&&U<Y&&(Y=U,Z=K);}let G=X;Z!==null&&(G=t?(Z-o/2-d.left)/(d.width-o)*100:(Z-o/2-d.top)/(d.height-o)*100);let H=Math.max(C,Math.min(N,G));F=H;let q=m.children[0],J=m.children[m.children.length-1];q&&J&&(q.style.flex=`${H} 1 0%`,J.style.flex=`${100-H} 1 0%`),u&&u(p,H);},W=()=>{document.body.classList.remove("zeugma-resizing"),_.removeAttribute("data-resizing");let D=document.getElementById("zeugma-global-cursor-style");D&&D.remove(),document.removeEventListener("pointermove",k),document.removeEventListener("pointerup",W);let z=$(s,p,F);console.log("onLayoutChange (finalized) called with percentage:",F),x(z),P&&P(),R&&R(p,F);};document.addEventListener("pointermove",k),document.addEventListener("pointerup",W);},[e,t,r,n,o,i,s,p,x,b,P,a,u,R,C,N])}var ot=({currentNode:e,resizerSize:t,snapThreshold:r,renderResizer:n})=>{let{layout:o,onLayoutChange:i,classNames:s,renderResizer:p}=M(),[x,b]=useState(false),P=n||p,a=useRef(null),{direction:u,first:R,second:C,splitPercentage:N}=e,g=u==="row",m=ve({containerRef:a,isRow:g,direction:u,splitPercentage:N,resizerSize:t,snapThreshold:r??8,layout:o,currentNode:e,onLayoutChange:i,onResizeStart:()=>b(true),onResizeEnd:()=>b(false)});return jsxs("div",{ref:a,style:{display:"flex",flexDirection:g?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${N} 1 0%`,overflow:"hidden"},children:jsx(be,{tree:R,resizerSize:t,snapThreshold:r,renderResizer:n})}),P?P({direction:u,splitPercentage:N,resizerSize:t,isResizing:x,onPointerDown:m}):jsx("div",{className:s.resizer,"data-direction":u,style:{width:g?`${t}px`:"100%",height:g?"100%":`${t}px`,cursor:g?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:m,role:"separator","aria-valuenow":N,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-N} 1 0%`,overflow:"hidden"},children:jsx(be,{tree:C,resizerSize:t,snapThreshold:r,renderResizer:n})})]})},be=({tree:e,resizerSize:t=4,snapThreshold:r,renderResizer:n})=>{let{layout:o,renderPane:i,activeId:s,classNames:p,fullscreenPaneId:x,snapThreshold:b}=M(),P=r!==void 0?r:b,a=useMemo(()=>e!==void 0||!s?false:E(o,s)!==null,[e,o,s]);if(x&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(x)});let u=e!==void 0?e:o;if(!u)return null;let R=()=>u.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:i(u.paneId)}):jsx(ot,{currentNode:u,resizerSize:t,snapThreshold:P,renderResizer:n});return e===void 0?jsxs("div",{className:"zeugma-dashboard-root",style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[R(),jsx(Ce,{activeId:s,hasOtherPanes:a,dropPreviewClassName:p.dropPreview})]}):R()};var ce=createContext(null);var at={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:"25%",left:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:"25%",right:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},dt={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"}},Te=({id:e,position:t,activeClassName:r})=>{let{setNodeRef:n,isOver:o}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:n,style:at[t]}),o&&jsx("div",{className:r,style:dt[t]})]})},lt=({id:e,children:t,style:r})=>{let{layout:n,activeId:o,classNames:i,fullscreenPaneId:s,onRemove:p,onFullscreenChange:x}=M(),{removePane:b,updatePaneMetadata:P}=fe(),a=o!==null&&o!==e,{attributes:u,listeners:R,setNodeRef:C,isDragging:N}=useDraggable({id:e}),g=o===e||N,m=s===e,d=useMemo(()=>I(n,e),[n,e])?.metadata,h=useMemo(()=>({isDragging:g,isFullscreen:m,toggleFullscreen:()=>x?.(m?null:e),remove:()=>{m&&x?.(null),p?p(e):b(e);},metadata:d,updateMetadata:S=>{P(e,S);}}),[g,m,x,e,p,b,d,P]),O=useMemo(()=>({...R,...u}),[R,u]);return jsx(ce.Provider,{value:O,children:jsxs("div",{ref:C,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...r},children:[t(h),a&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(S=>jsx(Te,{id:`drop-${S}-${e}`,position:S,activeClassName:i.dropPreview},S)),jsx(Te,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var ut=({children:e,className:t,style:r})=>{let n=useContext(ce);if(!n)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...r},...n,children:e})};export{He as DEFAULT_DRAG_ACTIVATION_DISTANCE,Dt as DEFAULT_RESIZER_SIZE,Ze as DEFAULT_SNAP_THRESHOLD,We as DashboardProvider,ut as DragHandle,lt as Pane,be as PaneTree,ye as addPane,I as findPane,E as removePane,te as splitPane,ze as splitRoot,ge as swapPanes,ae as updatePaneMetadata,$ as updateSplitPercentage,fe as useDashboardActions,M as useDashboardState,ve as useResizer};//# sourceMappingURL=index.js.map
7
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","SmartPointerSensor","PointerSensor","event","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","localLayout","setLocalLayout","useState","prevLayout","setPrevLayout","setActiveId","sensors","useSensors","useSensor","handleDragStart","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleLocalLayoutChange","useCallback","handleRemovePane","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","handleResizeEnd","finalLayout","contextValue","useMemo","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport { DashboardContext } from './context'\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport { DashboardContext, ZeugmaClassNames, ResizerRenderProps } from '../model/context'\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\nclass SmartPointerSensor extends PointerSensor {\n static activators = [\n {\n eventName: 'onPointerDown' as const,\n handler: ({ nativeEvent: event }: { nativeEvent: PointerEvent }) => {\n const element = event.target as HTMLElement | null\n if (element?.closest('.drag-cancel')) {\n return false\n }\n return true\n },\n },\n ]\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [localLayout, setLocalLayout] = useState<TreeNode | null>(layout)\n const [prevLayout, setPrevLayout] = useState<TreeNode | null>(layout)\n\n if (layout !== prevLayout) {\n setLocalLayout(layout)\n setPrevLayout(layout)\n }\n\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(SmartPointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n localLayout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n const newLayout = swapPanes(localLayout, draggingId, targetId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(localLayout, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(localLayout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleLocalLayoutChange = useCallback((newLayout: TreeNode | null) => {\n setLocalLayout(newLayout)\n }, [])\n\n const handleRemovePane = useCallback(\n (paneId: string) => {\n const newLayout = removePane(localLayout, paneId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleAddPane = useCallback(\n (paneId: string) => {\n const newLayout = addPane(localLayout, paneId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleSwapPanes = useCallback(\n (paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(localLayout, paneIdA, paneIdB)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(localLayout, paneToAdd) ?? {\n type: 'pane',\n paneId: paneToAdd,\n }\n const treeWithoutDragging = removePane(localLayout, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleUpdateSplitPercentage = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(localLayout, currentNode, percentage)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(localLayout, paneId, updater)\n setLocalLayout(newLayout)\n onChange(newLayout)\n },\n [localLayout, onChange],\n )\n\n const handleResizeEnd = useCallback(\n (currentNode: SplitNode, percentage: number) => {\n const finalLayout = updateSplitPercentage(localLayout, currentNode, percentage)\n setLocalLayout(finalLayout)\n onChange(finalLayout)\n if (onResizeEnd) {\n onResizeEnd(currentNode, percentage)\n }\n },\n [localLayout, onChange, onResizeEnd],\n )\n\n // Best practice: Memoize context value to prevent unnecessary re-renders of context consumers.\n const contextValue = useMemo(\n () => ({\n layout: localLayout,\n onLayoutChange: handleLocalLayoutChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd: handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n localLayout,\n handleLocalLayoutChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardContext.Provider value={contextValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboard } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboard()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n const newLayout = updateSplitPercentage(layout, currentNode, finalPercentage)\n onLayoutChange(newLayout)\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboard, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const { layout, onLayoutChange, classNames, renderResizer: contextRenderResizer } = useDashboard()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboard()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (!activeId) return false\n return removePane(layout, activeId) !== null\n }, [layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const {\n layout,\n activeId,\n classNames,\n fullscreenPaneId,\n onRemove,\n onFullscreenChange,\n removePane,\n updatePaneMetadata,\n } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }\n\n // Best practice: Memoize drag context value to prevent unnecessary re-renders of the drag handle.\n const contextValue = useMemo(\n () => ({\n ...listeners,\n ...attributes,\n }),\n [listeners, attributes],\n )\n\n return (\n <DragListenersCtx.Provider value={contextValue}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n","import React, { useContext } from 'react'\nimport { DragListenersCtx } from '../model/context'\n\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/entities/dashboard/model/context.ts","../src/entities/dashboard/model/hooks.ts","../src/shared/lib/tree/tree-helpers.ts","../src/shared/config/constants.ts","../src/entities/dashboard/ui/DashboardProvider.tsx","../src/entities/dashboard/ui/RootDropZone.tsx","../src/features/resize-pane/hooks/useResizer.ts","../src/widgets/pane-tree/ui/PaneTree.tsx","../src/entities/pane/model/context.ts","../src/entities/pane/ui/Pane.tsx","../src/entities/pane/ui/DragHandle.tsx"],"names":["DashboardStateContext","createContext","DashboardActionsContext","useDashboardState","state","useContext","useDashboardActions","actions","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","swapPanes","idA","idB","nodeA","findPane","nodeB","swap","node","addPane","insert","parentDirection","updateSplitPercentage","target","newPercentage","splitRoot","draggingId","draggedPaneNode","treeWithoutDragging","draggedNode","paneId","updatePaneMetadata","updater","newMetadata","_","rest","DEFAULT_SNAP_THRESHOLD","DEFAULT_DRAG_ACTIVATION_DISTANCE","DEFAULT_RESIZER_SIZE","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","SmartPointerSensor","PointerSensor","event","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","snapThreshold","onDragStart","onDragEnd","onResizeStart","onResize","onResizeEnd","renderResizer","minSplitPercentage","maxSplitPercentage","children","localLayout","setLocalLayout","useState","prevLayoutRef","setActiveId","layoutRef","onChangeRef","renderPaneRef","onResizeEndPropRef","stableRenderPane","useCallback","stableClassNames","useMemo","sensors","useSensors","useSensor","handleDragStart","handleDragEnd","active","over","overIdStr","rootMatch","dropZone","newLayout","swapMatch","match","handleLocalLayoutChange","handleRemovePane","handleAddPane","handleSwapPanes","paneIdA","paneIdB","handleSplitPane","handleUpdateSplitPercentage","currentNode","percentage","handleUpdatePaneMetadata","handleResizeEnd","finalLayout","stateValue","actionsValue","jsxs","DndContext","pointerWithin","rootActivationPositions","rootPreviewPositions","RootDropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","RootDropZones","hasOtherPanes","dropPreviewClassName","pos","useResizer","containerRef","isRow","splitPercentage","resizerSize","onLayoutChange","localOnResizeStart","localOnResizeEnd","globalOnResizeStart","globalOnResize","globalOnResizeEnd","container","styleEl","rect","startX","startY","startPercentage","resizerEl","otherPositions","el","r","currentPercentage","handlePointerMove","moveEvent","delta","proposedPercentage","proposedPos","closestDistance","bestTarget","dist","snappedPercentage","finalPercentage","firstChild","secondChild","handlePointerUp","globalStyle","PaneSplit","propRenderResizer","contextRenderResizer","isResizing","setIsResizing","first","second","handlePointerDown","PaneTree","propSnapThreshold","contextSnapThreshold","renderContent","DragListenersCtx","activationPositions","previewPositions","DropZone","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","metadata","renderProps","contextValue","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, ReactNode } from 'react'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface ResizerRenderProps {\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n isResizing: boolean\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void\n}\n\n/**\n * State context — holds reactive values that change during runtime.\n * All consumers of this context will re-render when any of these values change.\n */\nexport interface DashboardStateValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n snapThreshold?: number\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n}\n\n/**\n * Actions context — holds stable dispatch functions with permanent identity.\n * Consumers of only this context will never re-render from layout/drag state changes.\n */\nexport interface DashboardActionsValue {\n removePane: (paneId: string) => void\n addPane: (paneId: string) => void\n swapPanes: (paneIdA: string, paneIdB: string) => void\n splitPane: (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => void\n updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void\n updatePaneMetadata: (\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n ) => void\n}\nexport const DashboardStateContext = createContext<DashboardStateValue | undefined>(undefined)\nexport const DashboardActionsContext = createContext<DashboardActionsValue | undefined>(undefined)\n","import { useContext } from 'react'\nimport {\n DashboardStateContext,\n DashboardActionsContext,\n DashboardStateValue,\n DashboardActionsValue,\n} from './context'\n\n/** Returns only reactive state. Use when you need layout, activeId, classNames, etc. */\nexport const useDashboardState = (): DashboardStateValue => {\n const state = useContext(DashboardStateContext)\n if (!state) {\n throw new Error('useDashboardState must be used within a DashboardProvider')\n }\n return state\n}\n\n/** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */\nexport const useDashboardActions = (): DashboardActionsValue => {\n const actions = useContext(DashboardActionsContext)\n if (!actions) {\n throw new Error('useDashboardActions must be used within a DashboardProvider')\n }\n return actions\n}\n","import { TreeNode, SplitNode, SplitDirection, PaneNode } from '../../model'\n\n/**\n * Tree Helper: Remove a pane and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n/**\n * Tree Helper: Insert a pane by splitting an existing target node.\n */\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string | PaneNode,\n): TreeNode | null {\n if (tree === null) {\n return typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string' ? { type: 'pane', paneId: paneToAdd } : paneToAdd\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : tree,\n second: isFirst ? tree : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n/**\n * Tree Helper: Swap the position of two panes in the tree structure.\n */\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n\n // First pass: collect the full PaneNode references\n const nodeA = findPane(tree, idA)\n const nodeB = findPane(tree, idB)\n if (!nodeA || !nodeB) return tree\n\n // Second pass: replace each location with the other node\n function swap(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.paneId === idA) return { ...nodeB! }\n if (node.paneId === idB) return { ...nodeA! }\n return node\n }\n return {\n ...node,\n first: swap(node.first),\n second: swap(node.second),\n }\n }\n\n return swap(tree)\n}\n\n/**\n * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/**\n * Tree Helper: Update split percentage recursively.\n */\nexport function updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\n/**\n * Tree Helper: Split the entire tree at the root using a dragged pane.\n */\nexport function splitRoot(\n tree: TreeNode | null,\n draggingId: string,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n): TreeNode | null {\n // Preserve dragged pane's metadata\n const draggedPaneNode: PaneNode = findPane(tree, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(tree, draggingId)\n if (treeWithoutDragging === null) {\n return { ...draggedPaneNode }\n }\n\n const direction: SplitDirection = splitType === 'left' || splitType === 'right' ? 'row' : 'column'\n const isFirst = splitType === 'left' || splitType === 'top'\n const draggedNode: TreeNode = { ...draggedPaneNode }\n\n return {\n type: 'split',\n direction,\n first: isFirst ? draggedNode : treeWithoutDragging,\n second: isFirst ? treeWithoutDragging : draggedNode,\n splitPercentage: 50,\n }\n}\n\n/**\n * Find a PaneNode by its paneId.\n */\nexport function findPane(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === paneId ? tree : null\n }\n return findPane(tree.first, paneId) ?? findPane(tree.second, paneId)\n}\n\n/**\n * Update metadata on a specific pane node using an updater function.\n */\nexport function updatePaneMetadata(\n tree: TreeNode | null,\n paneId: string,\n updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === paneId) {\n const newMetadata = updater(tree.metadata)\n if (newMetadata === undefined) {\n // Remove metadata key\n const { metadata: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, metadata: newMetadata }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneMetadata(tree.first, paneId, updater) ?? tree.first,\n second: updatePaneMetadata(tree.second, paneId, updater) ?? tree.second,\n }\n}\n","export const DEFAULT_SNAP_THRESHOLD = 8 // px\nexport const DEFAULT_DRAG_ACTIVATION_DISTANCE = 8 // px\nexport const DEFAULT_RESIZER_SIZE = 4 // px\n","import React, { useState, useEffect, useRef, ReactNode, useMemo, useCallback } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, SplitNode } from '../../../shared/model'\nimport {\n removePane,\n splitPane,\n swapPanes,\n addPane,\n updateSplitPercentage,\n splitRoot,\n updatePaneMetadata,\n findPane,\n} from '../../../shared/lib/tree'\nimport { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_SNAP_THRESHOLD } from '../../../shared/config'\nimport {\n DashboardStateContext,\n DashboardActionsContext,\n ZeugmaClassNames,\n ResizerRenderProps,\n} 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\nclass SmartPointerSensor extends PointerSensor {\n static activators = [\n {\n eventName: 'onPointerDown' as const,\n handler: ({ nativeEvent: event }: { nativeEvent: PointerEvent }) => {\n const element = event.target as HTMLElement | null\n if (element?.closest('.drag-cancel')) {\n return false\n }\n return true\n },\n },\n ]\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n snapThreshold?: number\n onDragStart?: (activeId: string) => void\n onDragEnd?: (\n activeId: string,\n overId: string | null,\n dropAction: {\n type: 'split' | 'swap'\n direction?: SplitDirection\n position?: 'top' | 'bottom' | 'left' | 'right' | 'center'\n } | null,\n ) => void\n onResizeStart?: (currentNode: SplitNode) => void\n onResize?: (currentNode: SplitNode, percentage: number) => void\n onResizeEnd?: (currentNode: SplitNode, percentage: number) => void\n renderResizer?: (props: ResizerRenderProps) => ReactNode\n minSplitPercentage?: number\n maxSplitPercentage?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = DEFAULT_DRAG_ACTIVATION_DISTANCE,\n snapThreshold = DEFAULT_SNAP_THRESHOLD,\n onDragStart,\n onDragEnd,\n onResizeStart,\n onResize,\n onResizeEnd,\n renderResizer,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n children,\n}) => {\n const [localLayout, setLocalLayout] = useState<TreeNode | null>(layout)\n const prevLayoutRef = useRef(layout)\n\n if (layout !== prevLayoutRef.current) {\n prevLayoutRef.current = layout\n setLocalLayout(layout)\n }\n\n const [activeId, setActiveId] = useState<string | null>(null)\n\n // Refs for stable closure access — prevents callback identity changes on every layout update\n const layoutRef = useRef(localLayout)\n layoutRef.current = localLayout\n\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n\n const renderPaneRef = useRef(renderPane)\n renderPaneRef.current = renderPane\n\n const onResizeEndPropRef = useRef(onResizeEnd)\n onResizeEndPropRef.current = onResizeEnd\n\n // Stable renderPane wrapper — immune to consumer passing inline functions\n const stableRenderPane = useCallback((paneId: string) => renderPaneRef.current(paneId), [])\n\n // Shallow-memoize classNames by individual fields to avoid identity busting from inline objects\n const stableClassNames = useMemo(\n () => classNames,\n [\n classNames.pane,\n classNames.dropPreview,\n classNames.swapPreview,\n classNames.dragOverlay,\n classNames.resizer,\n ],\n )\n\n const sensors = useSensors(\n useSensor(SmartPointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n const draggingId = event.active.id.toString()\n setActiveId(draggingId)\n if (onDragStart) {\n onDragStart(draggingId)\n }\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n const draggingId = active.id.toString()\n\n if (!over) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const overIdStr = over.id.toString()\n\n // Check for root drop (places pane like half of the root)\n const rootMatch = overIdStr.match(/^drop-root-(left|right|top|bottom)$/)\n if (rootMatch) {\n const [, dropZone] = rootMatch\n const newLayout = splitRoot(\n localLayout,\n draggingId,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n\n if (onDragEnd) {\n const direction: SplitDirection =\n dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n onDragEnd(draggingId, 'root', {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n return\n }\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n const newLayout = swapPanes(localLayout, draggingId, targetId)\n setLocalLayout(newLayout)\n onChange(newLayout)\n }\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, { type: 'swap', position: 'center' })\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) {\n if (onDragEnd) {\n onDragEnd(draggingId, null, null)\n }\n return\n }\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const draggedPaneNode = findPane(localLayout, draggingId) ?? {\n type: 'pane',\n paneId: draggingId,\n }\n const treeWithoutDragging = removePane(localLayout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChange(newLayout)\n if (onDragEnd) {\n onDragEnd(draggingId, targetId, {\n type: 'split',\n direction,\n position: dropZone as 'left' | 'right' | 'top' | 'bottom',\n })\n }\n }\n\n const handleLocalLayoutChange = useCallback((newLayout: TreeNode | null) => {\n setLocalLayout(newLayout)\n }, [])\n\n const handleRemovePane = useCallback((paneId: string) => {\n const newLayout = removePane(layoutRef.current, paneId)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleAddPane = useCallback((paneId: string) => {\n const newLayout = addPane(layoutRef.current, paneId)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleSwapPanes = useCallback((paneIdA: string, paneIdB: string) => {\n const newLayout = swapPanes(layoutRef.current, paneIdA, paneIdB)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleSplitPane = useCallback(\n (\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n ) => {\n const draggedPaneNode = findPane(layoutRef.current, paneToAdd) ?? {\n type: 'pane',\n paneId: paneToAdd,\n }\n const treeWithoutDragging = removePane(layoutRef.current, paneToAdd)\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n splitType,\n draggedPaneNode,\n )\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n },\n [],\n )\n\n const handleUpdateSplitPercentage = useCallback((currentNode: SplitNode, percentage: number) => {\n const newLayout = updateSplitPercentage(layoutRef.current, currentNode, percentage)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n }, [])\n\n const handleUpdatePaneMetadata = useCallback(\n (\n paneId: string,\n updater: (\n current: Record<string, unknown> | undefined,\n ) => Record<string, unknown> | undefined,\n ) => {\n const newLayout = updatePaneMetadata(layoutRef.current, paneId, updater)\n setLocalLayout(newLayout)\n onChangeRef.current(newLayout)\n },\n [],\n )\n\n const handleResizeEnd = useCallback((currentNode: SplitNode, percentage: number) => {\n const finalLayout = updateSplitPercentage(layoutRef.current, currentNode, percentage)\n setLocalLayout(finalLayout)\n onChangeRef.current(finalLayout)\n if (onResizeEndPropRef.current) {\n onResizeEndPropRef.current(currentNode, percentage)\n }\n }, [])\n\n // State context — reactive values that change during runtime\n const stateValue = useMemo(\n () => ({\n layout: localLayout,\n onLayoutChange: handleLocalLayoutChange,\n renderPane: stableRenderPane,\n activeId,\n fullscreenPaneId,\n classNames: stableClassNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n onResizeEnd: handleResizeEnd,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n }),\n [\n localLayout,\n activeId,\n fullscreenPaneId,\n stableClassNames,\n onRemove,\n onFullscreenChange,\n snapThreshold,\n onResizeStart,\n onResize,\n renderResizer,\n minSplitPercentage,\n maxSplitPercentage,\n // Stable callbacks (empty deps) — included for exhaustive-deps lint rule\n handleLocalLayoutChange,\n stableRenderPane,\n handleResizeEnd,\n ],\n )\n\n // Actions context — stable dispatch functions that never change identity\n const actionsValue = useMemo(\n () => ({\n removePane: handleRemovePane,\n addPane: handleAddPane,\n swapPanes: handleSwapPanes,\n splitPane: handleSplitPane,\n updateSplitPercentage: handleUpdateSplitPercentage,\n updatePaneMetadata: handleUpdatePaneMetadata,\n }),\n [\n handleRemovePane,\n handleAddPane,\n handleSwapPanes,\n handleSplitPane,\n handleUpdateSplitPercentage,\n handleUpdatePaneMetadata,\n ],\n )\n\n return (\n <DashboardActionsContext.Provider value={actionsValue}>\n <DashboardStateContext.Provider value={stateValue}>\n <DndContext\n id=\"zeugma-dnd-context\"\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardStateContext.Provider>\n </DashboardActionsContext.Provider>\n )\n}\n","import React from 'react'\nimport { useDroppable } from '@dnd-kit/core'\n\nconst rootActivationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '32px',\n zIndex: 30,\n pointerEvents: 'auto',\n },\n}\n\nconst rootPreviewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 31,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nexport interface RootDropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right'\n activeClassName?: string\n}\n\nexport const RootDropZone: React.FC<RootDropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={rootActivationPositions[position]} />\n {isOver && <div className={activeClassName} style={rootPreviewPositions[position]} />}\n </>\n )\n}\n\nexport interface RootDropZonesProps {\n activeId: string | null\n hasOtherPanes: boolean\n dropPreviewClassName?: string\n}\n\nexport const RootDropZones: React.FC<RootDropZonesProps> = ({\n activeId,\n hasOtherPanes,\n dropPreviewClassName,\n}) => {\n if (!activeId || !hasOtherPanes) return null\n\n return (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 30,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <RootDropZone\n key={pos}\n id={`drop-root-${pos}`}\n position={pos}\n activeClassName={dropPreviewClassName}\n />\n ))}\n </div>\n )\n}\n","import React, { useCallback } from 'react'\nimport { TreeNode, SplitNode, SplitDirection } from '../../../shared/model'\nimport { updateSplitPercentage } from '../../../shared/lib/tree'\nimport { useDashboardState } from '../../../entities/dashboard'\n\ninterface UseResizerProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n isRow: boolean\n direction: SplitDirection\n splitPercentage: number\n resizerSize: number\n snapThreshold: number\n layout: TreeNode | null\n currentNode: SplitNode\n onLayoutChange: (newLayout: TreeNode | null) => void\n onResizeStart?: () => void\n onResizeEnd?: () => void\n}\n\nexport function useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: localOnResizeStart,\n onResizeEnd: localOnResizeEnd,\n}: UseResizerProps) {\n const {\n onResizeStart: globalOnResizeStart,\n onResize: globalOnResize,\n onResizeEnd: globalOnResizeEnd,\n minSplitPercentage = 5,\n maxSplitPercentage = 95,\n } = useDashboardState()\n\n return useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n // Inject global cursor style to keep resizing cursor active across the entire page during drag\n const styleEl = document.createElement('style')\n styleEl.id = 'zeugma-global-cursor-style'\n styleEl.textContent = `\n * {\n cursor: ${isRow ? 'col-resize' : 'row-resize'} !important;\n user-select: none !important;\n }\n `\n document.head.appendChild(styleEl)\n\n if (localOnResizeStart) {\n localOnResizeStart()\n }\n if (globalOnResizeStart) {\n globalOnResizeStart(currentNode)\n }\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n // Cache other resizers of the same direction once at drag-start to prevent layout thrashing on move\n const resizerEl = e.currentTarget\n resizerEl.setAttribute('data-resizing', 'true')\n\n const otherResizers = Array.from(\n document.querySelectorAll('div[role=\"separator\"][data-direction]'),\n ).filter((el) => el !== resizerEl && el.getAttribute('data-direction') === direction)\n\n const otherPositions = otherResizers.map((el) => {\n const r = el.getBoundingClientRect()\n return isRow ? r.left + r.width / 2 : r.top + r.height / 2\n })\n\n let currentPercentage = startPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const proposedPercentage = startPercentage + delta\n\n // Find physical position corresponding to proposed percentage\n const proposedPos = isRow\n ? rect.left + (rect.width - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n : rect.top + (rect.height - resizerSize) * (proposedPercentage / 100) + resizerSize / 2\n\n let closestDistance = Infinity\n let bestTarget: number | null = null\n\n for (const pos of otherPositions) {\n const dist = Math.abs(proposedPos - pos)\n if (dist < snapThreshold && dist < closestDistance) {\n closestDistance = dist\n bestTarget = pos\n }\n }\n\n let snappedPercentage = proposedPercentage\n if (bestTarget !== null) {\n snappedPercentage = isRow\n ? ((bestTarget - resizerSize / 2 - rect.left) / (rect.width - resizerSize)) * 100\n : ((bestTarget - resizerSize / 2 - rect.top) / (rect.height - resizerSize)) * 100\n }\n\n const finalPercentage = Math.max(\n minSplitPercentage,\n Math.min(maxSplitPercentage, snappedPercentage),\n )\n currentPercentage = finalPercentage\n\n // Imperatively update the sibling pane container flex sizes during drag\n const firstChild = container.children[0] as HTMLElement\n const secondChild = container.children[container.children.length - 1] as HTMLElement\n if (firstChild && secondChild) {\n firstChild.style.flex = `${finalPercentage} 1 0%`\n secondChild.style.flex = `${100 - finalPercentage} 1 0%`\n }\n\n if (globalOnResize) {\n globalOnResize(currentNode, finalPercentage)\n }\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n resizerEl.removeAttribute('data-resizing')\n\n const globalStyle = document.getElementById('zeugma-global-cursor-style')\n if (globalStyle) {\n globalStyle.remove()\n }\n\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n\n // Write to React state once resizing completes\n const newLayout = updateSplitPercentage(layout, currentNode, currentPercentage)\n console.log('onLayoutChange (finalized) called with percentage:', currentPercentage)\n onLayoutChange(newLayout)\n\n if (localOnResizeEnd) {\n localOnResizeEnd()\n }\n if (globalOnResizeEnd) {\n globalOnResizeEnd(currentNode, currentPercentage)\n }\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n },\n [\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold,\n layout,\n currentNode,\n onLayoutChange,\n localOnResizeStart,\n localOnResizeEnd,\n globalOnResizeStart,\n globalOnResize,\n globalOnResizeEnd,\n minSplitPercentage,\n maxSplitPercentage,\n ],\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { useDashboardState, ResizerRenderProps, RootDropZones } from '../../../entities/dashboard'\nimport { useResizer } from '../../../features/resize-pane'\nimport { TreeNode, SplitNode } from '../../../shared/model'\nimport { removePane } from '../../../shared'\n\nexport interface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n /** Threshold in pixels to snap to adjacent resizer edges (default 8) */\n snapThreshold?: number\n /** Custom resizer renderer to override context-level renderResizer */\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\ninterface PaneSplitProps {\n currentNode: SplitNode\n resizerSize: number\n snapThreshold?: number\n renderResizer?: (props: ResizerRenderProps) => React.ReactNode\n}\n\nconst PaneSplit: React.FC<PaneSplitProps> = ({\n currentNode,\n resizerSize,\n snapThreshold,\n renderResizer: propRenderResizer,\n}) => {\n const {\n layout,\n onLayoutChange,\n classNames,\n renderResizer: contextRenderResizer,\n } = useDashboardState()\n const [isResizing, setIsResizing] = useState(false)\n\n const renderResizer = propRenderResizer || contextRenderResizer\n\n const containerRef = useRef<HTMLDivElement>(null)\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = useResizer({\n containerRef,\n isRow,\n direction,\n splitPercentage,\n resizerSize,\n snapThreshold: snapThreshold ?? 8,\n layout,\n currentNode,\n onLayoutChange,\n onResizeStart: () => setIsResizing(true),\n onResizeEnd: () => setIsResizing(false),\n })\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={first}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n {renderResizer ? (\n renderResizer({\n direction,\n splitPercentage,\n resizerSize,\n isResizing,\n onPointerDown: handlePointerDown,\n })\n ) : (\n <div\n className={classNames.resizer}\n data-direction={direction}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n )}\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree\n tree={second}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={propRenderResizer}\n />\n </div>\n </div>\n )\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({\n tree,\n resizerSize = 4,\n snapThreshold: propSnapThreshold,\n renderResizer,\n}) => {\n const {\n layout,\n renderPane,\n activeId,\n classNames,\n fullscreenPaneId,\n snapThreshold: contextSnapThreshold,\n } = useDashboardState()\n\n const snapThreshold = propSnapThreshold !== undefined ? propSnapThreshold : contextSnapThreshold\n\n const hasOtherPanes = useMemo(() => {\n if (tree !== undefined || !activeId) return false\n return removePane(layout, activeId) !== null\n }, [tree, layout, activeId])\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n const renderContent = () => {\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n return (\n <PaneSplit\n currentNode={currentNode}\n resizerSize={resizerSize}\n snapThreshold={snapThreshold}\n renderResizer={renderResizer}\n />\n )\n }\n\n // Only render RootDropZones at the top-level PaneTree (where tree is undefined)\n if (tree === undefined) {\n return (\n <div\n className=\"zeugma-dashboard-root\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n {renderContent()}\n <RootDropZones\n activeId={activeId}\n hasOtherPanes={hasOtherPanes}\n dropPreviewClassName={classNames.dropPreview}\n />\n </div>\n )\n }\n\n return renderContent()\n}\n","import { createContext } from 'react'\n\nexport const DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n","import React, { useMemo } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboardState, useDashboardActions } from '../../dashboard'\nimport { DragListenersCtx } from '../model/context'\nimport { PaneRenderProps } from '../model/types'\nimport { findPane } from '../../../shared/lib/tree'\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: '25%',\n left: 0,\n width: '25%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: '25%',\n right: 0,\n width: '25%',\n height: '50%',\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 { layout, activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } =\n useDashboardState()\n const { removePane, updatePaneMetadata } = useDashboardActions()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const paneNode = useMemo(() => findPane(layout, id), [layout, id])\n const metadata = paneNode?.metadata\n\n const renderProps: PaneRenderProps = useMemo(\n () => ({\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n if (onRemove) {\n onRemove(id)\n } else {\n removePane(id)\n }\n },\n metadata,\n updateMetadata: (updater) => {\n updatePaneMetadata(id, updater)\n },\n }),\n [\n dragging,\n isFullscreen,\n onFullscreenChange,\n id,\n onRemove,\n removePane,\n metadata,\n updatePaneMetadata,\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.8.1",
3
+ "version": "1.0.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,