react-zeugma 5.1.0 → 5.2.1

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.
@@ -84,7 +84,9 @@ interface ZeugmaController {
84
84
  /** Removes the specified pane from the layout tree and collapses its parent split. */
85
85
  removePane: (paneId: string) => void;
86
86
  /** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
87
- addPane: (paneId: string) => void;
87
+ addPane: (paneId: string, metadata?: Record<string, unknown>) => void;
88
+ /** Appends a tab into a target pane node. */
89
+ addTab: (paneId: string, tabId: string, metadata?: Record<string, unknown>) => void;
88
90
  /** Stable callback to update metadata for a specific tab. */
89
91
  updateTabMetadata: (tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
90
92
  /** Stable callback to update the locked status of a specific pane in the layout tree. */
@@ -95,6 +97,12 @@ interface ZeugmaController {
95
97
  mergeTab: (draggedTabId: string, targetPaneId: string) => void;
96
98
  /** Stable callback to remove/close a specific tab from the layout. */
97
99
  removeTab: (tabId: string) => void;
100
+ /** Splits an existing pane and adds a new one. */
101
+ splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
102
+ /** Updates the split percentage of a split node. */
103
+ updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
104
+ /** Moves/reorders a tab relative to another target tab. */
105
+ moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
98
106
  /** Find a PaneNode by its ID in the layout tree. */
99
107
  findPaneById: (paneId: string) => PaneNode | null;
100
108
  /** Find the PaneNode containing the given tab ID in the layout tree. */
@@ -221,7 +229,9 @@ interface ZeugmaActionsValue {
221
229
  /** Removes the specified pane from the layout tree and collapses its parent split. */
222
230
  removePane: (paneId: string) => void;
223
231
  /** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
224
- addPane: (paneId: string) => void;
232
+ addPane: (paneId: string, metadata?: Record<string, unknown>) => void;
233
+ /** Appends a tab into a target pane node. */
234
+ addTab: (paneId: string, tabId: string, metadata?: Record<string, unknown>) => void;
225
235
  /** Stable callback to update metadata for a specific tab. */
226
236
  updateTabMetadata: (tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
227
237
  /** Stable callback to update the locked status of a specific pane in the layout tree. */
@@ -232,6 +242,16 @@ interface ZeugmaActionsValue {
232
242
  mergeTab: (draggedTabId: string, targetPaneId: string) => void;
233
243
  /** Stable callback to remove/close a specific tab from the layout. */
234
244
  removeTab: (tabId: string) => void;
245
+ /** Programmatically sets the fullscreen pane ID. */
246
+ setFullscreenPaneId: (paneId: string | null) => void;
247
+ /** Programmatically updates the global locked status. */
248
+ setLocked: Dispatch<SetStateAction<boolean>>;
249
+ /** Splits an existing pane and adds a new one. */
250
+ splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
251
+ /** Updates the split percentage of a split node. */
252
+ updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
253
+ /** Moves/reorders a tab relative to another target tab. */
254
+ moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
235
255
  }
236
256
  interface ZeugmaContextValue extends ZeugmaStateValue, ZeugmaActionsValue {
237
257
  }
@@ -84,7 +84,9 @@ interface ZeugmaController {
84
84
  /** Removes the specified pane from the layout tree and collapses its parent split. */
85
85
  removePane: (paneId: string) => void;
86
86
  /** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
87
- addPane: (paneId: string) => void;
87
+ addPane: (paneId: string, metadata?: Record<string, unknown>) => void;
88
+ /** Appends a tab into a target pane node. */
89
+ addTab: (paneId: string, tabId: string, metadata?: Record<string, unknown>) => void;
88
90
  /** Stable callback to update metadata for a specific tab. */
89
91
  updateTabMetadata: (tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
90
92
  /** Stable callback to update the locked status of a specific pane in the layout tree. */
@@ -95,6 +97,12 @@ interface ZeugmaController {
95
97
  mergeTab: (draggedTabId: string, targetPaneId: string) => void;
96
98
  /** Stable callback to remove/close a specific tab from the layout. */
97
99
  removeTab: (tabId: string) => void;
100
+ /** Splits an existing pane and adds a new one. */
101
+ splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
102
+ /** Updates the split percentage of a split node. */
103
+ updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
104
+ /** Moves/reorders a tab relative to another target tab. */
105
+ moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
98
106
  /** Find a PaneNode by its ID in the layout tree. */
99
107
  findPaneById: (paneId: string) => PaneNode | null;
100
108
  /** Find the PaneNode containing the given tab ID in the layout tree. */
@@ -221,7 +229,9 @@ interface ZeugmaActionsValue {
221
229
  /** Removes the specified pane from the layout tree and collapses its parent split. */
222
230
  removePane: (paneId: string) => void;
223
231
  /** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
224
- addPane: (paneId: string) => void;
232
+ addPane: (paneId: string, metadata?: Record<string, unknown>) => void;
233
+ /** Appends a tab into a target pane node. */
234
+ addTab: (paneId: string, tabId: string, metadata?: Record<string, unknown>) => void;
225
235
  /** Stable callback to update metadata for a specific tab. */
226
236
  updateTabMetadata: (tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
227
237
  /** Stable callback to update the locked status of a specific pane in the layout tree. */
@@ -232,6 +242,16 @@ interface ZeugmaActionsValue {
232
242
  mergeTab: (draggedTabId: string, targetPaneId: string) => void;
233
243
  /** Stable callback to remove/close a specific tab from the layout. */
234
244
  removeTab: (tabId: string) => void;
245
+ /** Programmatically sets the fullscreen pane ID. */
246
+ setFullscreenPaneId: (paneId: string | null) => void;
247
+ /** Programmatically updates the global locked status. */
248
+ setLocked: Dispatch<SetStateAction<boolean>>;
249
+ /** Splits an existing pane and adds a new one. */
250
+ splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
251
+ /** Updates the split percentage of a split node. */
252
+ updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
253
+ /** Moves/reorders a tab relative to another target tab. */
254
+ moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
235
255
  }
236
256
  interface ZeugmaContextValue extends ZeugmaStateValue, ZeugmaActionsValue {
237
257
  }
package/dist/utils.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function P(n,t){if(n===null)return null;if(n.type==="pane")return n.id===t?null:n;let e=P(n.first,t),i=P(n.second,t);return e===null?i:i===null?e:{...n,first:e,second:i}}function T(n,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let r=n.tabs.filter(l=>l!==t);if(r.length===0)return null;let u=n.activeTabId;n.activeTabId===t&&(u=r[0]);let s={...n.tabsMetadata};return delete s[t],{...n,tabs:r,activeTabId:u,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}let e=T(n.first,t),i=T(n.second,t);return e===null?i:i===null?e:{...n,first:e,second:i}}function M(n,t,e,i,r){if(n===null)return typeof r=="string"?{type:"pane",id:p(),tabs:[r],activeTabId:r}:r;if(n.type==="pane"){if(n.id===t){let u=typeof r=="string"?{type:"pane",id:p(),tabs:[r],activeTabId:r}:r,s=i==="left"||i==="top";return {type:"split",direction:e,first:s?u:n,second:s?n:u,splitPercentage:50}}return n}return {...n,first:M(n.first,t,e,i,r)||n.first,second:M(n.second,t,e,i,r)||n.second}}function L(n,t){if(n===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t};function e(i,r){return i.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[t],activeTabId:t}}:{...i,second:e(i.second,i.direction)}}return e(n,null)}function x(n,t,e){return n===null?null:n===t?{...n,splitPercentage:e}:n.type==="split"?{...n,first:x(n.first,t,e)||n.first,second:x(n.second,t,e)||n.second}:n}function v(n,t){return n===null?null:n.type==="pane"?n.id===t?n:null:v(n.first,t)??v(n.second,t)}function N(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:N(n.first,t)??N(n.second,t)}function D(n,t){let e=N(n,t);if(!e)return null;let i=e.tabs.indexOf(t);return {id:t,paneId:e.id,isActive:e.activeTabId===t,index:i,metadata:e.tabsMetadata?.[t]}}function S(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let i=n.tabsMetadata||{},r=i[t],u=e(r),s={...i};return u===void 0?delete s[t]:s[t]=u,{...n,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}return {...n,first:S(n.first,t,e)??n.first,second:S(n.second,t,e)??n.second}}function w(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.id===t){if(e===false){let{locked:i,...r}=n;return r}return {...n,locked:e}}return n}return {...n,first:w(n.first,t,e)??n.first,second:w(n.second,t,e)??n.second}}function C(n,t,e){return n===null?null:n.type==="pane"?n.id===t?{...n,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function k(n,t,e){if(n===null)return null;let r=N(n,t)?.tabsMetadata?.[t],u=T(n,t);if(u===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:r?{[t]:r}:void 0};function s(l){if(l.type==="pane"){if(l.id===e){let o=[...l.tabs];o.includes(t)||o.push(t);let c={...l.tabsMetadata};return r&&(c[t]=r),{...l,tabs:o,activeTabId:t,tabsMetadata:Object.keys(c).length>0?c:void 0}}return l}return {...l,first:s(l.first),second:s(l.second)}}return s(u)}function O(n,t,e,i="before"){if(n===null)return null;let u=N(n,t)?.tabsMetadata?.[t],s=T(n,t);if(s===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:u?{[t]:u}:void 0};function l(o){if(o.type==="pane"){if(o.tabs.includes(e)){let y=[...o.tabs].filter(b=>b!==t),d=y.indexOf(e);d<0&&(d=0),i==="after"&&(d+=1),y.splice(d,0,t);let a={...o.tabsMetadata};return u&&(a[t]=u),{...o,tabs:y,activeTabId:t,tabsMetadata:Object.keys(a).length>0?a:void 0}}return o}return {...o,first:l(o.first),second:l(o.second)}}return l(s)}function m(n,t=0,e=0,i=100,r=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:t,top:e,width:i,height:r,node:n}],splitters:[]};let{direction:s,splitPercentage:l,first:o,second:c}=n,d={id:`splitter-${u}-${s}`,currentNode:n,direction:s,left:s==="row"?t+i*(l/100):t,top:s==="column"?e+r*(l/100):e,width:s==="row"?0:i,height:s==="column"?0:r,parentLeft:t,parentTop:e,parentWidth:i,parentHeight:r},a={panes:[],splitters:[]},b={panes:[],splitters:[]};if(s==="row"){let f=i*(l/100);a=m(o,t,e,f,r,`${u}-L`),b=m(c,t+f,e,i-f,r,`${u}-R`);}else {let f=r*(l/100);a=m(o,t,e,i,f,`${u}-T`),b=m(c,t,e+f,i,r-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}exports.addPane=L;exports.computeLayout=m;exports.findPaneById=v;exports.findPaneContainingTab=N;exports.findTabById=D;exports.generateUniqueId=p;exports.mergeTab=k;exports.moveTab=O;exports.removePane=P;exports.removeTab=T;exports.selectTab=C;exports.splitPane=M;exports.updatePaneLock=w;exports.updateSplitPercentage=x;exports.updateTabMetadata=S;//# sourceMappingURL=utils.cjs.map
1
+ 'use strict';function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function M(n,t){if(n===null)return null;if(n.type==="pane")return n.id===t?null:n;let e=M(n.first,t),s=M(n.second,t);return e===null?s:s===null?e:{...n,first:e,second:s}}function m(n,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let i=n.tabs.filter(l=>l!==t);if(i.length===0)return null;let u=n.activeTabId;n.activeTabId===t&&(u=i[0]);let r={...n.tabsMetadata};return delete r[t],{...n,tabs:i,activeTabId:u,tabsMetadata:Object.keys(r).length>0?r:void 0}}return n}let e=m(n.first,t),s=m(n.second,t);return e===null?s:s===null?e:{...n,first:e,second:s}}function P(n,t,e,s,i){if(n===null)return typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i;if(n.type==="pane"){if(n.id===t){let u=typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i,r=s==="left"||s==="top";return {type:"split",direction:e,first:r?u:n,second:r?n:u,splitPercentage:50}}return n}return {...n,first:P(n.first,t,e,s,i)||n.first,second:P(n.second,t,e,s,i)||n.second}}function L(n,t,e){if(n===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:e?{[t]:e}:void 0};function s(i,u){return i.type==="pane"?{type:"split",direction:u==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:e?{[t]:e}:void 0}}:{...i,second:s(i.second,i.direction)}}return s(n,null)}function x(n,t,e){return n===null?null:n===t?{...n,splitPercentage:e}:n.type==="split"?{...n,first:x(n.first,t,e)||n.first,second:x(n.second,t,e)||n.second}:n}function v(n,t){return n===null?null:n.type==="pane"?n.id===t?n:null:v(n.first,t)??v(n.second,t)}function N(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:N(n.first,t)??N(n.second,t)}function k(n,t){let e=N(n,t);if(!e)return null;let s=e.tabs.indexOf(t);return {id:t,paneId:e.id,isActive:e.activeTabId===t,index:s,metadata:e.tabsMetadata?.[t]}}function S(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let s=n.tabsMetadata||{},i=s[t],u=e(i),r={...s};return u===void 0?delete r[t]:r[t]=u,{...n,tabsMetadata:Object.keys(r).length>0?r:void 0}}return n}return {...n,first:S(n.first,t,e)??n.first,second:S(n.second,t,e)??n.second}}function w(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.id===t){if(e===false){let{locked:s,...i}=n;return i}return {...n,locked:e}}return n}return {...n,first:w(n.first,t,e)??n.first,second:w(n.second,t,e)??n.second}}function C(n,t,e){return n===null?null:n.type==="pane"?n.id===t?{...n,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function D(n,t,e){if(n===null)return null;let i=N(n,t)?.tabsMetadata?.[t],u=m(n,t);if(u===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:i?{[t]:i}:void 0};function r(l){if(l.type==="pane"){if(l.id===e){let o=[...l.tabs];o.includes(t)||o.push(t);let c={...l.tabsMetadata};return i&&(c[t]=i),{...l,tabs:o,activeTabId:t,tabsMetadata:Object.keys(c).length>0?c:void 0}}return l}return {...l,first:r(l.first),second:r(l.second)}}return r(u)}function O(n,t,e,s="before"){if(n===null)return null;let u=N(n,t)?.tabsMetadata?.[t],r=m(n,t);if(r===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:u?{[t]:u}:void 0};function l(o){if(o.type==="pane"){if(o.tabs.includes(e)){let y=[...o.tabs].filter(b=>b!==t),d=y.indexOf(e);d<0&&(d=0),s==="after"&&(d+=1),y.splice(d,0,t);let a={...o.tabsMetadata};return u&&(a[t]=u),{...o,tabs:y,activeTabId:t,tabsMetadata:Object.keys(a).length>0?a:void 0}}return o}return {...o,first:l(o.first),second:l(o.second)}}return l(r)}function T(n,t=0,e=0,s=100,i=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:t,top:e,width:s,height:i,node:n}],splitters:[]};let{direction:r,splitPercentage:l,first:o,second:c}=n,d={id:`splitter-${u}-${r}`,currentNode:n,direction:r,left:r==="row"?t+s*(l/100):t,top:r==="column"?e+i*(l/100):e,width:r==="row"?0:s,height:r==="column"?0:i,parentLeft:t,parentTop:e,parentWidth:s,parentHeight:i},a={panes:[],splitters:[]},b={panes:[],splitters:[]};if(r==="row"){let f=s*(l/100);a=T(o,t,e,f,i,`${u}-L`),b=T(c,t+f,e,s-f,i,`${u}-R`);}else {let f=i*(l/100);a=T(o,t,e,s,f,`${u}-T`),b=T(c,t,e+f,s,i-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}exports.addPane=L;exports.computeLayout=T;exports.findPaneById=v;exports.findPaneContainingTab=N;exports.findTabById=k;exports.generateUniqueId=p;exports.mergeTab=D;exports.moveTab=O;exports.removePane=M;exports.removeTab=m;exports.selectTab=C;exports.splitPane=P;exports.updatePaneLock=w;exports.updateSplitPercentage=x;exports.updateTabMetadata=S;//# sourceMappingURL=utils.cjs.map
2
2
  //# sourceMappingURL=utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts"],"names":["generateUniqueId","removePane","tree","paneId","newFirst","newSecond","removeTab","tabId","newTabs","t","newActive","newTabsMetadata","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","addPane","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","findPaneById","findPaneContainingTab","findTabById","pane","index","updateTabMetadata","updater","currentTabsMetadata","currentTabMeta","newTabMeta","updatePaneLock","locked","_","rest","selectTab","mergeTab","draggedTabId","targetPaneId","sourceMetadata","cleanTree","moveTab","targetTabId","position","filteredTabs","insertIndex","computeLayout","left","top","width","height","path","splitPercentage","first","second","currentSplitter","firstLayout","secondLayout","firstWidth","firstHeight"],"mappings":"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","file":"utils.cjs","sourcesContent":["import { TreeNode, SplitNode, SplitDirection, PaneNode, TabDetails } from '../../model'\n\nexport function generateUniqueId(): string {\n return 'pane-' + Math.random().toString(36).substring(2, 11)\n}\n\n/**\n * Tree Helper: Remove a pane container and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, paneId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) return null\n return tree\n }\n const newFirst = removePane(tree.first, paneId)\n const newSecond = removePane(tree.second, paneId)\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: Remove a tab from a pane and consolidate the tree structure if no tabs remain.\n */\nexport function removeTab(tree: TreeNode | null, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.tabs.includes(tabId)) {\n const newTabs = tree.tabs.filter((t) => t !== tabId)\n if (newTabs.length === 0) return null\n let newActive = tree.activeTabId\n if (tree.activeTabId === tabId) {\n newActive = newTabs[0]\n }\n const newTabsMetadata = { ...tree.tabsMetadata }\n delete newTabsMetadata[tabId]\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: newActive,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n const newFirst = removeTab(tree.first, tabId)\n const newSecond = removeTab(tree.second, tabId)\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 if (typeof paneToAdd === 'string') {\n return { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n }\n return paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.id === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string'\n ? { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n : 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: 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', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: 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', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: 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 * Find a PaneNode by its ID.\n */\nexport function findPaneById(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.id === paneId ? tree : null\n }\n return findPaneById(tree.first, paneId) ?? findPaneById(tree.second, paneId)\n}\n\n/**\n * Find a PaneNode containing the given tab ID.\n */\nexport function findPaneContainingTab(tree: TreeNode | null, tabId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.tabs.includes(tabId) ? tree : null\n }\n return findPaneContainingTab(tree.first, tabId) ?? findPaneContainingTab(tree.second, tabId)\n}\n\n/**\n * Find the details of a tab by its ID.\n */\nexport function findTabById(tree: TreeNode | null, tabId: string): TabDetails | null {\n const pane = findPaneContainingTab(tree, tabId)\n if (!pane) return null\n const index = pane.tabs.indexOf(tabId)\n return {\n id: tabId,\n paneId: pane.id,\n isActive: pane.activeTabId === tabId,\n index,\n metadata: pane.tabsMetadata?.[tabId],\n }\n}\n\n/**\n * Update metadata on a specific tab node using an updater function.\n */\nexport function updateTabMetadata(\n tree: TreeNode | null,\n tabId: 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.tabs.includes(tabId)) {\n const currentTabsMetadata = tree.tabsMetadata || {}\n const currentTabMeta = currentTabsMetadata[tabId]\n const newTabMeta = updater(currentTabMeta)\n\n const newTabsMetadata = { ...currentTabsMetadata }\n if (newTabMeta === undefined) {\n delete newTabsMetadata[tabId]\n } else {\n newTabsMetadata[tabId] = newTabMeta\n }\n\n return {\n ...tree,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: updateTabMetadata(tree.first, tabId, updater) ?? tree.first,\n second: updateTabMetadata(tree.second, tabId, updater) ?? tree.second,\n }\n}\n\n/**\n * Update the locked status on a specific pane node in the layout tree.\n */\nexport function updatePaneLock(\n tree: TreeNode | null,\n paneId: string,\n locked: boolean,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n if (locked === false) {\n const { locked: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, locked }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneLock(tree.first, paneId, locked) ?? tree.first,\n second: updatePaneLock(tree.second, paneId, locked) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Activate a tab within a pane.\n */\nexport function selectTab(tree: TreeNode | null, paneId: string, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n return { ...tree, activeTabId: tabId }\n }\n return tree\n }\n return {\n ...tree,\n first: selectTab(tree.first, paneId, tabId) ?? tree.first,\n second: selectTab(tree.second, paneId, tabId) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Merge a tab into a target pane node.\n */\nexport function mergeTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetPaneId: string,\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.id === targetPaneId) {\n const newTabs = [...node.tabs]\n if (!newTabs.includes(draggedTabId)) {\n newTabs.push(draggedTabId)\n }\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: newTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\n/**\n * Tree Helper: Move/reorder a tab inside or to a target pane next to a target tab.\n */\nexport function moveTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetTabId: string,\n position: 'before' | 'after' = 'before',\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.tabs.includes(targetTabId)) {\n const newTabs = [...node.tabs]\n const filteredTabs = newTabs.filter((t) => t !== draggedTabId)\n let insertIndex = filteredTabs.indexOf(targetTabId)\n if (insertIndex < 0) {\n insertIndex = 0\n }\n if (position === 'after') {\n insertIndex += 1\n }\n filteredTabs.splice(insertIndex, 0, draggedTabId)\n\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: filteredTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\nexport interface ComputedPane {\n paneId: string\n left: number\n top: number\n width: number\n height: number\n node: PaneNode\n}\n\nexport interface ComputedSplitter {\n id: string\n currentNode: SplitNode\n direction: SplitDirection\n left: number\n top: number\n width: number\n height: number\n parentLeft: number\n parentTop: number\n parentWidth: number\n parentHeight: number\n}\n\nexport function computeLayout(\n node: TreeNode | null,\n left = 0,\n top = 0,\n width = 100,\n height = 100,\n path = 'root',\n): { panes: ComputedPane[]; splitters: ComputedSplitter[] } {\n if (node === null) return { panes: [], splitters: [] }\n if (node.type === 'pane') {\n return {\n panes: [{ paneId: node.id, left, top, width, height, node }],\n splitters: [],\n }\n }\n\n const { direction, splitPercentage, first, second } = node\n const splitterId = `splitter-${path}-${direction}`\n\n const currentSplitter: ComputedSplitter = {\n id: splitterId,\n currentNode: node,\n direction,\n left: direction === 'row' ? left + width * (splitPercentage / 100) : left,\n top: direction === 'column' ? top + height * (splitPercentage / 100) : top,\n width: direction === 'row' ? 0 : width,\n height: direction === 'column' ? 0 : height,\n parentLeft: left,\n parentTop: top,\n parentWidth: width,\n parentHeight: height,\n }\n\n let firstLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n let secondLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n\n if (direction === 'row') {\n const firstWidth = width * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, firstWidth, height, `${path}-L`)\n secondLayout = computeLayout(\n second,\n left + firstWidth,\n top,\n width - firstWidth,\n height,\n `${path}-R`,\n )\n } else {\n const firstHeight = height * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, width, firstHeight, `${path}-T`)\n secondLayout = computeLayout(\n second,\n left,\n top + firstHeight,\n width,\n height - firstHeight,\n `${path}-B`,\n )\n }\n\n return {\n panes: [...firstLayout.panes, ...secondLayout.panes],\n splitters: [currentSplitter, ...firstLayout.splitters, ...secondLayout.splitters],\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts"],"names":["generateUniqueId","removePane","tree","paneId","newFirst","newSecond","removeTab","tabId","newTabs","t","newActive","newTabsMetadata","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","addPane","metadata","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","findPaneById","findPaneContainingTab","findTabById","pane","index","updateTabMetadata","updater","currentTabsMetadata","currentTabMeta","newTabMeta","updatePaneLock","locked","_","rest","selectTab","mergeTab","draggedTabId","targetPaneId","sourceMetadata","cleanTree","moveTab","targetTabId","position","filteredTabs","insertIndex","computeLayout","left","top","width","height","path","splitPercentage","first","second","currentSplitter","firstLayout","secondLayout","firstWidth","firstHeight"],"mappings":"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","file":"utils.cjs","sourcesContent":["import { TreeNode, SplitNode, SplitDirection, PaneNode, TabDetails } from '../../model'\n\nexport function generateUniqueId(): string {\n return 'pane-' + Math.random().toString(36).substring(2, 11)\n}\n\n/**\n * Tree Helper: Remove a pane container and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, paneId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) return null\n return tree\n }\n const newFirst = removePane(tree.first, paneId)\n const newSecond = removePane(tree.second, paneId)\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: Remove a tab from a pane and consolidate the tree structure if no tabs remain.\n */\nexport function removeTab(tree: TreeNode | null, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.tabs.includes(tabId)) {\n const newTabs = tree.tabs.filter((t) => t !== tabId)\n if (newTabs.length === 0) return null\n let newActive = tree.activeTabId\n if (tree.activeTabId === tabId) {\n newActive = newTabs[0]\n }\n const newTabsMetadata = { ...tree.tabsMetadata }\n delete newTabsMetadata[tabId]\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: newActive,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n const newFirst = removeTab(tree.first, tabId)\n const newSecond = removeTab(tree.second, tabId)\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 if (typeof paneToAdd === 'string') {\n return { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n }\n return paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.id === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string'\n ? { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n : 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: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(\n tree: TreeNode | null,\n paneToAdd: string,\n metadata?: Record<string, unknown>,\n): TreeNode {\n if (tree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [paneToAdd],\n activeTabId: paneToAdd,\n tabsMetadata: metadata ? { [paneToAdd]: metadata } : undefined,\n }\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: {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [paneToAdd],\n activeTabId: paneToAdd,\n tabsMetadata: metadata ? { [paneToAdd]: metadata } : undefined,\n },\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 * Find a PaneNode by its ID.\n */\nexport function findPaneById(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.id === paneId ? tree : null\n }\n return findPaneById(tree.first, paneId) ?? findPaneById(tree.second, paneId)\n}\n\n/**\n * Find a PaneNode containing the given tab ID.\n */\nexport function findPaneContainingTab(tree: TreeNode | null, tabId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.tabs.includes(tabId) ? tree : null\n }\n return findPaneContainingTab(tree.first, tabId) ?? findPaneContainingTab(tree.second, tabId)\n}\n\n/**\n * Find the details of a tab by its ID.\n */\nexport function findTabById(tree: TreeNode | null, tabId: string): TabDetails | null {\n const pane = findPaneContainingTab(tree, tabId)\n if (!pane) return null\n const index = pane.tabs.indexOf(tabId)\n return {\n id: tabId,\n paneId: pane.id,\n isActive: pane.activeTabId === tabId,\n index,\n metadata: pane.tabsMetadata?.[tabId],\n }\n}\n\n/**\n * Update metadata on a specific tab node using an updater function.\n */\nexport function updateTabMetadata(\n tree: TreeNode | null,\n tabId: 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.tabs.includes(tabId)) {\n const currentTabsMetadata = tree.tabsMetadata || {}\n const currentTabMeta = currentTabsMetadata[tabId]\n const newTabMeta = updater(currentTabMeta)\n\n const newTabsMetadata = { ...currentTabsMetadata }\n if (newTabMeta === undefined) {\n delete newTabsMetadata[tabId]\n } else {\n newTabsMetadata[tabId] = newTabMeta\n }\n\n return {\n ...tree,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: updateTabMetadata(tree.first, tabId, updater) ?? tree.first,\n second: updateTabMetadata(tree.second, tabId, updater) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Add a tab directly to a specific target pane node.\n */\nexport function addTab(\n tree: TreeNode | null,\n targetPaneId: string,\n tabId: string,\n metadata?: Record<string, unknown>,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === targetPaneId) {\n const newTabs = [...tree.tabs]\n if (!newTabs.includes(tabId)) {\n newTabs.push(tabId)\n }\n let newTabsMetadata = tree.tabsMetadata\n if (metadata) {\n newTabsMetadata = {\n ...tree.tabsMetadata,\n [tabId]: metadata,\n }\n }\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: tabId,\n tabsMetadata: newTabsMetadata,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: addTab(tree.first, targetPaneId, tabId, metadata) || tree.first,\n second: addTab(tree.second, targetPaneId, tabId, metadata) || tree.second,\n }\n}\n\n/**\n * Update the locked status on a specific pane node in the layout tree.\n */\nexport function updatePaneLock(\n tree: TreeNode | null,\n paneId: string,\n locked: boolean,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n if (locked === false) {\n const { locked: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, locked }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneLock(tree.first, paneId, locked) ?? tree.first,\n second: updatePaneLock(tree.second, paneId, locked) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Activate a tab within a pane.\n */\nexport function selectTab(tree: TreeNode | null, paneId: string, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n return { ...tree, activeTabId: tabId }\n }\n return tree\n }\n return {\n ...tree,\n first: selectTab(tree.first, paneId, tabId) ?? tree.first,\n second: selectTab(tree.second, paneId, tabId) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Merge a tab into a target pane node.\n */\nexport function mergeTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetPaneId: string,\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.id === targetPaneId) {\n const newTabs = [...node.tabs]\n if (!newTabs.includes(draggedTabId)) {\n newTabs.push(draggedTabId)\n }\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: newTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\n/**\n * Tree Helper: Move/reorder a tab inside or to a target pane next to a target tab.\n */\nexport function moveTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetTabId: string,\n position: 'before' | 'after' = 'before',\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.tabs.includes(targetTabId)) {\n const newTabs = [...node.tabs]\n const filteredTabs = newTabs.filter((t) => t !== draggedTabId)\n let insertIndex = filteredTabs.indexOf(targetTabId)\n if (insertIndex < 0) {\n insertIndex = 0\n }\n if (position === 'after') {\n insertIndex += 1\n }\n filteredTabs.splice(insertIndex, 0, draggedTabId)\n\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: filteredTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\nexport interface ComputedPane {\n paneId: string\n left: number\n top: number\n width: number\n height: number\n node: PaneNode\n}\n\nexport interface ComputedSplitter {\n id: string\n currentNode: SplitNode\n direction: SplitDirection\n left: number\n top: number\n width: number\n height: number\n parentLeft: number\n parentTop: number\n parentWidth: number\n parentHeight: number\n}\n\nexport function computeLayout(\n node: TreeNode | null,\n left = 0,\n top = 0,\n width = 100,\n height = 100,\n path = 'root',\n): { panes: ComputedPane[]; splitters: ComputedSplitter[] } {\n if (node === null) return { panes: [], splitters: [] }\n if (node.type === 'pane') {\n return {\n panes: [{ paneId: node.id, left, top, width, height, node }],\n splitters: [],\n }\n }\n\n const { direction, splitPercentage, first, second } = node\n const splitterId = `splitter-${path}-${direction}`\n\n const currentSplitter: ComputedSplitter = {\n id: splitterId,\n currentNode: node,\n direction,\n left: direction === 'row' ? left + width * (splitPercentage / 100) : left,\n top: direction === 'column' ? top + height * (splitPercentage / 100) : top,\n width: direction === 'row' ? 0 : width,\n height: direction === 'column' ? 0 : height,\n parentLeft: left,\n parentTop: top,\n parentWidth: width,\n parentHeight: height,\n }\n\n let firstLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n let secondLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n\n if (direction === 'row') {\n const firstWidth = width * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, firstWidth, height, `${path}-L`)\n secondLayout = computeLayout(\n second,\n left + firstWidth,\n top,\n width - firstWidth,\n height,\n `${path}-R`,\n )\n } else {\n const firstHeight = height * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, width, firstHeight, `${path}-T`)\n secondLayout = computeLayout(\n second,\n left,\n top + firstHeight,\n width,\n height - firstHeight,\n `${path}-B`,\n )\n }\n\n return {\n panes: [...firstLayout.panes, ...secondLayout.panes],\n splitters: [currentSplitter, ...firstLayout.splitters, ...secondLayout.splitters],\n }\n}\n"]}
package/dist/utils.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-CaiXD2pG.cjs';
1
+ import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-BjBbRjIM.cjs';
2
2
  import 'react';
3
3
 
4
4
  declare function generateUniqueId(): string;
@@ -17,7 +17,7 @@ declare function splitPane(tree: TreeNode | null, targetId: string, direction: S
17
17
  /**
18
18
  * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.
19
19
  */
20
- declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
20
+ declare function addPane(tree: TreeNode | null, paneToAdd: string, metadata?: Record<string, unknown>): TreeNode;
21
21
  /**
22
22
  * Tree Helper: Update split percentage recursively.
23
23
  */
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-CaiXD2pG.js';
1
+ import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-BjBbRjIM.js';
2
2
  import 'react';
3
3
 
4
4
  declare function generateUniqueId(): string;
@@ -17,7 +17,7 @@ declare function splitPane(tree: TreeNode | null, targetId: string, direction: S
17
17
  /**
18
18
  * Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.
19
19
  */
20
- declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
20
+ declare function addPane(tree: TreeNode | null, paneToAdd: string, metadata?: Record<string, unknown>): TreeNode;
21
21
  /**
22
22
  * Tree Helper: Update split percentage recursively.
23
23
  */
package/dist/utils.js CHANGED
@@ -1,2 +1,2 @@
1
- function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function P(n,t){if(n===null)return null;if(n.type==="pane")return n.id===t?null:n;let e=P(n.first,t),i=P(n.second,t);return e===null?i:i===null?e:{...n,first:e,second:i}}function T(n,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let r=n.tabs.filter(l=>l!==t);if(r.length===0)return null;let u=n.activeTabId;n.activeTabId===t&&(u=r[0]);let s={...n.tabsMetadata};return delete s[t],{...n,tabs:r,activeTabId:u,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}let e=T(n.first,t),i=T(n.second,t);return e===null?i:i===null?e:{...n,first:e,second:i}}function M(n,t,e,i,r){if(n===null)return typeof r=="string"?{type:"pane",id:p(),tabs:[r],activeTabId:r}:r;if(n.type==="pane"){if(n.id===t){let u=typeof r=="string"?{type:"pane",id:p(),tabs:[r],activeTabId:r}:r,s=i==="left"||i==="top";return {type:"split",direction:e,first:s?u:n,second:s?n:u,splitPercentage:50}}return n}return {...n,first:M(n.first,t,e,i,r)||n.first,second:M(n.second,t,e,i,r)||n.second}}function L(n,t){if(n===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t};function e(i,r){return i.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[t],activeTabId:t}}:{...i,second:e(i.second,i.direction)}}return e(n,null)}function x(n,t,e){return n===null?null:n===t?{...n,splitPercentage:e}:n.type==="split"?{...n,first:x(n.first,t,e)||n.first,second:x(n.second,t,e)||n.second}:n}function v(n,t){return n===null?null:n.type==="pane"?n.id===t?n:null:v(n.first,t)??v(n.second,t)}function N(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:N(n.first,t)??N(n.second,t)}function D(n,t){let e=N(n,t);if(!e)return null;let i=e.tabs.indexOf(t);return {id:t,paneId:e.id,isActive:e.activeTabId===t,index:i,metadata:e.tabsMetadata?.[t]}}function S(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let i=n.tabsMetadata||{},r=i[t],u=e(r),s={...i};return u===void 0?delete s[t]:s[t]=u,{...n,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}return {...n,first:S(n.first,t,e)??n.first,second:S(n.second,t,e)??n.second}}function w(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.id===t){if(e===false){let{locked:i,...r}=n;return r}return {...n,locked:e}}return n}return {...n,first:w(n.first,t,e)??n.first,second:w(n.second,t,e)??n.second}}function C(n,t,e){return n===null?null:n.type==="pane"?n.id===t?{...n,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function k(n,t,e){if(n===null)return null;let r=N(n,t)?.tabsMetadata?.[t],u=T(n,t);if(u===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:r?{[t]:r}:void 0};function s(l){if(l.type==="pane"){if(l.id===e){let o=[...l.tabs];o.includes(t)||o.push(t);let c={...l.tabsMetadata};return r&&(c[t]=r),{...l,tabs:o,activeTabId:t,tabsMetadata:Object.keys(c).length>0?c:void 0}}return l}return {...l,first:s(l.first),second:s(l.second)}}return s(u)}function O(n,t,e,i="before"){if(n===null)return null;let u=N(n,t)?.tabsMetadata?.[t],s=T(n,t);if(s===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:u?{[t]:u}:void 0};function l(o){if(o.type==="pane"){if(o.tabs.includes(e)){let y=[...o.tabs].filter(b=>b!==t),d=y.indexOf(e);d<0&&(d=0),i==="after"&&(d+=1),y.splice(d,0,t);let a={...o.tabsMetadata};return u&&(a[t]=u),{...o,tabs:y,activeTabId:t,tabsMetadata:Object.keys(a).length>0?a:void 0}}return o}return {...o,first:l(o.first),second:l(o.second)}}return l(s)}function m(n,t=0,e=0,i=100,r=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:t,top:e,width:i,height:r,node:n}],splitters:[]};let{direction:s,splitPercentage:l,first:o,second:c}=n,d={id:`splitter-${u}-${s}`,currentNode:n,direction:s,left:s==="row"?t+i*(l/100):t,top:s==="column"?e+r*(l/100):e,width:s==="row"?0:i,height:s==="column"?0:r,parentLeft:t,parentTop:e,parentWidth:i,parentHeight:r},a={panes:[],splitters:[]},b={panes:[],splitters:[]};if(s==="row"){let f=i*(l/100);a=m(o,t,e,f,r,`${u}-L`),b=m(c,t+f,e,i-f,r,`${u}-R`);}else {let f=r*(l/100);a=m(o,t,e,i,f,`${u}-T`),b=m(c,t,e+f,i,r-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}export{L as addPane,m as computeLayout,v as findPaneById,N as findPaneContainingTab,D as findTabById,p as generateUniqueId,k as mergeTab,O as moveTab,P as removePane,T as removeTab,C as selectTab,M as splitPane,w as updatePaneLock,x as updateSplitPercentage,S as updateTabMetadata};//# sourceMappingURL=utils.js.map
1
+ function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function M(n,t){if(n===null)return null;if(n.type==="pane")return n.id===t?null:n;let e=M(n.first,t),s=M(n.second,t);return e===null?s:s===null?e:{...n,first:e,second:s}}function m(n,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let i=n.tabs.filter(l=>l!==t);if(i.length===0)return null;let u=n.activeTabId;n.activeTabId===t&&(u=i[0]);let r={...n.tabsMetadata};return delete r[t],{...n,tabs:i,activeTabId:u,tabsMetadata:Object.keys(r).length>0?r:void 0}}return n}let e=m(n.first,t),s=m(n.second,t);return e===null?s:s===null?e:{...n,first:e,second:s}}function P(n,t,e,s,i){if(n===null)return typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i;if(n.type==="pane"){if(n.id===t){let u=typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i,r=s==="left"||s==="top";return {type:"split",direction:e,first:r?u:n,second:r?n:u,splitPercentage:50}}return n}return {...n,first:P(n.first,t,e,s,i)||n.first,second:P(n.second,t,e,s,i)||n.second}}function L(n,t,e){if(n===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:e?{[t]:e}:void 0};function s(i,u){return i.type==="pane"?{type:"split",direction:u==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:e?{[t]:e}:void 0}}:{...i,second:s(i.second,i.direction)}}return s(n,null)}function x(n,t,e){return n===null?null:n===t?{...n,splitPercentage:e}:n.type==="split"?{...n,first:x(n.first,t,e)||n.first,second:x(n.second,t,e)||n.second}:n}function v(n,t){return n===null?null:n.type==="pane"?n.id===t?n:null:v(n.first,t)??v(n.second,t)}function N(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:N(n.first,t)??N(n.second,t)}function k(n,t){let e=N(n,t);if(!e)return null;let s=e.tabs.indexOf(t);return {id:t,paneId:e.id,isActive:e.activeTabId===t,index:s,metadata:e.tabsMetadata?.[t]}}function S(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(t)){let s=n.tabsMetadata||{},i=s[t],u=e(i),r={...s};return u===void 0?delete r[t]:r[t]=u,{...n,tabsMetadata:Object.keys(r).length>0?r:void 0}}return n}return {...n,first:S(n.first,t,e)??n.first,second:S(n.second,t,e)??n.second}}function w(n,t,e){if(n===null)return null;if(n.type==="pane"){if(n.id===t){if(e===false){let{locked:s,...i}=n;return i}return {...n,locked:e}}return n}return {...n,first:w(n.first,t,e)??n.first,second:w(n.second,t,e)??n.second}}function C(n,t,e){return n===null?null:n.type==="pane"?n.id===t?{...n,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function D(n,t,e){if(n===null)return null;let i=N(n,t)?.tabsMetadata?.[t],u=m(n,t);if(u===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:i?{[t]:i}:void 0};function r(l){if(l.type==="pane"){if(l.id===e){let o=[...l.tabs];o.includes(t)||o.push(t);let c={...l.tabsMetadata};return i&&(c[t]=i),{...l,tabs:o,activeTabId:t,tabsMetadata:Object.keys(c).length>0?c:void 0}}return l}return {...l,first:r(l.first),second:r(l.second)}}return r(u)}function O(n,t,e,s="before"){if(n===null)return null;let u=N(n,t)?.tabsMetadata?.[t],r=m(n,t);if(r===null)return {type:"pane",id:p(),tabs:[t],activeTabId:t,tabsMetadata:u?{[t]:u}:void 0};function l(o){if(o.type==="pane"){if(o.tabs.includes(e)){let y=[...o.tabs].filter(b=>b!==t),d=y.indexOf(e);d<0&&(d=0),s==="after"&&(d+=1),y.splice(d,0,t);let a={...o.tabsMetadata};return u&&(a[t]=u),{...o,tabs:y,activeTabId:t,tabsMetadata:Object.keys(a).length>0?a:void 0}}return o}return {...o,first:l(o.first),second:l(o.second)}}return l(r)}function T(n,t=0,e=0,s=100,i=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:t,top:e,width:s,height:i,node:n}],splitters:[]};let{direction:r,splitPercentage:l,first:o,second:c}=n,d={id:`splitter-${u}-${r}`,currentNode:n,direction:r,left:r==="row"?t+s*(l/100):t,top:r==="column"?e+i*(l/100):e,width:r==="row"?0:s,height:r==="column"?0:i,parentLeft:t,parentTop:e,parentWidth:s,parentHeight:i},a={panes:[],splitters:[]},b={panes:[],splitters:[]};if(r==="row"){let f=s*(l/100);a=T(o,t,e,f,i,`${u}-L`),b=T(c,t+f,e,s-f,i,`${u}-R`);}else {let f=i*(l/100);a=T(o,t,e,s,f,`${u}-T`),b=T(c,t,e+f,s,i-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}export{L as addPane,T as computeLayout,v as findPaneById,N as findPaneContainingTab,k as findTabById,p as generateUniqueId,D as mergeTab,O as moveTab,M as removePane,m as removeTab,C as selectTab,P as splitPane,w as updatePaneLock,x as updateSplitPercentage,S as updateTabMetadata};//# sourceMappingURL=utils.js.map
2
2
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts"],"names":["generateUniqueId","removePane","tree","paneId","newFirst","newSecond","removeTab","tabId","newTabs","t","newActive","newTabsMetadata","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","addPane","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","findPaneById","findPaneContainingTab","findTabById","pane","index","updateTabMetadata","updater","currentTabsMetadata","currentTabMeta","newTabMeta","updatePaneLock","locked","_","rest","selectTab","mergeTab","draggedTabId","targetPaneId","sourceMetadata","cleanTree","moveTab","targetTabId","position","filteredTabs","insertIndex","computeLayout","left","top","width","height","path","splitPercentage","first","second","currentSplitter","firstLayout","secondLayout","firstWidth","firstHeight"],"mappings":"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","file":"utils.js","sourcesContent":["import { TreeNode, SplitNode, SplitDirection, PaneNode, TabDetails } from '../../model'\n\nexport function generateUniqueId(): string {\n return 'pane-' + Math.random().toString(36).substring(2, 11)\n}\n\n/**\n * Tree Helper: Remove a pane container and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, paneId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) return null\n return tree\n }\n const newFirst = removePane(tree.first, paneId)\n const newSecond = removePane(tree.second, paneId)\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: Remove a tab from a pane and consolidate the tree structure if no tabs remain.\n */\nexport function removeTab(tree: TreeNode | null, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.tabs.includes(tabId)) {\n const newTabs = tree.tabs.filter((t) => t !== tabId)\n if (newTabs.length === 0) return null\n let newActive = tree.activeTabId\n if (tree.activeTabId === tabId) {\n newActive = newTabs[0]\n }\n const newTabsMetadata = { ...tree.tabsMetadata }\n delete newTabsMetadata[tabId]\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: newActive,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n const newFirst = removeTab(tree.first, tabId)\n const newSecond = removeTab(tree.second, tabId)\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 if (typeof paneToAdd === 'string') {\n return { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n }\n return paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.id === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string'\n ? { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n : 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: 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', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: 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', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: 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 * Find a PaneNode by its ID.\n */\nexport function findPaneById(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.id === paneId ? tree : null\n }\n return findPaneById(tree.first, paneId) ?? findPaneById(tree.second, paneId)\n}\n\n/**\n * Find a PaneNode containing the given tab ID.\n */\nexport function findPaneContainingTab(tree: TreeNode | null, tabId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.tabs.includes(tabId) ? tree : null\n }\n return findPaneContainingTab(tree.first, tabId) ?? findPaneContainingTab(tree.second, tabId)\n}\n\n/**\n * Find the details of a tab by its ID.\n */\nexport function findTabById(tree: TreeNode | null, tabId: string): TabDetails | null {\n const pane = findPaneContainingTab(tree, tabId)\n if (!pane) return null\n const index = pane.tabs.indexOf(tabId)\n return {\n id: tabId,\n paneId: pane.id,\n isActive: pane.activeTabId === tabId,\n index,\n metadata: pane.tabsMetadata?.[tabId],\n }\n}\n\n/**\n * Update metadata on a specific tab node using an updater function.\n */\nexport function updateTabMetadata(\n tree: TreeNode | null,\n tabId: 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.tabs.includes(tabId)) {\n const currentTabsMetadata = tree.tabsMetadata || {}\n const currentTabMeta = currentTabsMetadata[tabId]\n const newTabMeta = updater(currentTabMeta)\n\n const newTabsMetadata = { ...currentTabsMetadata }\n if (newTabMeta === undefined) {\n delete newTabsMetadata[tabId]\n } else {\n newTabsMetadata[tabId] = newTabMeta\n }\n\n return {\n ...tree,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: updateTabMetadata(tree.first, tabId, updater) ?? tree.first,\n second: updateTabMetadata(tree.second, tabId, updater) ?? tree.second,\n }\n}\n\n/**\n * Update the locked status on a specific pane node in the layout tree.\n */\nexport function updatePaneLock(\n tree: TreeNode | null,\n paneId: string,\n locked: boolean,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n if (locked === false) {\n const { locked: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, locked }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneLock(tree.first, paneId, locked) ?? tree.first,\n second: updatePaneLock(tree.second, paneId, locked) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Activate a tab within a pane.\n */\nexport function selectTab(tree: TreeNode | null, paneId: string, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n return { ...tree, activeTabId: tabId }\n }\n return tree\n }\n return {\n ...tree,\n first: selectTab(tree.first, paneId, tabId) ?? tree.first,\n second: selectTab(tree.second, paneId, tabId) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Merge a tab into a target pane node.\n */\nexport function mergeTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetPaneId: string,\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.id === targetPaneId) {\n const newTabs = [...node.tabs]\n if (!newTabs.includes(draggedTabId)) {\n newTabs.push(draggedTabId)\n }\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: newTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\n/**\n * Tree Helper: Move/reorder a tab inside or to a target pane next to a target tab.\n */\nexport function moveTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetTabId: string,\n position: 'before' | 'after' = 'before',\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.tabs.includes(targetTabId)) {\n const newTabs = [...node.tabs]\n const filteredTabs = newTabs.filter((t) => t !== draggedTabId)\n let insertIndex = filteredTabs.indexOf(targetTabId)\n if (insertIndex < 0) {\n insertIndex = 0\n }\n if (position === 'after') {\n insertIndex += 1\n }\n filteredTabs.splice(insertIndex, 0, draggedTabId)\n\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: filteredTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\nexport interface ComputedPane {\n paneId: string\n left: number\n top: number\n width: number\n height: number\n node: PaneNode\n}\n\nexport interface ComputedSplitter {\n id: string\n currentNode: SplitNode\n direction: SplitDirection\n left: number\n top: number\n width: number\n height: number\n parentLeft: number\n parentTop: number\n parentWidth: number\n parentHeight: number\n}\n\nexport function computeLayout(\n node: TreeNode | null,\n left = 0,\n top = 0,\n width = 100,\n height = 100,\n path = 'root',\n): { panes: ComputedPane[]; splitters: ComputedSplitter[] } {\n if (node === null) return { panes: [], splitters: [] }\n if (node.type === 'pane') {\n return {\n panes: [{ paneId: node.id, left, top, width, height, node }],\n splitters: [],\n }\n }\n\n const { direction, splitPercentage, first, second } = node\n const splitterId = `splitter-${path}-${direction}`\n\n const currentSplitter: ComputedSplitter = {\n id: splitterId,\n currentNode: node,\n direction,\n left: direction === 'row' ? left + width * (splitPercentage / 100) : left,\n top: direction === 'column' ? top + height * (splitPercentage / 100) : top,\n width: direction === 'row' ? 0 : width,\n height: direction === 'column' ? 0 : height,\n parentLeft: left,\n parentTop: top,\n parentWidth: width,\n parentHeight: height,\n }\n\n let firstLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n let secondLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n\n if (direction === 'row') {\n const firstWidth = width * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, firstWidth, height, `${path}-L`)\n secondLayout = computeLayout(\n second,\n left + firstWidth,\n top,\n width - firstWidth,\n height,\n `${path}-R`,\n )\n } else {\n const firstHeight = height * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, width, firstHeight, `${path}-T`)\n secondLayout = computeLayout(\n second,\n left,\n top + firstHeight,\n width,\n height - firstHeight,\n `${path}-B`,\n )\n }\n\n return {\n panes: [...firstLayout.panes, ...secondLayout.panes],\n splitters: [currentSplitter, ...firstLayout.splitters, ...secondLayout.splitters],\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts"],"names":["generateUniqueId","removePane","tree","paneId","newFirst","newSecond","removeTab","tabId","newTabs","t","newActive","newTabsMetadata","splitPane","targetId","direction","splitType","paneToAdd","addedNode","isFirst","addPane","metadata","insert","node","parentDirection","updateSplitPercentage","target","newPercentage","findPaneById","findPaneContainingTab","findTabById","pane","index","updateTabMetadata","updater","currentTabsMetadata","currentTabMeta","newTabMeta","updatePaneLock","locked","_","rest","selectTab","mergeTab","draggedTabId","targetPaneId","sourceMetadata","cleanTree","moveTab","targetTabId","position","filteredTabs","insertIndex","computeLayout","left","top","width","height","path","splitPercentage","first","second","currentSplitter","firstLayout","secondLayout","firstWidth","firstHeight"],"mappings":"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","file":"utils.js","sourcesContent":["import { TreeNode, SplitNode, SplitDirection, PaneNode, TabDetails } from '../../model'\n\nexport function generateUniqueId(): string {\n return 'pane-' + Math.random().toString(36).substring(2, 11)\n}\n\n/**\n * Tree Helper: Remove a pane container and consolidate the tree structure.\n */\nexport function removePane(tree: TreeNode | null, paneId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) return null\n return tree\n }\n const newFirst = removePane(tree.first, paneId)\n const newSecond = removePane(tree.second, paneId)\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: Remove a tab from a pane and consolidate the tree structure if no tabs remain.\n */\nexport function removeTab(tree: TreeNode | null, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.tabs.includes(tabId)) {\n const newTabs = tree.tabs.filter((t) => t !== tabId)\n if (newTabs.length === 0) return null\n let newActive = tree.activeTabId\n if (tree.activeTabId === tabId) {\n newActive = newTabs[0]\n }\n const newTabsMetadata = { ...tree.tabsMetadata }\n delete newTabsMetadata[tabId]\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: newActive,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n const newFirst = removeTab(tree.first, tabId)\n const newSecond = removeTab(tree.second, tabId)\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 if (typeof paneToAdd === 'string') {\n return { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n }\n return paneToAdd\n }\n if (tree.type === 'pane') {\n if (tree.id === targetId) {\n const addedNode: PaneNode =\n typeof paneToAdd === 'string'\n ? { type: 'pane', id: generateUniqueId(), tabs: [paneToAdd], activeTabId: paneToAdd }\n : 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: Add a pane by recursively splitting the rightmost/bottommost pane in the tree.\n */\nexport function addPane(\n tree: TreeNode | null,\n paneToAdd: string,\n metadata?: Record<string, unknown>,\n): TreeNode {\n if (tree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [paneToAdd],\n activeTabId: paneToAdd,\n tabsMetadata: metadata ? { [paneToAdd]: metadata } : undefined,\n }\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: {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [paneToAdd],\n activeTabId: paneToAdd,\n tabsMetadata: metadata ? { [paneToAdd]: metadata } : undefined,\n },\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 * Find a PaneNode by its ID.\n */\nexport function findPaneById(tree: TreeNode | null, paneId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.id === paneId ? tree : null\n }\n return findPaneById(tree.first, paneId) ?? findPaneById(tree.second, paneId)\n}\n\n/**\n * Find a PaneNode containing the given tab ID.\n */\nexport function findPaneContainingTab(tree: TreeNode | null, tabId: string): PaneNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.tabs.includes(tabId) ? tree : null\n }\n return findPaneContainingTab(tree.first, tabId) ?? findPaneContainingTab(tree.second, tabId)\n}\n\n/**\n * Find the details of a tab by its ID.\n */\nexport function findTabById(tree: TreeNode | null, tabId: string): TabDetails | null {\n const pane = findPaneContainingTab(tree, tabId)\n if (!pane) return null\n const index = pane.tabs.indexOf(tabId)\n return {\n id: tabId,\n paneId: pane.id,\n isActive: pane.activeTabId === tabId,\n index,\n metadata: pane.tabsMetadata?.[tabId],\n }\n}\n\n/**\n * Update metadata on a specific tab node using an updater function.\n */\nexport function updateTabMetadata(\n tree: TreeNode | null,\n tabId: 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.tabs.includes(tabId)) {\n const currentTabsMetadata = tree.tabsMetadata || {}\n const currentTabMeta = currentTabsMetadata[tabId]\n const newTabMeta = updater(currentTabMeta)\n\n const newTabsMetadata = { ...currentTabsMetadata }\n if (newTabMeta === undefined) {\n delete newTabsMetadata[tabId]\n } else {\n newTabsMetadata[tabId] = newTabMeta\n }\n\n return {\n ...tree,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: updateTabMetadata(tree.first, tabId, updater) ?? tree.first,\n second: updateTabMetadata(tree.second, tabId, updater) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Add a tab directly to a specific target pane node.\n */\nexport function addTab(\n tree: TreeNode | null,\n targetPaneId: string,\n tabId: string,\n metadata?: Record<string, unknown>,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === targetPaneId) {\n const newTabs = [...tree.tabs]\n if (!newTabs.includes(tabId)) {\n newTabs.push(tabId)\n }\n let newTabsMetadata = tree.tabsMetadata\n if (metadata) {\n newTabsMetadata = {\n ...tree.tabsMetadata,\n [tabId]: metadata,\n }\n }\n return {\n ...tree,\n tabs: newTabs,\n activeTabId: tabId,\n tabsMetadata: newTabsMetadata,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: addTab(tree.first, targetPaneId, tabId, metadata) || tree.first,\n second: addTab(tree.second, targetPaneId, tabId, metadata) || tree.second,\n }\n}\n\n/**\n * Update the locked status on a specific pane node in the layout tree.\n */\nexport function updatePaneLock(\n tree: TreeNode | null,\n paneId: string,\n locked: boolean,\n): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n if (locked === false) {\n const { locked: _, ...rest } = tree\n return rest as PaneNode\n }\n return { ...tree, locked }\n }\n return tree\n }\n return {\n ...tree,\n first: updatePaneLock(tree.first, paneId, locked) ?? tree.first,\n second: updatePaneLock(tree.second, paneId, locked) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Activate a tab within a pane.\n */\nexport function selectTab(tree: TreeNode | null, paneId: string, tabId: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.id === paneId) {\n return { ...tree, activeTabId: tabId }\n }\n return tree\n }\n return {\n ...tree,\n first: selectTab(tree.first, paneId, tabId) ?? tree.first,\n second: selectTab(tree.second, paneId, tabId) ?? tree.second,\n }\n}\n\n/**\n * Tree Helper: Merge a tab into a target pane node.\n */\nexport function mergeTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetPaneId: string,\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.id === targetPaneId) {\n const newTabs = [...node.tabs]\n if (!newTabs.includes(draggedTabId)) {\n newTabs.push(draggedTabId)\n }\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: newTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\n/**\n * Tree Helper: Move/reorder a tab inside or to a target pane next to a target tab.\n */\nexport function moveTab(\n tree: TreeNode | null,\n draggedTabId: string,\n targetTabId: string,\n position: 'before' | 'after' = 'before',\n): TreeNode | null {\n if (tree === null) return null\n\n const sourcePane = findPaneContainingTab(tree, draggedTabId)\n const sourceMetadata = sourcePane?.tabsMetadata?.[draggedTabId]\n\n const cleanTree = removeTab(tree, draggedTabId)\n if (cleanTree === null) {\n return {\n type: 'pane',\n id: generateUniqueId(),\n tabs: [draggedTabId],\n activeTabId: draggedTabId,\n tabsMetadata: sourceMetadata ? { [draggedTabId]: sourceMetadata } : undefined,\n }\n }\n\n function insert(node: TreeNode): TreeNode {\n if (node.type === 'pane') {\n if (node.tabs.includes(targetTabId)) {\n const newTabs = [...node.tabs]\n const filteredTabs = newTabs.filter((t) => t !== draggedTabId)\n let insertIndex = filteredTabs.indexOf(targetTabId)\n if (insertIndex < 0) {\n insertIndex = 0\n }\n if (position === 'after') {\n insertIndex += 1\n }\n filteredTabs.splice(insertIndex, 0, draggedTabId)\n\n const newTabsMetadata = { ...node.tabsMetadata }\n if (sourceMetadata) {\n newTabsMetadata[draggedTabId] = sourceMetadata\n }\n return {\n ...node,\n tabs: filteredTabs,\n activeTabId: draggedTabId,\n tabsMetadata: Object.keys(newTabsMetadata).length > 0 ? newTabsMetadata : undefined,\n }\n }\n return node\n }\n return {\n ...node,\n first: insert(node.first),\n second: insert(node.second),\n }\n }\n\n return insert(cleanTree)\n}\n\nexport interface ComputedPane {\n paneId: string\n left: number\n top: number\n width: number\n height: number\n node: PaneNode\n}\n\nexport interface ComputedSplitter {\n id: string\n currentNode: SplitNode\n direction: SplitDirection\n left: number\n top: number\n width: number\n height: number\n parentLeft: number\n parentTop: number\n parentWidth: number\n parentHeight: number\n}\n\nexport function computeLayout(\n node: TreeNode | null,\n left = 0,\n top = 0,\n width = 100,\n height = 100,\n path = 'root',\n): { panes: ComputedPane[]; splitters: ComputedSplitter[] } {\n if (node === null) return { panes: [], splitters: [] }\n if (node.type === 'pane') {\n return {\n panes: [{ paneId: node.id, left, top, width, height, node }],\n splitters: [],\n }\n }\n\n const { direction, splitPercentage, first, second } = node\n const splitterId = `splitter-${path}-${direction}`\n\n const currentSplitter: ComputedSplitter = {\n id: splitterId,\n currentNode: node,\n direction,\n left: direction === 'row' ? left + width * (splitPercentage / 100) : left,\n top: direction === 'column' ? top + height * (splitPercentage / 100) : top,\n width: direction === 'row' ? 0 : width,\n height: direction === 'column' ? 0 : height,\n parentLeft: left,\n parentTop: top,\n parentWidth: width,\n parentHeight: height,\n }\n\n let firstLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n let secondLayout = { panes: [] as ComputedPane[], splitters: [] as ComputedSplitter[] }\n\n if (direction === 'row') {\n const firstWidth = width * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, firstWidth, height, `${path}-L`)\n secondLayout = computeLayout(\n second,\n left + firstWidth,\n top,\n width - firstWidth,\n height,\n `${path}-R`,\n )\n } else {\n const firstHeight = height * (splitPercentage / 100)\n firstLayout = computeLayout(first, left, top, width, firstHeight, `${path}-T`)\n secondLayout = computeLayout(\n second,\n left,\n top + firstHeight,\n width,\n height - firstHeight,\n `${path}-B`,\n )\n }\n\n return {\n panes: [...firstLayout.panes, ...secondLayout.panes],\n splitters: [currentSplitter, ...firstLayout.splitters, ...secondLayout.splitters],\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-zeugma",
3
- "version": "5.1.0",
3
+ "version": "5.2.1",
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,
@@ -62,6 +62,8 @@
62
62
  "typecheck": "tsc --noEmit",
63
63
  "format": "prettier --write \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
64
64
  "format:check": "prettier --check \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
65
67
  "version": "changeset version",
66
68
  "release": "npm run build && changeset publish"
67
69
  },
@@ -76,17 +78,21 @@
76
78
  },
77
79
  "devDependencies": {
78
80
  "@changesets/cli": "^2.31.0",
81
+ "@testing-library/dom": "^10.4.1",
82
+ "@testing-library/react": "^16.3.2",
79
83
  "@types/node": "^25.9.1",
80
84
  "@types/react": "^19.2.15",
81
85
  "@types/react-dom": "^19.2.3",
82
86
  "eslint": "^10.4.1",
83
87
  "husky": "^9.1.7",
88
+ "jsdom": "^29.1.1",
84
89
  "lint-staged": "^16.4.0",
85
90
  "prettier": "^3.8.3",
86
91
  "react": "^19.2.6",
87
92
  "react-dom": "^19.2.6",
88
93
  "tsup": "^8.5.1",
89
94
  "typescript": "^6.0.3",
90
- "typescript-eslint": "^8.60.0"
95
+ "typescript-eslint": "^8.60.0",
96
+ "vitest": "^4.1.9"
91
97
  }
92
98
  }