react-zeugma 6.0.4 → 6.1.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/dist/utils.cjs CHANGED
@@ -1,2 +1,2 @@
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 D(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 T(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:T(n.first,t)??T(n.second,t)}function g(n,t){let e=T(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,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function L(n,t,e){if(n===null)return null;let i=T(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 k(n,t,e,s="before"){if(n===null)return null;let u=T(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 N(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=N(o,t,e,f,i,`${u}-L`),b=N(c,t+f,e,s-f,i,`${u}-R`);}else {let f=i*(l/100);a=N(o,t,e,s,f,`${u}-T`),b=N(c,t,e+f,s,i-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}function O(n,t,e,s){if(!(t==="tab"&&e&&n.includes(e))||!s)return -1;let r=n.indexOf(e);return s==="before"?r:r+1}exports.addPane=D;exports.calculateTabDropIndex=O;exports.computeLayout=N;exports.findPaneById=v;exports.findPaneContainingTab=T;exports.findTabById=g;exports.generateUniqueId=p;exports.mergeTab=L;exports.moveTab=k;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
1
+ 'use strict';function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function x(n,e){if(n===null)return null;if(n.type==="pane")return n.id===e?null:n;let t=x(n.first,e),r=x(n.second,e);return t===null?r:r===null?t:{...n,first:t,second:r}}function y(n,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(e)){let i=n.tabs.filter(l=>l!==e);if(i.length===0)return null;let u=n.activeTabId;n.activeTabId===e&&(u=i[0]);let s={...n.tabsMetadata};return delete s[e],{...n,tabs:i,activeTabId:u,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}let t=y(n.first,e),r=y(n.second,e);return t===null?r:r===null?t:{...n,first:t,second:r}}function M(n,e,t,r,i){if(n===null)return typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i;if(n.type==="pane"){if(n.id===e){let u=typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i,s=r==="left"||r==="top";return {type:"split",direction:t,first:s?u:n,second:s?n:u,splitPercentage:50}}return n}return {...n,first:M(n.first,e,t,r,i)||n.first,second:M(n.second,e,t,r,i)||n.second}}function h(n,e,t){if(n===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:t?{[e]:t}:void 0};function r(i,u){return i.type==="pane"?{type:"split",direction:u==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:t?{[e]:t}:void 0}}:{...i,second:r(i.second,i.direction)}}return r(n,null)}function P(n,e,t){return n===null?null:n===e?{...n,splitPercentage:t}:n.type==="split"?{...n,first:P(n.first,e,t)||n.first,second:P(n.second,e,t)||n.second}:n}function S(n,e){return n===null?null:n.type==="pane"?n.id===e?n:null:S(n.first,e)??S(n.second,e)}function T(n,e){return n===null?null:n.type==="pane"?n.tabs.includes(e)?n:null:T(n.first,e)??T(n.second,e)}function g(n,e){let t=T(n,e);if(!t)return null;let r=t.tabs.indexOf(e);return {id:e,paneId:t.id,isActive:t.activeTabId===e,index:r,metadata:t.tabsMetadata?.[e]}}function v(n,e,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(e)){let r=n.tabsMetadata||{},i=r[e],u=t(i),s={...r};return u===void 0?delete s[e]:s[e]=u,{...n,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}return {...n,first:v(n.first,e,t)??n.first,second:v(n.second,e,t)??n.second}}function w(n,e,t){if(n===null)return null;if(n.type==="pane"){if(n.id===e){if(t===false){let{locked:r,...i}=n;return i}return {...n,locked:t}}return n}return {...n,first:w(n.first,e,t)??n.first,second:w(n.second,e,t)??n.second}}function C(n,e,t){return n===null?null:n.type==="pane"?n.id===e?n.activeTabId===t?n:{...n,activeTabId:t}:n:{...n,first:C(n.first,e,t)??n.first,second:C(n.second,e,t)??n.second}}function k(n,e,t){if(n===null)return null;let i=T(n,e)?.tabsMetadata?.[e],u=y(n,e);if(u===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:i?{[e]:i}:void 0};function s(l){if(l.type==="pane"){if(l.id===t){let a=[...l.tabs];a.includes(e)||a.push(e);let c={...l.tabsMetadata};return i&&(c[e]=i),{...l,tabs:a,activeTabId:e,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 L(n,e,t,r="before"){if(n===null)return null;let u=T(n,e)?.tabsMetadata?.[e],s=y(n,e);if(s===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:u?{[e]:u}:void 0};function l(a){if(a.type==="pane"){if(a.tabs.includes(t)){let N=[...a.tabs].filter(b=>b!==e),d=N.indexOf(t);d<0&&(d=0),r==="after"&&(d+=1),N.splice(d,0,e);let o={...a.tabsMetadata};return u&&(o[e]=u),{...a,tabs:N,activeTabId:e,tabsMetadata:Object.keys(o).length>0?o:void 0}}return a}return {...a,first:l(a.first),second:l(a.second)}}return l(s)}function m(n,e=0,t=0,r=100,i=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:e,top:t,width:r,height:i,node:n}],splitters:[]};let{direction:s,splitPercentage:l,first:a,second:c}=n,d={id:`splitter-${u}-${s}`,currentNode:n,direction:s,left:s==="row"?e+r*(l/100):e,top:s==="column"?t+i*(l/100):t,width:s==="row"?0:r,height:s==="column"?0:i,parentLeft:e,parentTop:t,parentWidth:r,parentHeight:i},o={panes:[],splitters:[]},b={panes:[],splitters:[]};if(s==="row"){let f=r*(l/100);o=m(a,e,t,f,i,`${u}-L`),b=m(c,e+f,t,r-f,i,`${u}-R`);}else {let f=i*(l/100);o=m(a,e,t,r,f,`${u}-T`),b=m(c,e,t+f,r,i-f,`${u}-B`);}return {panes:[...o.panes,...b.panes],splitters:[d,...o.splitters,...b.splitters]}}function O(n,e,t,r){if(!(e==="tab"&&t&&n.includes(t))||!r)return -1;let s=n.indexOf(t);return r==="before"?s:s+1}function E(n){let e=document.getElementById(n);return e||(e=document.createElement("div"),e.id=n,e.style.display="none",document.body.appendChild(e)),e}exports.addPane=h;exports.calculateTabDropIndex=O;exports.computeLayout=m;exports.findPaneById=S;exports.findPaneContainingTab=T;exports.findTabById=g;exports.generateUniqueId=p;exports.getOrCreateHiddenContainer=E;exports.mergeTab=k;exports.moveTab=L;exports.removePane=x;exports.removeTab=y;exports.selectTab=C;exports.splitPane=M;exports.updatePaneLock=w;exports.updateSplitPercentage=P;exports.updateTabMetadata=v;//# 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","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","calculateTabDropIndex","tabs","activeType","overTabId","overTabPosition"],"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 if (tree.activeTabId === tabId) return tree\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\n/**\n * Calculates the target drop insertion index in a list of tabs during a drag.\n * Returns -1 if the drop target is not in the list.\n */\nexport function calculateTabDropIndex(\n tabs: string[],\n activeType: string | null,\n overTabId: string | null,\n overTabPosition: 'before' | 'after' | null,\n): number {\n const isDraggingTab = activeType === 'tab'\n const isHoveredTabInThisPane = isDraggingTab && overTabId && tabs.includes(overTabId)\n if (!isHoveredTabInThisPane || !overTabPosition) {\n return -1\n }\n const index = tabs.indexOf(overTabId)\n return overTabPosition === 'before' ? index : index + 1\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts","../src/shared/lib/dom.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","calculateTabDropIndex","tabs","activeType","overTabId","overTabPosition","getOrCreateHiddenContainer","id","container"],"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 if (tree.activeTabId === tabId) return tree\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\n/**\n * Calculates the target drop insertion index in a list of tabs during a drag.\n * Returns -1 if the drop target is not in the list.\n */\nexport function calculateTabDropIndex(\n tabs: string[],\n activeType: string | null,\n overTabId: string | null,\n overTabPosition: 'before' | 'after' | null,\n): number {\n const isDraggingTab = activeType === 'tab'\n const isHoveredTabInThisPane = isDraggingTab && overTabId && tabs.includes(overTabId)\n if (!isHoveredTabInThisPane || !overTabPosition) {\n return -1\n }\n const index = tabs.indexOf(overTabId)\n return overTabPosition === 'before' ? index : index + 1\n}\n","/**\n * Utility to copy stylesheets from source document to destination document.\n */\nexport function copyStyles(srcDoc: Document, destDoc: Document) {\n Array.from(srcDoc.styleSheets).forEach((sheet) => {\n try {\n if (sheet.cssRules) {\n const newStyle = destDoc.createElement('style')\n Array.from(sheet.cssRules).forEach((rule) => {\n newStyle.appendChild(destDoc.createTextNode(rule.cssText))\n })\n destDoc.head.appendChild(newStyle)\n } else if (sheet.href) {\n const newLink = destDoc.createElement('link')\n newLink.rel = 'stylesheet'\n newLink.href = sheet.href\n destDoc.head.appendChild(newLink)\n }\n } catch {\n if (sheet.href) {\n const newLink = destDoc.createElement('link')\n newLink.rel = 'stylesheet'\n newLink.href = sheet.href\n destDoc.head.appendChild(newLink)\n }\n }\n })\n}\n\n/**\n * Utility to get or create a hidden container element on the document body.\n */\nexport function getOrCreateHiddenContainer(id: string): HTMLElement {\n let container = document.getElementById(id)\n if (!container) {\n container = document.createElement('div')\n container.id = id\n container.style.display = 'none'\n document.body.appendChild(container)\n }\n return container\n}\n"]}
package/dist/utils.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-Kf7gkm94.cjs';
1
+ import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './dom-DrgwRi7G.cjs';
2
+ export { k as getOrCreateHiddenContainer } from './dom-DrgwRi7G.cjs';
2
3
  import 'react';
3
4
 
4
5
  declare function generateUniqueId(): string;
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-Kf7gkm94.js';
1
+ import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './dom-DrgwRi7G.js';
2
+ export { k as getOrCreateHiddenContainer } from './dom-DrgwRi7G.js';
2
3
  import 'react';
3
4
 
4
5
  declare function generateUniqueId(): string;
package/dist/utils.js CHANGED
@@ -1,2 +1,2 @@
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 D(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 T(n,t){return n===null?null:n.type==="pane"?n.tabs.includes(t)?n:null:T(n.first,t)??T(n.second,t)}function g(n,t){let e=T(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,activeTabId:e}:n:{...n,first:C(n.first,t,e)??n.first,second:C(n.second,t,e)??n.second}}function L(n,t,e){if(n===null)return null;let i=T(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 k(n,t,e,s="before"){if(n===null)return null;let u=T(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 N(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=N(o,t,e,f,i,`${u}-L`),b=N(c,t+f,e,s-f,i,`${u}-R`);}else {let f=i*(l/100);a=N(o,t,e,s,f,`${u}-T`),b=N(c,t,e+f,s,i-f,`${u}-B`);}return {panes:[...a.panes,...b.panes],splitters:[d,...a.splitters,...b.splitters]}}function O(n,t,e,s){if(!(t==="tab"&&e&&n.includes(e))||!s)return -1;let r=n.indexOf(e);return s==="before"?r:r+1}export{D as addPane,O as calculateTabDropIndex,N as computeLayout,v as findPaneById,T as findPaneContainingTab,g as findTabById,p as generateUniqueId,L as mergeTab,k 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
1
+ function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function x(n,e){if(n===null)return null;if(n.type==="pane")return n.id===e?null:n;let t=x(n.first,e),r=x(n.second,e);return t===null?r:r===null?t:{...n,first:t,second:r}}function y(n,e){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(e)){let i=n.tabs.filter(l=>l!==e);if(i.length===0)return null;let u=n.activeTabId;n.activeTabId===e&&(u=i[0]);let s={...n.tabsMetadata};return delete s[e],{...n,tabs:i,activeTabId:u,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}let t=y(n.first,e),r=y(n.second,e);return t===null?r:r===null?t:{...n,first:t,second:r}}function M(n,e,t,r,i){if(n===null)return typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i;if(n.type==="pane"){if(n.id===e){let u=typeof i=="string"?{type:"pane",id:p(),tabs:[i],activeTabId:i}:i,s=r==="left"||r==="top";return {type:"split",direction:t,first:s?u:n,second:s?n:u,splitPercentage:50}}return n}return {...n,first:M(n.first,e,t,r,i)||n.first,second:M(n.second,e,t,r,i)||n.second}}function h(n,e,t){if(n===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:t?{[e]:t}:void 0};function r(i,u){return i.type==="pane"?{type:"split",direction:u==="row"?"column":"row",splitPercentage:50,first:i,second:{type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:t?{[e]:t}:void 0}}:{...i,second:r(i.second,i.direction)}}return r(n,null)}function P(n,e,t){return n===null?null:n===e?{...n,splitPercentage:t}:n.type==="split"?{...n,first:P(n.first,e,t)||n.first,second:P(n.second,e,t)||n.second}:n}function S(n,e){return n===null?null:n.type==="pane"?n.id===e?n:null:S(n.first,e)??S(n.second,e)}function T(n,e){return n===null?null:n.type==="pane"?n.tabs.includes(e)?n:null:T(n.first,e)??T(n.second,e)}function g(n,e){let t=T(n,e);if(!t)return null;let r=t.tabs.indexOf(e);return {id:e,paneId:t.id,isActive:t.activeTabId===e,index:r,metadata:t.tabsMetadata?.[e]}}function v(n,e,t){if(n===null)return null;if(n.type==="pane"){if(n.tabs.includes(e)){let r=n.tabsMetadata||{},i=r[e],u=t(i),s={...r};return u===void 0?delete s[e]:s[e]=u,{...n,tabsMetadata:Object.keys(s).length>0?s:void 0}}return n}return {...n,first:v(n.first,e,t)??n.first,second:v(n.second,e,t)??n.second}}function w(n,e,t){if(n===null)return null;if(n.type==="pane"){if(n.id===e){if(t===false){let{locked:r,...i}=n;return i}return {...n,locked:t}}return n}return {...n,first:w(n.first,e,t)??n.first,second:w(n.second,e,t)??n.second}}function C(n,e,t){return n===null?null:n.type==="pane"?n.id===e?n.activeTabId===t?n:{...n,activeTabId:t}:n:{...n,first:C(n.first,e,t)??n.first,second:C(n.second,e,t)??n.second}}function k(n,e,t){if(n===null)return null;let i=T(n,e)?.tabsMetadata?.[e],u=y(n,e);if(u===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:i?{[e]:i}:void 0};function s(l){if(l.type==="pane"){if(l.id===t){let a=[...l.tabs];a.includes(e)||a.push(e);let c={...l.tabsMetadata};return i&&(c[e]=i),{...l,tabs:a,activeTabId:e,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 L(n,e,t,r="before"){if(n===null)return null;let u=T(n,e)?.tabsMetadata?.[e],s=y(n,e);if(s===null)return {type:"pane",id:p(),tabs:[e],activeTabId:e,tabsMetadata:u?{[e]:u}:void 0};function l(a){if(a.type==="pane"){if(a.tabs.includes(t)){let N=[...a.tabs].filter(b=>b!==e),d=N.indexOf(t);d<0&&(d=0),r==="after"&&(d+=1),N.splice(d,0,e);let o={...a.tabsMetadata};return u&&(o[e]=u),{...a,tabs:N,activeTabId:e,tabsMetadata:Object.keys(o).length>0?o:void 0}}return a}return {...a,first:l(a.first),second:l(a.second)}}return l(s)}function m(n,e=0,t=0,r=100,i=100,u="root"){if(n===null)return {panes:[],splitters:[]};if(n.type==="pane")return {panes:[{paneId:n.id,left:e,top:t,width:r,height:i,node:n}],splitters:[]};let{direction:s,splitPercentage:l,first:a,second:c}=n,d={id:`splitter-${u}-${s}`,currentNode:n,direction:s,left:s==="row"?e+r*(l/100):e,top:s==="column"?t+i*(l/100):t,width:s==="row"?0:r,height:s==="column"?0:i,parentLeft:e,parentTop:t,parentWidth:r,parentHeight:i},o={panes:[],splitters:[]},b={panes:[],splitters:[]};if(s==="row"){let f=r*(l/100);o=m(a,e,t,f,i,`${u}-L`),b=m(c,e+f,t,r-f,i,`${u}-R`);}else {let f=i*(l/100);o=m(a,e,t,r,f,`${u}-T`),b=m(c,e,t+f,r,i-f,`${u}-B`);}return {panes:[...o.panes,...b.panes],splitters:[d,...o.splitters,...b.splitters]}}function O(n,e,t,r){if(!(e==="tab"&&t&&n.includes(t))||!r)return -1;let s=n.indexOf(t);return r==="before"?s:s+1}function E(n){let e=document.getElementById(n);return e||(e=document.createElement("div"),e.id=n,e.style.display="none",document.body.appendChild(e)),e}export{h as addPane,O as calculateTabDropIndex,m as computeLayout,S as findPaneById,T as findPaneContainingTab,g as findTabById,p as generateUniqueId,E as getOrCreateHiddenContainer,k as mergeTab,L as moveTab,x as removePane,y as removeTab,C as selectTab,M as splitPane,w as updatePaneLock,P as updateSplitPercentage,v 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","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","calculateTabDropIndex","tabs","activeType","overTabId","overTabPosition"],"mappings":"AAEO,SAASA,GAA2B,CACzC,OAAO,OAAA,CAAU,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,EAAE,CAC7D,CAKO,SAASC,CAAAA,CAAWC,CAAAA,CAAuBC,CAAAA,CAAiC,CACjF,GAAID,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,CAAAA,CAAK,IAAA,GAAS,MAAA,CAChB,OAAIA,EAAK,EAAA,GAAOC,CAAAA,CAAe,IAAA,CACxBD,CAAAA,CAET,IAAME,CAAAA,CAAWH,CAAAA,CAAWC,CAAAA,CAAK,KAAA,CAAOC,CAAM,CAAA,CACxCE,CAAAA,CAAYJ,CAAAA,CAAWC,CAAAA,CAAK,OAAQC,CAAM,CAAA,CAChD,OAAIC,CAAAA,GAAa,KAAaC,CAAAA,CAC1BA,CAAAA,GAAc,IAAA,CAAaD,CAAAA,CACxB,CAAE,GAAGF,CAAAA,CAAM,KAAA,CAAOE,CAAAA,CAAU,OAAQC,CAAU,CACvD,CAKO,SAASC,EAAUJ,CAAAA,CAAuBK,CAAAA,CAAgC,CAC/E,GAAIL,IAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,EAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,EAAK,IAAA,CAAK,QAAA,CAASK,CAAK,CAAA,CAAG,CAC7B,IAAMC,CAAAA,CAAUN,CAAAA,CAAK,IAAA,CAAK,OAAQO,CAAAA,EAAMA,CAAAA,GAAMF,CAAK,CAAA,CACnD,GAAIC,CAAAA,CAAQ,MAAA,GAAW,CAAA,CAAG,OAAO,KACjC,IAAIE,CAAAA,CAAYR,CAAAA,CAAK,WAAA,CACjBA,EAAK,WAAA,GAAgBK,CAAAA,GACvBG,CAAAA,CAAYF,CAAAA,CAAQ,CAAC,CAAA,CAAA,CAEvB,IAAMG,CAAAA,CAAkB,CAAE,GAAGT,CAAAA,CAAK,YAAa,CAAA,CAC/C,OAAA,OAAOS,EAAgBJ,CAAK,CAAA,CACrB,CACL,GAAGL,EACH,IAAA,CAAMM,CAAAA,CACN,WAAA,CAAaE,CAAAA,CACb,aAAc,MAAA,CAAO,IAAA,CAAKC,CAAe,CAAA,CAAE,OAAS,CAAA,CAAIA,CAAAA,CAAkB,MAC5E,CACF,CACA,OAAOT,CACT,CACA,IAAME,EAAWE,CAAAA,CAAUJ,CAAAA,CAAK,KAAA,CAAOK,CAAK,EACtCF,CAAAA,CAAYC,CAAAA,CAAUJ,CAAAA,CAAK,MAAA,CAAQK,CAAK,CAAA,CAC9C,OAAIH,CAAAA,GAAa,IAAA,CAAaC,EAC1BA,CAAAA,GAAc,IAAA,CAAaD,CAAAA,CACxB,CAAE,GAAGF,CAAAA,CAAM,KAAA,CAAOE,CAAAA,CAAU,MAAA,CAAQC,CAAU,CACvD,CAKO,SAASO,CAAAA,CACdV,EACAW,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAId,CAAAA,GAAS,IAAA,CACX,OAAI,OAAOc,CAAAA,EAAc,QAAA,CAChB,CAAE,IAAA,CAAM,OAAQ,EAAA,CAAIhB,CAAAA,EAAiB,CAAG,IAAA,CAAM,CAACgB,CAAS,CAAA,CAAG,WAAA,CAAaA,CAAU,EAEpFA,CAAAA,CAET,GAAId,CAAAA,CAAK,IAAA,GAAS,OAAQ,CACxB,GAAIA,CAAAA,CAAK,EAAA,GAAOW,EAAU,CACxB,IAAMI,CAAAA,CACJ,OAAOD,GAAc,QAAA,CACjB,CAAE,IAAA,CAAM,MAAA,CAAQ,GAAIhB,CAAAA,EAAiB,CAAG,IAAA,CAAM,CAACgB,CAAS,CAAA,CAAG,WAAA,CAAaA,CAAU,CAAA,CAClFA,EACAE,CAAAA,CAAUH,CAAAA,GAAc,MAAA,EAAUA,CAAAA,GAAc,MACtD,OAAO,CACL,IAAA,CAAM,OAAA,CACN,UAAAD,CAAAA,CACA,KAAA,CAAOI,CAAAA,CAAUD,CAAAA,CAAYf,EAC7B,MAAA,CAAQgB,CAAAA,CAAUhB,CAAAA,CAAOe,CAAAA,CACzB,gBAAiB,EACnB,CACF,CACA,OAAOf,CACT,CACA,OAAO,CACL,GAAGA,EACH,KAAA,CAAOU,CAAAA,CAAUV,CAAAA,CAAK,KAAA,CAAOW,EAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,CAAA,EAAKd,EAAK,KAAA,CAChF,MAAA,CAAQU,CAAAA,CAAUV,CAAAA,CAAK,OAAQW,CAAAA,CAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,GAAKd,CAAAA,CAAK,MACpF,CACF,CAKO,SAASiB,CAAAA,CACdjB,CAAAA,CACAc,CAAAA,CACAI,CAAAA,CACU,CACV,GAAIlB,CAAAA,GAAS,IAAA,CACX,OAAO,CACL,IAAA,CAAM,MAAA,CACN,EAAA,CAAIF,CAAAA,GACJ,IAAA,CAAM,CAACgB,CAAS,CAAA,CAChB,YAAaA,CAAAA,CACb,YAAA,CAAcI,CAAAA,CAAW,CAAE,CAACJ,CAAS,EAAGI,CAAS,CAAA,CAAI,MACvD,EAGF,SAASC,CAAAA,CAAOC,CAAAA,CAAgBC,CAAAA,CAAkD,CAChF,OAAID,CAAAA,CAAK,IAAA,GAAS,MAAA,CAET,CACL,IAAA,CAAM,OAAA,CACN,SAAA,CAHgCC,CAAAA,GAAoB,MAAQ,QAAA,CAAW,KAAA,CAIvE,eAAA,CAAiB,EAAA,CACjB,MAAOD,CAAAA,CACP,MAAA,CAAQ,CACN,IAAA,CAAM,OACN,EAAA,CAAItB,CAAAA,EAAiB,CACrB,IAAA,CAAM,CAACgB,CAAS,CAAA,CAChB,WAAA,CAAaA,CAAAA,CACb,aAAcI,CAAAA,CAAW,CAAE,CAACJ,CAAS,EAAGI,CAAS,CAAA,CAAI,MACvD,CACF,EAGK,CACL,GAAGE,CAAAA,CACH,MAAA,CAAQD,EAAOC,CAAAA,CAAK,MAAA,CAAQA,CAAAA,CAAK,SAAS,CAC5C,CACF,CAEA,OAAOD,CAAAA,CAAOnB,EAAM,IAAI,CAC1B,CAKO,SAASsB,EACdtB,CAAAA,CACAuB,CAAAA,CACAC,CAAAA,CACiB,CACjB,OAAIxB,CAAAA,GAAS,IAAA,CAAa,IAAA,CACtBA,CAAAA,GAASuB,EACJ,CAAE,GAAGvB,CAAAA,CAAM,eAAA,CAAiBwB,CAAc,CAAA,CAE/CxB,CAAAA,CAAK,IAAA,GAAS,OAAA,CACT,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOsB,CAAAA,CAAsBtB,EAAK,KAAA,CAAOuB,CAAAA,CAAQC,CAAa,CAAA,EAAKxB,EAAK,KAAA,CACxE,MAAA,CAAQsB,CAAAA,CAAsBtB,CAAAA,CAAK,OAAQuB,CAAAA,CAAQC,CAAa,CAAA,EAAKxB,CAAAA,CAAK,MAC5E,CAAA,CAEKA,CACT,CAKO,SAASyB,EAAazB,CAAAA,CAAuBC,CAAAA,CAAiC,CACnF,OAAID,IAAS,IAAA,CAAa,IAAA,CACtBA,CAAAA,CAAK,IAAA,GAAS,OACTA,CAAAA,CAAK,EAAA,GAAOC,CAAAA,CAASD,CAAAA,CAAO,KAE9ByB,CAAAA,CAAazB,CAAAA,CAAK,KAAA,CAAOC,CAAM,GAAKwB,CAAAA,CAAazB,CAAAA,CAAK,MAAA,CAAQC,CAAM,CAC7E,CAKO,SAASyB,CAAAA,CAAsB1B,CAAAA,CAAuBK,EAAgC,CAC3F,OAAIL,CAAAA,GAAS,IAAA,CAAa,KACtBA,CAAAA,CAAK,IAAA,GAAS,MAAA,CACTA,CAAAA,CAAK,KAAK,QAAA,CAASK,CAAK,CAAA,CAAIL,CAAAA,CAAO,KAErC0B,CAAAA,CAAsB1B,CAAAA,CAAK,KAAA,CAAOK,CAAK,GAAKqB,CAAAA,CAAsB1B,CAAAA,CAAK,MAAA,CAAQK,CAAK,CAC7F,CAKO,SAASsB,CAAAA,CAAY3B,CAAAA,CAAuBK,EAAkC,CACnF,IAAMuB,CAAAA,CAAOF,CAAAA,CAAsB1B,EAAMK,CAAK,CAAA,CAC9C,GAAI,CAACuB,EAAM,OAAO,IAAA,CAClB,IAAMC,CAAAA,CAAQD,EAAK,IAAA,CAAK,OAAA,CAAQvB,CAAK,CAAA,CACrC,OAAO,CACL,EAAA,CAAIA,CAAAA,CACJ,MAAA,CAAQuB,EAAK,EAAA,CACb,QAAA,CAAUA,CAAAA,CAAK,WAAA,GAAgBvB,EAC/B,KAAA,CAAAwB,CAAAA,CACA,QAAA,CAAUD,CAAAA,CAAK,eAAevB,CAAK,CACrC,CACF,CAKO,SAASyB,CAAAA,CACd9B,CAAAA,CACAK,CAAAA,CACA0B,CAAAA,CACiB,CACjB,GAAI/B,CAAAA,GAAS,IAAA,CAAM,OAAO,KAC1B,GAAIA,CAAAA,CAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,IAAA,CAAK,QAAA,CAASK,CAAK,CAAA,CAAG,CAC7B,IAAM2B,CAAAA,CAAsBhC,EAAK,YAAA,EAAgB,EAAC,CAC5CiC,CAAAA,CAAiBD,EAAoB3B,CAAK,CAAA,CAC1C6B,CAAAA,CAAaH,CAAAA,CAAQE,CAAc,CAAA,CAEnCxB,CAAAA,CAAkB,CAAE,GAAGuB,CAAoB,CAAA,CACjD,OAAIE,CAAAA,GAAe,MAAA,CACjB,OAAOzB,CAAAA,CAAgBJ,CAAK,CAAA,CAE5BI,CAAAA,CAAgBJ,CAAK,CAAA,CAAI6B,CAAAA,CAGpB,CACL,GAAGlC,EACH,YAAA,CAAc,MAAA,CAAO,IAAA,CAAKS,CAAe,EAAE,MAAA,CAAS,CAAA,CAAIA,CAAAA,CAAkB,MAC5E,CACF,CACA,OAAOT,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAO8B,EAAkB9B,CAAAA,CAAK,KAAA,CAAOK,CAAAA,CAAO0B,CAAO,GAAK/B,CAAAA,CAAK,KAAA,CAC7D,MAAA,CAAQ8B,CAAAA,CAAkB9B,EAAK,MAAA,CAAQK,CAAAA,CAAO0B,CAAO,CAAA,EAAK/B,EAAK,MACjE,CACF,CA4CO,SAASmC,EACdnC,CAAAA,CACAC,CAAAA,CACAmC,CAAAA,CACiB,CACjB,GAAIpC,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAC1B,GAAIA,CAAAA,CAAK,IAAA,GAAS,OAAQ,CACxB,GAAIA,EAAK,EAAA,GAAOC,CAAAA,CAAQ,CACtB,GAAImC,IAAW,KAAA,CAAO,CACpB,GAAM,CAAE,OAAQC,CAAAA,CAAG,GAAGC,CAAK,CAAA,CAAItC,EAC/B,OAAOsC,CACT,CACA,OAAO,CAAE,GAAGtC,CAAAA,CAAM,MAAA,CAAAoC,CAAO,CAC3B,CACA,OAAOpC,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOmC,EAAenC,CAAAA,CAAK,KAAA,CAAOC,CAAAA,CAAQmC,CAAM,GAAKpC,CAAAA,CAAK,KAAA,CAC1D,MAAA,CAAQmC,CAAAA,CAAenC,EAAK,MAAA,CAAQC,CAAAA,CAAQmC,CAAM,CAAA,EAAKpC,EAAK,MAC9D,CACF,CAKO,SAASuC,EAAUvC,CAAAA,CAAuBC,CAAAA,CAAgBI,CAAAA,CAAgC,CAC/F,OAAIL,CAAAA,GAAS,IAAA,CAAa,IAAA,CACtBA,CAAAA,CAAK,OAAS,MAAA,CACZA,CAAAA,CAAK,EAAA,GAAOC,CAAAA,CACVD,EAAK,WAAA,GAAgBK,CAAAA,CAAcL,CAAAA,CAChC,CAAE,GAAGA,CAAAA,CAAM,WAAA,CAAaK,CAAM,CAAA,CAEhCL,EAEF,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOuC,EAAUvC,CAAAA,CAAK,KAAA,CAAOC,CAAAA,CAAQI,CAAK,GAAKL,CAAAA,CAAK,KAAA,CACpD,MAAA,CAAQuC,CAAAA,CAAUvC,EAAK,MAAA,CAAQC,CAAAA,CAAQI,CAAK,CAAA,EAAKL,EAAK,MACxD,CACF,CAKO,SAASwC,EACdxC,CAAAA,CACAyC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAI1C,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAG1B,IAAM2C,CAAAA,CADajB,CAAAA,CAAsB1B,CAAAA,CAAMyC,CAAY,GACxB,YAAA,GAAeA,CAAY,CAAA,CAExDG,CAAAA,CAAYxC,EAAUJ,CAAAA,CAAMyC,CAAY,CAAA,CAC9C,GAAIG,IAAc,IAAA,CAChB,OAAO,CACL,IAAA,CAAM,OACN,EAAA,CAAI9C,CAAAA,EAAiB,CACrB,IAAA,CAAM,CAAC2C,CAAY,CAAA,CACnB,WAAA,CAAaA,CAAAA,CACb,aAAcE,CAAAA,CAAiB,CAAE,CAACF,CAAY,EAAGE,CAAe,CAAA,CAAI,MACtE,CAAA,CAGF,SAASxB,CAAAA,CAAOC,CAAAA,CAA0B,CACxC,GAAIA,EAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,EAAK,EAAA,GAAOsB,CAAAA,CAAc,CAC5B,IAAMpC,EAAU,CAAC,GAAGc,CAAAA,CAAK,IAAI,EACxBd,CAAAA,CAAQ,QAAA,CAASmC,CAAY,CAAA,EAChCnC,EAAQ,IAAA,CAAKmC,CAAY,CAAA,CAE3B,IAAMhC,EAAkB,CAAE,GAAGW,CAAAA,CAAK,YAAa,EAC/C,OAAIuB,CAAAA,GACFlC,CAAAA,CAAgBgC,CAAY,EAAIE,CAAAA,CAAAA,CAE3B,CACL,GAAGvB,CAAAA,CACH,KAAMd,CAAAA,CACN,WAAA,CAAamC,CAAAA,CACb,YAAA,CAAc,OAAO,IAAA,CAAKhC,CAAe,CAAA,CAAE,MAAA,CAAS,EAAIA,CAAAA,CAAkB,MAC5E,CACF,CACA,OAAOW,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOD,CAAAA,CAAOC,CAAAA,CAAK,KAAK,CAAA,CACxB,MAAA,CAAQD,CAAAA,CAAOC,CAAAA,CAAK,MAAM,CAC5B,CACF,CAEA,OAAOD,EAAOyB,CAAS,CACzB,CAKO,SAASC,EACd7C,CAAAA,CACAyC,CAAAA,CACAK,CAAAA,CACAC,CAAAA,CAA+B,SACd,CACjB,GAAI/C,CAAAA,GAAS,IAAA,CAAM,OAAO,IAAA,CAG1B,IAAM2C,CAAAA,CADajB,CAAAA,CAAsB1B,EAAMyC,CAAY,CAAA,EACxB,YAAA,GAAeA,CAAY,EAExDG,CAAAA,CAAYxC,CAAAA,CAAUJ,CAAAA,CAAMyC,CAAY,EAC9C,GAAIG,CAAAA,GAAc,IAAA,CAChB,OAAO,CACL,IAAA,CAAM,MAAA,CACN,EAAA,CAAI9C,CAAAA,GACJ,IAAA,CAAM,CAAC2C,CAAY,CAAA,CACnB,YAAaA,CAAAA,CACb,YAAA,CAAcE,CAAAA,CAAiB,CAAE,CAACF,CAAY,EAAGE,CAAe,CAAA,CAAI,MACtE,CAAA,CAGF,SAASxB,CAAAA,CAAOC,CAAAA,CAA0B,CACxC,GAAIA,CAAAA,CAAK,IAAA,GAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,IAAA,CAAK,QAAA,CAAS0B,CAAW,CAAA,CAAG,CAEnC,IAAME,CAAAA,CADU,CAAC,GAAG5B,CAAAA,CAAK,IAAI,CAAA,CACA,OAAQb,CAAAA,EAAMA,CAAAA,GAAMkC,CAAY,CAAA,CACzDQ,CAAAA,CAAcD,EAAa,OAAA,CAAQF,CAAW,CAAA,CAC9CG,CAAAA,CAAc,IAChBA,CAAAA,CAAc,CAAA,CAAA,CAEZF,CAAAA,GAAa,OAAA,GACfE,GAAe,CAAA,CAAA,CAEjBD,CAAAA,CAAa,MAAA,CAAOC,CAAAA,CAAa,EAAGR,CAAY,CAAA,CAEhD,IAAMhC,CAAAA,CAAkB,CAAE,GAAGW,CAAAA,CAAK,YAAa,CAAA,CAC/C,OAAIuB,CAAAA,GACFlC,CAAAA,CAAgBgC,CAAY,CAAA,CAAIE,GAE3B,CACL,GAAGvB,CAAAA,CACH,IAAA,CAAM4B,EACN,WAAA,CAAaP,CAAAA,CACb,YAAA,CAAc,MAAA,CAAO,KAAKhC,CAAe,CAAA,CAAE,MAAA,CAAS,CAAA,CAAIA,EAAkB,MAC5E,CACF,CACA,OAAOW,CACT,CACA,OAAO,CACL,GAAGA,EACH,KAAA,CAAOD,CAAAA,CAAOC,CAAAA,CAAK,KAAK,EACxB,MAAA,CAAQD,CAAAA,CAAOC,CAAAA,CAAK,MAAM,CAC5B,CACF,CAEA,OAAOD,CAAAA,CAAOyB,CAAS,CACzB,CAyBO,SAASM,CAAAA,CACd9B,EACA+B,CAAAA,CAAO,CAAA,CACPC,CAAAA,CAAM,CAAA,CACNC,EAAQ,GAAA,CACRC,CAAAA,CAAS,GAAA,CACTC,CAAAA,CAAO,OACmD,CAC1D,GAAInC,CAAAA,GAAS,IAAA,CAAM,OAAO,CAAE,KAAA,CAAO,EAAC,CAAG,UAAW,EAAG,CAAA,CACrD,GAAIA,EAAK,IAAA,GAAS,MAAA,CAChB,OAAO,CACL,MAAO,CAAC,CAAE,MAAA,CAAQA,CAAAA,CAAK,GAAI,IAAA,CAAA+B,CAAAA,CAAM,GAAA,CAAAC,CAAAA,CAAK,MAAAC,CAAAA,CAAO,MAAA,CAAAC,CAAAA,CAAQ,IAAA,CAAAlC,CAAK,CAAC,CAAA,CAC3D,SAAA,CAAW,EACb,CAAA,CAGF,GAAM,CAAE,SAAA,CAAAR,EAAW,eAAA,CAAA4C,CAAAA,CAAiB,KAAA,CAAAC,CAAAA,CAAO,OAAAC,CAAO,CAAA,CAAItC,CAAAA,CAGhDuC,CAAAA,CAAoC,CACxC,EAAA,CAHiB,CAAA,SAAA,EAAYJ,CAAI,CAAA,CAAA,EAAI3C,CAAS,CAAA,CAAA,CAI9C,WAAA,CAAaQ,CAAAA,CACb,SAAA,CAAAR,EACA,IAAA,CAAMA,CAAAA,GAAc,KAAA,CAAQuC,CAAAA,CAAOE,GAASG,CAAAA,CAAkB,GAAA,CAAA,CAAOL,EACrE,GAAA,CAAKvC,CAAAA,GAAc,SAAWwC,CAAAA,CAAME,CAAAA,EAAUE,CAAAA,CAAkB,GAAA,CAAA,CAAOJ,EACvE,KAAA,CAAOxC,CAAAA,GAAc,KAAA,CAAQ,CAAA,CAAIyC,EACjC,MAAA,CAAQzC,CAAAA,GAAc,QAAA,CAAW,CAAA,CAAI0C,EACrC,UAAA,CAAYH,CAAAA,CACZ,SAAA,CAAWC,CAAAA,CACX,YAAaC,CAAAA,CACb,YAAA,CAAcC,CAChB,CAAA,CAEIM,EAAc,CAAE,KAAA,CAAO,EAAC,CAAqB,UAAW,EAAyB,CAAA,CACjFC,CAAAA,CAAe,CAAE,KAAA,CAAO,EAAC,CAAqB,SAAA,CAAW,EAAyB,CAAA,CAEtF,GAAIjD,CAAAA,GAAc,MAAO,CACvB,IAAMkD,CAAAA,CAAaT,CAAAA,EAASG,EAAkB,GAAA,CAAA,CAC9CI,CAAAA,CAAcV,CAAAA,CAAcO,CAAAA,CAAON,EAAMC,CAAAA,CAAKU,CAAAA,CAAYR,CAAAA,CAAQ,CAAA,EAAGC,CAAI,CAAA,EAAA,CAAI,CAAA,CAC7EM,CAAAA,CAAeX,CAAAA,CACbQ,EACAP,CAAAA,CAAOW,CAAAA,CACPV,CAAAA,CACAC,CAAAA,CAAQS,EACRR,CAAAA,CACA,CAAA,EAAGC,CAAI,CAAA,EAAA,CACT,EACF,CAAA,KAAO,CACL,IAAMQ,CAAAA,CAAcT,GAAUE,CAAAA,CAAkB,GAAA,CAAA,CAChDI,CAAAA,CAAcV,CAAAA,CAAcO,EAAON,CAAAA,CAAMC,CAAAA,CAAKC,CAAAA,CAAOU,CAAAA,CAAa,GAAGR,CAAI,CAAA,EAAA,CAAI,CAAA,CAC7EM,CAAAA,CAAeX,EACbQ,CAAAA,CACAP,CAAAA,CACAC,CAAAA,CAAMW,CAAAA,CACNV,EACAC,CAAAA,CAASS,CAAAA,CACT,CAAA,EAAGR,CAAI,IACT,EACF,CAEA,OAAO,CACL,MAAO,CAAC,GAAGK,CAAAA,CAAY,KAAA,CAAO,GAAGC,CAAAA,CAAa,KAAK,CAAA,CACnD,SAAA,CAAW,CAACF,CAAAA,CAAiB,GAAGC,CAAAA,CAAY,SAAA,CAAW,GAAGC,CAAAA,CAAa,SAAS,CAClF,CACF,CAMO,SAASG,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACQ,CAGR,GAAI,EAFkBF,IAAe,KAAA,EACWC,CAAAA,EAAaF,CAAAA,CAAK,QAAA,CAASE,CAAS,CAAA,CAAA,EACrD,CAACC,CAAAA,CAC9B,OAAO,IAET,IAAMvC,CAAAA,CAAQoC,CAAAA,CAAK,OAAA,CAAQE,CAAS,CAAA,CACpC,OAAOC,IAAoB,QAAA,CAAWvC,CAAAA,CAAQA,EAAQ,CACxD","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 if (tree.activeTabId === tabId) return tree\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\n/**\n * Calculates the target drop insertion index in a list of tabs during a drag.\n * Returns -1 if the drop target is not in the list.\n */\nexport function calculateTabDropIndex(\n tabs: string[],\n activeType: string | null,\n overTabId: string | null,\n overTabPosition: 'before' | 'after' | null,\n): number {\n const isDraggingTab = activeType === 'tab'\n const isHoveredTabInThisPane = isDraggingTab && overTabId && tabs.includes(overTabId)\n if (!isHoveredTabInThisPane || !overTabPosition) {\n return -1\n }\n const index = tabs.indexOf(overTabId)\n return overTabPosition === 'before' ? index : index + 1\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/lib/tree/tree-helpers.ts","../src/shared/lib/dom.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","calculateTabDropIndex","tabs","activeType","overTabId","overTabPosition","getOrCreateHiddenContainer","id","container"],"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 if (tree.activeTabId === tabId) return tree\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\n/**\n * Calculates the target drop insertion index in a list of tabs during a drag.\n * Returns -1 if the drop target is not in the list.\n */\nexport function calculateTabDropIndex(\n tabs: string[],\n activeType: string | null,\n overTabId: string | null,\n overTabPosition: 'before' | 'after' | null,\n): number {\n const isDraggingTab = activeType === 'tab'\n const isHoveredTabInThisPane = isDraggingTab && overTabId && tabs.includes(overTabId)\n if (!isHoveredTabInThisPane || !overTabPosition) {\n return -1\n }\n const index = tabs.indexOf(overTabId)\n return overTabPosition === 'before' ? index : index + 1\n}\n","/**\n * Utility to copy stylesheets from source document to destination document.\n */\nexport function copyStyles(srcDoc: Document, destDoc: Document) {\n Array.from(srcDoc.styleSheets).forEach((sheet) => {\n try {\n if (sheet.cssRules) {\n const newStyle = destDoc.createElement('style')\n Array.from(sheet.cssRules).forEach((rule) => {\n newStyle.appendChild(destDoc.createTextNode(rule.cssText))\n })\n destDoc.head.appendChild(newStyle)\n } else if (sheet.href) {\n const newLink = destDoc.createElement('link')\n newLink.rel = 'stylesheet'\n newLink.href = sheet.href\n destDoc.head.appendChild(newLink)\n }\n } catch {\n if (sheet.href) {\n const newLink = destDoc.createElement('link')\n newLink.rel = 'stylesheet'\n newLink.href = sheet.href\n destDoc.head.appendChild(newLink)\n }\n }\n })\n}\n\n/**\n * Utility to get or create a hidden container element on the document body.\n */\nexport function getOrCreateHiddenContainer(id: string): HTMLElement {\n let container = document.getElementById(id)\n if (!container) {\n container = document.createElement('div')\n container.id = id\n container.style.display = 'none'\n document.body.appendChild(container)\n }\n return container\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-zeugma",
3
- "version": "6.0.4",
3
+ "version": "6.1.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,
@@ -34,7 +34,7 @@
34
34
  "bugs": {
35
35
  "url": "https://github.com/react-zeugma/react-zeugma/issues"
36
36
  },
37
- "homepage": "https://react-zeugma.vercel.app",
37
+ "homepage": "https://react-zeugma.com",
38
38
  "publishConfig": {
39
39
  "access": "public",
40
40
  "registry": "https://registry.npmjs.org/"