react-zeugma 6.1.3 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -81
- package/dist/index.cjs +2 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -5
- package/dist/index.d.ts +3 -5
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/{dom-CGKdSlH9.d.cts → types-BPZMRZht.d.cts} +3 -22
- package/dist/{dom-CGKdSlH9.d.ts → types-BPZMRZht.d.ts} +3 -22
- package/dist/utils.cjs +1 -1
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +1 -2
- package/dist/utils.d.ts +1 -2
- package/dist/utils.js +1 -1
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -81,8 +81,6 @@ interface ZeugmaController {
|
|
|
81
81
|
locked: boolean;
|
|
82
82
|
/** Programmatically updates the global locked status. */
|
|
83
83
|
setLocked: Dispatch<SetStateAction<boolean>>;
|
|
84
|
-
/** Map of tab IDs to their popped-out state. */
|
|
85
|
-
popoutTabs: Record<string, boolean>;
|
|
86
84
|
/** The ID of the active dragged item (pane or tab). */
|
|
87
85
|
activeId: string | null;
|
|
88
86
|
/** The type of the active dragged item ('pane' | 'tab'). */
|
|
@@ -135,8 +133,6 @@ interface ZeugmaController {
|
|
|
135
133
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
136
134
|
/** Moves/reorders a tab relative to another target tab. */
|
|
137
135
|
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
|
|
138
|
-
/** Sets the popped-out state of a tab. */
|
|
139
|
-
setTabPopout: (tabId: string, popped: boolean) => void;
|
|
140
136
|
/** Find a PaneNode by its ID in the layout tree. */
|
|
141
137
|
findPaneById: (paneId: string) => PaneNode | null;
|
|
142
138
|
/** Find the PaneNode containing the given tab ID in the layout tree. */
|
|
@@ -155,6 +151,8 @@ interface ZeugmaClassNames {
|
|
|
155
151
|
paneLocked?: string;
|
|
156
152
|
/** CSS class applied to drop zone indicators when hovering over layout edges to split a pane. */
|
|
157
153
|
dropPreview?: string;
|
|
154
|
+
/** CSS class applied to root split drop zone preview. */
|
|
155
|
+
rootDropPreview?: string;
|
|
158
156
|
/** CSS class applied to the custom cursor-following drag preview portal wrapper. */
|
|
159
157
|
dragOverlay?: string;
|
|
160
158
|
/** CSS class applied to the drag-to-resize split bar handles. */
|
|
@@ -201,8 +199,6 @@ interface ZeugmaStateValue {
|
|
|
201
199
|
locked: boolean;
|
|
202
200
|
/** Programmatically updates the global locked status. */
|
|
203
201
|
setLocked: Dispatch<SetStateAction<boolean>>;
|
|
204
|
-
/** Map of tab IDs to their popped-out state. */
|
|
205
|
-
popoutTabs: Record<string, boolean>;
|
|
206
202
|
/** Find a PaneNode by its ID in the layout tree. */
|
|
207
203
|
findPaneById: (paneId: string) => PaneNode | null;
|
|
208
204
|
/** Find the PaneNode containing the given tab ID in the layout tree. */
|
|
@@ -262,26 +258,11 @@ interface ZeugmaActionsValue {
|
|
|
262
258
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
263
259
|
/** Moves/reorders a tab relative to another target tab. */
|
|
264
260
|
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
|
|
265
|
-
/** Sets the popped-out state of a tab. */
|
|
266
|
-
setTabPopout: (tabId: string, popped: boolean) => void;
|
|
267
261
|
}
|
|
268
262
|
interface ZeugmaContextValue extends ZeugmaStateValue, ZeugmaActionsValue {
|
|
269
263
|
}
|
|
270
264
|
interface PortalRegistryValue {
|
|
271
265
|
registerPortalTarget: (tabId: string, el: HTMLDivElement | null) => void;
|
|
272
266
|
}
|
|
273
|
-
interface TabWindowValue {
|
|
274
|
-
window: Window | null;
|
|
275
|
-
document: Document | null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Utility to copy stylesheets from source document to destination document.
|
|
280
|
-
*/
|
|
281
|
-
declare function copyStyles(srcDoc: Document, destDoc: Document): void;
|
|
282
|
-
/**
|
|
283
|
-
* Utility to get or create a hidden container element on the document body.
|
|
284
|
-
*/
|
|
285
|
-
declare function getOrCreateHiddenContainer(id: string): HTMLElement;
|
|
286
267
|
|
|
287
|
-
export {
|
|
268
|
+
export type { PortalRegistryValue as P, SplitDirection as S, TreeNode as T, UseZeugmaOptions as U, ZeugmaActionsValue as Z, ZeugmaDragStateValue as a, ZeugmaStateValue as b, ZeugmaController as c, ZeugmaContextValue as d, ZeugmaProps as e, SplitNode as f, PaneNode as g, TabDetails as h, ZeugmaClassNames as i };
|
|
@@ -81,8 +81,6 @@ interface ZeugmaController {
|
|
|
81
81
|
locked: boolean;
|
|
82
82
|
/** Programmatically updates the global locked status. */
|
|
83
83
|
setLocked: Dispatch<SetStateAction<boolean>>;
|
|
84
|
-
/** Map of tab IDs to their popped-out state. */
|
|
85
|
-
popoutTabs: Record<string, boolean>;
|
|
86
84
|
/** The ID of the active dragged item (pane or tab). */
|
|
87
85
|
activeId: string | null;
|
|
88
86
|
/** The type of the active dragged item ('pane' | 'tab'). */
|
|
@@ -135,8 +133,6 @@ interface ZeugmaController {
|
|
|
135
133
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
136
134
|
/** Moves/reorders a tab relative to another target tab. */
|
|
137
135
|
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
|
|
138
|
-
/** Sets the popped-out state of a tab. */
|
|
139
|
-
setTabPopout: (tabId: string, popped: boolean) => void;
|
|
140
136
|
/** Find a PaneNode by its ID in the layout tree. */
|
|
141
137
|
findPaneById: (paneId: string) => PaneNode | null;
|
|
142
138
|
/** Find the PaneNode containing the given tab ID in the layout tree. */
|
|
@@ -155,6 +151,8 @@ interface ZeugmaClassNames {
|
|
|
155
151
|
paneLocked?: string;
|
|
156
152
|
/** CSS class applied to drop zone indicators when hovering over layout edges to split a pane. */
|
|
157
153
|
dropPreview?: string;
|
|
154
|
+
/** CSS class applied to root split drop zone preview. */
|
|
155
|
+
rootDropPreview?: string;
|
|
158
156
|
/** CSS class applied to the custom cursor-following drag preview portal wrapper. */
|
|
159
157
|
dragOverlay?: string;
|
|
160
158
|
/** CSS class applied to the drag-to-resize split bar handles. */
|
|
@@ -201,8 +199,6 @@ interface ZeugmaStateValue {
|
|
|
201
199
|
locked: boolean;
|
|
202
200
|
/** Programmatically updates the global locked status. */
|
|
203
201
|
setLocked: Dispatch<SetStateAction<boolean>>;
|
|
204
|
-
/** Map of tab IDs to their popped-out state. */
|
|
205
|
-
popoutTabs: Record<string, boolean>;
|
|
206
202
|
/** Find a PaneNode by its ID in the layout tree. */
|
|
207
203
|
findPaneById: (paneId: string) => PaneNode | null;
|
|
208
204
|
/** Find the PaneNode containing the given tab ID in the layout tree. */
|
|
@@ -262,26 +258,11 @@ interface ZeugmaActionsValue {
|
|
|
262
258
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
263
259
|
/** Moves/reorders a tab relative to another target tab. */
|
|
264
260
|
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void;
|
|
265
|
-
/** Sets the popped-out state of a tab. */
|
|
266
|
-
setTabPopout: (tabId: string, popped: boolean) => void;
|
|
267
261
|
}
|
|
268
262
|
interface ZeugmaContextValue extends ZeugmaStateValue, ZeugmaActionsValue {
|
|
269
263
|
}
|
|
270
264
|
interface PortalRegistryValue {
|
|
271
265
|
registerPortalTarget: (tabId: string, el: HTMLDivElement | null) => void;
|
|
272
266
|
}
|
|
273
|
-
interface TabWindowValue {
|
|
274
|
-
window: Window | null;
|
|
275
|
-
document: Document | null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Utility to copy stylesheets from source document to destination document.
|
|
280
|
-
*/
|
|
281
|
-
declare function copyStyles(srcDoc: Document, destDoc: Document): void;
|
|
282
|
-
/**
|
|
283
|
-
* Utility to get or create a hidden container element on the document body.
|
|
284
|
-
*/
|
|
285
|
-
declare function getOrCreateHiddenContainer(id: string): HTMLElement;
|
|
286
267
|
|
|
287
|
-
export {
|
|
268
|
+
export type { PortalRegistryValue as P, SplitDirection as S, TreeNode as T, UseZeugmaOptions as U, ZeugmaActionsValue as Z, ZeugmaDragStateValue as a, ZeugmaStateValue as b, ZeugmaController as c, ZeugmaContextValue as d, ZeugmaProps as e, SplitNode as f, PaneNode as g, TabDetails as h, ZeugmaClassNames as i };
|
package/dist/utils.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';function p(){return "pane-"+Math.random().toString(36).substring(2,11)}function
|
|
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
|
|
2
2
|
//# sourceMappingURL=utils.cjs.map
|
package/dist/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 // 1. Copy all attributes of <html> (e.g. class=\"dark\", dataset, color-scheme, etc.)\n const srcHtml = srcDoc.documentElement\n const destHtml = destDoc.documentElement\n Array.from(destHtml.attributes).forEach((attr) => {\n destHtml.removeAttribute(attr.name)\n })\n Array.from(srcHtml.attributes).forEach((attr) => {\n destHtml.setAttribute(attr.name, attr.value)\n })\n\n // 2. Copy all attributes of <body> (e.g. background styles, class lists, etc.)\n const srcBody = srcDoc.body\n const destBody = destDoc.body\n Array.from(destBody.attributes).forEach((attr) => {\n destBody.removeAttribute(attr.name)\n })\n Array.from(srcBody.attributes).forEach((attr) => {\n destBody.setAttribute(attr.name, attr.value)\n })\n\n // 3. Copy all style/link elements from head\n Array.from(srcDoc.querySelectorAll('link[rel=\"stylesheet\"], style')).forEach((el) => {\n try {\n const cloned = el.cloneNode(true) as HTMLElement\n\n // If it's a style element, check if rules were inserted dynamically via CSSOM\n if (el.tagName.toLowerCase() === 'style') {\n const styleEl = el as HTMLStyleElement\n if (styleEl.sheet && styleEl.sheet.cssRules && styleEl.sheet.cssRules.length > 0) {\n cloned.textContent = Array.from(styleEl.sheet.cssRules)\n .map((rule) => rule.cssText)\n .join('\\n')\n }\n }\n\n destDoc.head.appendChild(cloned)\n } catch {\n // Fallback: just clone the node as is\n try {\n destDoc.head.appendChild(el.cloneNode(true))\n } catch (err) {\n console.error('Failed to copy style element:', err)\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"]}
|
|
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"]}
|
package/dist/utils.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { l as getOrCreateHiddenContainer } from './dom-CGKdSlH9.cjs';
|
|
1
|
+
import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-BPZMRZht.cjs';
|
|
3
2
|
import 'react';
|
|
4
3
|
|
|
5
4
|
declare function generateUniqueId(): string;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { l as getOrCreateHiddenContainer } from './dom-CGKdSlH9.js';
|
|
1
|
+
import { g as PaneNode, f as SplitNode, S as SplitDirection, T as TreeNode, h as TabDetails } from './types-BPZMRZht.js';
|
|
3
2
|
import 'react';
|
|
4
3
|
|
|
5
4
|
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
|
|
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
|
|
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","../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 // 1. Copy all attributes of <html> (e.g. class=\"dark\", dataset, color-scheme, etc.)\n const srcHtml = srcDoc.documentElement\n const destHtml = destDoc.documentElement\n Array.from(destHtml.attributes).forEach((attr) => {\n destHtml.removeAttribute(attr.name)\n })\n Array.from(srcHtml.attributes).forEach((attr) => {\n destHtml.setAttribute(attr.name, attr.value)\n })\n\n // 2. Copy all attributes of <body> (e.g. background styles, class lists, etc.)\n const srcBody = srcDoc.body\n const destBody = destDoc.body\n Array.from(destBody.attributes).forEach((attr) => {\n destBody.removeAttribute(attr.name)\n })\n Array.from(srcBody.attributes).forEach((attr) => {\n destBody.setAttribute(attr.name, attr.value)\n })\n\n // 3. Copy all style/link elements from head\n Array.from(srcDoc.querySelectorAll('link[rel=\"stylesheet\"], style')).forEach((el) => {\n try {\n const cloned = el.cloneNode(true) as HTMLElement\n\n // If it's a style element, check if rules were inserted dynamically via CSSOM\n if (el.tagName.toLowerCase() === 'style') {\n const styleEl = el as HTMLStyleElement\n if (styleEl.sheet && styleEl.sheet.cssRules && styleEl.sheet.cssRules.length > 0) {\n cloned.textContent = Array.from(styleEl.sheet.cssRules)\n .map((rule) => rule.cssText)\n .join('\\n')\n }\n }\n\n destDoc.head.appendChild(cloned)\n } catch {\n // Fallback: just clone the node as is\n try {\n destDoc.head.appendChild(el.cloneNode(true))\n } catch (err) {\n console.error('Failed to copy style element:', err)\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"]}
|
|
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.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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-zeugma",
|
|
3
|
-
"version": "6.1
|
|
3
|
+
"version": "6.2.1",
|
|
4
4
|
"description": "Recursive drag-and-drop dashboard layout engine for React — combining the tree-based splitting of react-mosaic with the declarative API of react-grid-layout.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|