@sqlrooms/layout 0.0.1-alpha.0 → 0.0.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/CHANGELOG.md +4 -0
- package/package.json +5 -5
- package/dist/mosaic/PanelLayout.d.ts +0 -11
- package/dist/mosaic/PanelLayout.d.ts.map +0 -1
- package/dist/mosaic/PanelLayout.js +0 -26
- package/dist/mosaic/PanelTile.d.ts +0 -9
- package/dist/mosaic/PanelTile.d.ts.map +0 -1
- package/dist/mosaic/PanelTile.js +0 -8
- package/dist/mosaic/ResizableLayout.js +0 -20
- package/dist/mosaic/ResizableTile.js +0 -6
- package/dist/mosaic/StyledMosaic.d.ts +0 -3
- package/dist/mosaic/StyledMosaic.d.ts.map +0 -1
- package/dist/mosaic/StyledMosaic.js +0 -154
- package/dist/mosaic/panel-utils.d.ts +0 -20
- package/dist/mosaic/panel-utils.d.ts.map +0 -1
- package/dist/mosaic/panel-utils.js +0 -102
- package/dist/mosaic/resizable-utils.js +0 -53
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.0.1](https://github.com/ilyabo/sqlrooms/compare/v0.0.1-alpha.0...v0.0.1) (2025-01-30)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @sqlrooms/layout
|
|
9
|
+
|
|
6
10
|
## 0.0.1-alpha.0 (2025-01-30)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @sqlrooms/layout
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqlrooms/layout",
|
|
3
|
-
"version": "0.0.1
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
|
-
"types": "
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"private": false,
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@sqlrooms/project-config": "0.0.1
|
|
14
|
-
"@sqlrooms/ui": "0.0.1
|
|
13
|
+
"@sqlrooms/project-config": "0.0.1",
|
|
14
|
+
"@sqlrooms/ui": "0.0.1"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"react": "*",
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"build": "tsc",
|
|
23
23
|
"lint": "eslint ."
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "5d8893a604a91d109dc5b5f80b4a3e937b4cf520"
|
|
26
26
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
2
|
-
import { PanelNode } from '@sqlrooms/project-config';
|
|
3
|
-
type Props = {
|
|
4
|
-
root: PanelNode | null;
|
|
5
|
-
onChange?: (root: PanelNode | null) => void;
|
|
6
|
-
onRelease?: (root: PanelNode | null) => void;
|
|
7
|
-
renderTile: (id: string) => React.ReactNode;
|
|
8
|
-
};
|
|
9
|
-
declare const PanelLayout: FC<Props>;
|
|
10
|
-
export default PanelLayout;
|
|
11
|
-
//# sourceMappingURL=PanelLayout.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PanelLayout.d.ts","sourceRoot":"","sources":["../../src/mosaic/PanelLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAC,EAAE,EAAc,MAAM,OAAO,CAAC;AAM7C,OAAO,EAAiB,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAInE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CAC7C,CAAC;AAEF,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,KAAK,CAoD1B,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback } from 'react';
|
|
3
|
-
import { Panel, PanelGroup as ResizablePanel, PanelResizeHandle, } from 'react-resizable-panels';
|
|
4
|
-
import PanelTile from './PanelTile';
|
|
5
|
-
const PanelLayout = (props) => {
|
|
6
|
-
const { root, onChange, onRelease, renderTile } = props;
|
|
7
|
-
const [isDragging, setDragging] = React.useState(false);
|
|
8
|
-
const handleLayoutChange = useCallback((sizes, groupId) => {
|
|
9
|
-
if (!root)
|
|
10
|
-
return;
|
|
11
|
-
// TODO: Update sizes in the layout tree
|
|
12
|
-
onChange?.(root);
|
|
13
|
-
}, [onChange, root]);
|
|
14
|
-
const renderNode = useCallback((node) => {
|
|
15
|
-
if (node.type === 'leaf') {
|
|
16
|
-
return (_jsx(Panel, { defaultSize: node.size, children: _jsx(PanelTile, { id: node.id, isDragging: isDragging, content: renderTile(node.id) }) }, node.id));
|
|
17
|
-
}
|
|
18
|
-
return (_jsx(ResizablePanel, { direction: node.direction === 'horizontal' ? 'horizontal' : 'vertical', onResize: (sizes) => handleLayoutChange(sizes, node.id), children: node.children.map((child, i) => (_jsxs(React.Fragment, { children: [i > 0 && _jsx(PanelResizeHandle, {}), renderNode(child)] }, i))) }, node.children
|
|
19
|
-
.map((n) => (n.type === 'leaf' ? n.id : ''))
|
|
20
|
-
.join('-')));
|
|
21
|
-
}, [handleLayoutChange, isDragging, renderTile]);
|
|
22
|
-
if (!root)
|
|
23
|
-
return null;
|
|
24
|
-
return _jsx("div", { className: "relative w-full h-full", children: renderNode(root) });
|
|
25
|
-
};
|
|
26
|
-
export default PanelLayout;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PanelTile.d.ts","sourceRoot":"","sources":["../../src/mosaic/PanelTile.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,KAAK,KAAK,GAAG;IACX,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,SAAS,EAAE,EAAE,CAAC,KAAK,CAaxB,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/dist/mosaic/PanelTile.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from '@sqlrooms/ui';
|
|
3
|
-
const ENABLE_LAYOUT_REARRANGE = false;
|
|
4
|
-
const PanelTile = (props) => {
|
|
5
|
-
const { id, content, isDragging } = props;
|
|
6
|
-
return (_jsx("div", { className: cn('flex-1 h-full p-2 flex-col bg-gray-700 rounded-md overflow-hidden', isDragging ? 'pointer-events-none' : ''), children: content }));
|
|
7
|
-
};
|
|
8
|
-
export default PanelTile;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
|
-
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
|
|
4
|
-
const RenderPanelTree = ({ node, path, renderTile, onLayout, }) => {
|
|
5
|
-
if (typeof node === 'string') {
|
|
6
|
-
return (_jsx(PanelGroup, { direction: "horizontal", children: _jsx(Panel, { id: node, minSize: 10, defaultSize: 100, children: renderTile(node, path) }) }));
|
|
7
|
-
}
|
|
8
|
-
const { direction, first, second, splitPercentage = 50 } = node;
|
|
9
|
-
return (_jsxs(PanelGroup, { direction: direction === 'row' ? 'horizontal' : 'vertical', onLayout: onLayout, children: [_jsx(Panel, { minSize: 10, defaultSize: splitPercentage, children: _jsx(RenderPanelTree, { node: first, path: [...path, 'first'], renderTile: renderTile }) }), _jsx(PanelResizeHandle, { className: "bg-blue-800 w-2 h-2" }), _jsx(Panel, { minSize: 10, defaultSize: 100 - splitPercentage, children: _jsx(RenderPanelTree, { node: second, path: [...path, 'second'], renderTile: renderTile }) })] }));
|
|
10
|
-
};
|
|
11
|
-
const ResizableLayout = ({ value, onChange, renderTile, className, }) => {
|
|
12
|
-
const handleLayout = useCallback((sizes) => {
|
|
13
|
-
// TODO: Implement layout change handling that preserves tree structure
|
|
14
|
-
console.log('Layout changed:', sizes);
|
|
15
|
-
}, [onChange]);
|
|
16
|
-
if (!value)
|
|
17
|
-
return null;
|
|
18
|
-
return (_jsx("div", { className: className, style: { width: '100%', height: '100%' }, children: _jsx(RenderPanelTree, { node: value, path: [], renderTile: renderTile, onLayout: handleLayout }) }));
|
|
19
|
-
};
|
|
20
|
-
export default ResizableLayout;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Flex } from '@chakra-ui/react';
|
|
3
|
-
const ResizableTile = ({ id, content }) => {
|
|
4
|
-
return (_jsx(Flex, { grow: "1", height: "100%", p: 2, direction: "column", borderRadius: "sm", overflow: "hidden", bg: "gray.700", children: content }));
|
|
5
|
-
};
|
|
6
|
-
export default ResizableTile;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StyledMosaic.d.ts","sourceRoot":"","sources":["../../src/mosaic/StyledMosaic.tsx"],"names":[],"mappings":"AAGA,QAAA,MAAM,YAAY,EAAE,GAA8B,CAAC;AAuLnD,eAAe,YAAY,CAAC"}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import styled from '@emotion/styled';
|
|
2
|
-
import { Mosaic } from 'react-mosaic-component';
|
|
3
|
-
const StyledMosaic = styled((Mosaic)) ``;
|
|
4
|
-
// const StyledMosaic = styled(Mosaic<string>)`
|
|
5
|
-
// background: ${(props) => props.theme.colors.gray[800]};
|
|
6
|
-
// .mosaic-zero-state {
|
|
7
|
-
// background: ${(props) => props.theme.colors.gray[300]};
|
|
8
|
-
// box-shadow: 0 0 5px ${(props) => props.theme.colors.gray[800]};
|
|
9
|
-
// .default-zero-state-icon {
|
|
10
|
-
// font-size: 120px;
|
|
11
|
-
// }
|
|
12
|
-
// }
|
|
13
|
-
// .mosaic-split:hover {
|
|
14
|
-
// background: none;
|
|
15
|
-
// .mosaic-split-line {
|
|
16
|
-
// box-shadow: 0 0 0 1px ${(props) => props.theme.colors.blue};
|
|
17
|
-
// }
|
|
18
|
-
// }
|
|
19
|
-
// &.mosaic-drop-target,
|
|
20
|
-
// .mosaic-drop-target {
|
|
21
|
-
// .drop-target-container .drop-target {
|
|
22
|
-
// background: fade(@blue5, 20%);
|
|
23
|
-
// border: 2px solid ${(props) => props.theme.colors.blue};
|
|
24
|
-
// transition: opacity 100ms;
|
|
25
|
-
// }
|
|
26
|
-
// }
|
|
27
|
-
// .mosaic-window,
|
|
28
|
-
// .mosaic-preview {
|
|
29
|
-
// box-shadow: 0 0 5px ${(props) => props.theme.colors.gray[800]};
|
|
30
|
-
// .mosaic-window-toolbar {
|
|
31
|
-
// background: ${(props) => props.theme.colors.gray[700]};
|
|
32
|
-
// &.draggable:hover {
|
|
33
|
-
// .mosaic-window-title {
|
|
34
|
-
// color: #000;
|
|
35
|
-
// }
|
|
36
|
-
// background: ${(props) => props.theme.colors.gray[800]};
|
|
37
|
-
// }
|
|
38
|
-
// }
|
|
39
|
-
// .mosaic-window-title {
|
|
40
|
-
// font-weight: 600;
|
|
41
|
-
// color: @dark-gray5;
|
|
42
|
-
// }
|
|
43
|
-
// .mosaic-window-controls {
|
|
44
|
-
// .separator {
|
|
45
|
-
// border-left: 1px solid @light-gray2;
|
|
46
|
-
// }
|
|
47
|
-
// .@{ns}-button {
|
|
48
|
-
// &,
|
|
49
|
-
// &:before {
|
|
50
|
-
// color: @gray2;
|
|
51
|
-
// }
|
|
52
|
-
// }
|
|
53
|
-
// }
|
|
54
|
-
// .default-preview-icon {
|
|
55
|
-
// font-size: 72px;
|
|
56
|
-
// }
|
|
57
|
-
// .mosaic-window-body {
|
|
58
|
-
// border-top-width: 0;
|
|
59
|
-
// background: @pt-app-background-color;
|
|
60
|
-
// border-bottom-right-radius: @pt-border-radius;
|
|
61
|
-
// border-bottom-left-radius: @pt-border-radius;
|
|
62
|
-
// }
|
|
63
|
-
// .mosaic-window-additional-actions-bar {
|
|
64
|
-
// transition: height 250ms;
|
|
65
|
-
// box-shadow: 0 1px 1px @pt-divider-black;
|
|
66
|
-
// .@{ns}-button {
|
|
67
|
-
// &,
|
|
68
|
-
// &:before {
|
|
69
|
-
// color: @gray2;
|
|
70
|
-
// }
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
// &.additional-controls-open {
|
|
74
|
-
// .mosaic-window-toolbar {
|
|
75
|
-
// box-shadow: 0 1px 0 @pt-elevation-shadow-0;
|
|
76
|
-
// }
|
|
77
|
-
// }
|
|
78
|
-
// .mosaic-preview {
|
|
79
|
-
// border: 1px solid @gray3;
|
|
80
|
-
// h4 {
|
|
81
|
-
// color: @dark-gray5;
|
|
82
|
-
// }
|
|
83
|
-
// }
|
|
84
|
-
// }
|
|
85
|
-
// &.@{ns}-dark {
|
|
86
|
-
// background: @dark-gray2;
|
|
87
|
-
// .mosaic-zero-state {
|
|
88
|
-
// background: @dark-gray4;
|
|
89
|
-
// box-shadow: @pt-dark-elevation-shadow-0;
|
|
90
|
-
// }
|
|
91
|
-
// .mosaic-split:hover .mosaic-split-line {
|
|
92
|
-
// box-shadow: 0 0 0 1px @blue3;
|
|
93
|
-
// }
|
|
94
|
-
// &.mosaic-drop-target,
|
|
95
|
-
// .mosaic-drop-target {
|
|
96
|
-
// .drop-target-container .drop-target {
|
|
97
|
-
// background: fade(@blue2, 20%);
|
|
98
|
-
// border-color: @blue3;
|
|
99
|
-
// }
|
|
100
|
-
// }
|
|
101
|
-
// .mosaic-window-toolbar,
|
|
102
|
-
// .mosaic-window-additional-actions-bar {
|
|
103
|
-
// background: @dark-gray4;
|
|
104
|
-
// box-shadow: 0 1px 1px @pt-dark-divider-black;
|
|
105
|
-
// }
|
|
106
|
-
// .mosaic-window,
|
|
107
|
-
// .mosaic-preview {
|
|
108
|
-
// box-shadow: @pt-dark-elevation-shadow-0;
|
|
109
|
-
// .mosaic-window-toolbar.draggable:hover {
|
|
110
|
-
// .mosaic-window-title {
|
|
111
|
-
// color: #fff;
|
|
112
|
-
// }
|
|
113
|
-
// background: linear-gradient(to bottom, @dark-gray5, @dark-gray4);
|
|
114
|
-
// }
|
|
115
|
-
// .mosaic-window-title {
|
|
116
|
-
// color: @light-gray2;
|
|
117
|
-
// }
|
|
118
|
-
// .mosaic-window-controls {
|
|
119
|
-
// .separator {
|
|
120
|
-
// border-color: @gray1;
|
|
121
|
-
// }
|
|
122
|
-
// .@{ns}-button {
|
|
123
|
-
// &,
|
|
124
|
-
// &:before {
|
|
125
|
-
// color: @gray4;
|
|
126
|
-
// }
|
|
127
|
-
// }
|
|
128
|
-
// }
|
|
129
|
-
// .mosaic-window-body {
|
|
130
|
-
// background: ${(props) => props.theme.colors.gray[800]};
|
|
131
|
-
// }
|
|
132
|
-
// .mosaic-window-additional-actions-bar {
|
|
133
|
-
// .@{ns}-button {
|
|
134
|
-
// &,
|
|
135
|
-
// &:before {
|
|
136
|
-
// color: @gray5;
|
|
137
|
-
// }
|
|
138
|
-
// }
|
|
139
|
-
// }
|
|
140
|
-
// &.additional-controls-open {
|
|
141
|
-
// .mosaic-window-toolbar {
|
|
142
|
-
// box-shadow: @pt-dark-elevation-shadow-0;
|
|
143
|
-
// }
|
|
144
|
-
// }
|
|
145
|
-
// .mosaic-preview {
|
|
146
|
-
// border-color: @gray1;
|
|
147
|
-
// h4 {
|
|
148
|
-
// color: @light-gray4;
|
|
149
|
-
// }
|
|
150
|
-
// }
|
|
151
|
-
// }
|
|
152
|
-
// }
|
|
153
|
-
// `;
|
|
154
|
-
export default StyledMosaic;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { PanelDirection, PanelGroup, PanelNode } from '@sqlrooms/project-config';
|
|
2
|
-
export declare function isPanelGroup(node: PanelNode | null | undefined): node is PanelGroup;
|
|
3
|
-
export declare function findPanelNodeById(root: PanelNode | null | undefined, id: string): {
|
|
4
|
-
node: PanelNode;
|
|
5
|
-
parent: PanelGroup | null;
|
|
6
|
-
index: number;
|
|
7
|
-
} | undefined;
|
|
8
|
-
export declare function removePanelNode(root: PanelNode | null | undefined, id: string): {
|
|
9
|
-
success: true;
|
|
10
|
-
nextRoot: PanelNode;
|
|
11
|
-
} | {
|
|
12
|
-
success: false;
|
|
13
|
-
};
|
|
14
|
-
export declare function addPanelNode(root: PanelNode | null | undefined, newNode: PanelNode, placement: {
|
|
15
|
-
direction: PanelDirection;
|
|
16
|
-
relativeTo: string;
|
|
17
|
-
position: 'before' | 'after';
|
|
18
|
-
}): PanelNode;
|
|
19
|
-
export declare function getVisiblePanels(root: PanelNode | null | undefined): string[];
|
|
20
|
-
//# sourceMappingURL=panel-utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"panel-utils.d.ts","sourceRoot":"","sources":["../../src/mosaic/panel-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,UAAU,EAEV,SAAS,EACV,MAAM,0BAA0B,CAAC;AAElC,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GACjC,IAAI,IAAI,UAAU,CAEpB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EAClC,EAAE,EAAE,MAAM,GACT;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,SAAS,CAkBzE;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EAClC,EAAE,EAAE,MAAM,GACT;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAC,GAAG;IAAC,OAAO,EAAE,KAAK,CAAA;CAAC,CA4BzD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,EAAE,SAAS,EAClB,SAAS,EAAE;IACT,SAAS,EAAE,cAAc,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC9B,GACA,SAAS,CAqDX;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAY7E"}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
export function isPanelGroup(node) {
|
|
2
|
-
return node?.type === 'group';
|
|
3
|
-
}
|
|
4
|
-
export function findPanelNodeById(root, id) {
|
|
5
|
-
if (!root)
|
|
6
|
-
return undefined;
|
|
7
|
-
if (root.type === 'leaf' && root.id === id) {
|
|
8
|
-
return { node: root, parent: null, index: -1 };
|
|
9
|
-
}
|
|
10
|
-
if (root.type === 'group') {
|
|
11
|
-
for (let i = 0; i < root.children.length; i++) {
|
|
12
|
-
const child = root.children[i];
|
|
13
|
-
if (child.type === 'leaf' && child.id === id) {
|
|
14
|
-
return { node: child, parent: root, index: i };
|
|
15
|
-
}
|
|
16
|
-
const found = findPanelNodeById(child, id);
|
|
17
|
-
if (found)
|
|
18
|
-
return found;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
export function removePanelNode(root, id) {
|
|
24
|
-
const found = findPanelNodeById(root, id);
|
|
25
|
-
if (!root || !found)
|
|
26
|
-
return { success: false };
|
|
27
|
-
const { parent } = found;
|
|
28
|
-
if (!parent)
|
|
29
|
-
return { success: false };
|
|
30
|
-
const { children } = parent;
|
|
31
|
-
const newChildren = children.filter((child) => child.type === 'leaf' ? child.id !== id : true);
|
|
32
|
-
if (newChildren.length === 0) {
|
|
33
|
-
return { success: false };
|
|
34
|
-
}
|
|
35
|
-
if (newChildren.length === 1) {
|
|
36
|
-
return { success: true, nextRoot: newChildren[0] };
|
|
37
|
-
}
|
|
38
|
-
return {
|
|
39
|
-
success: true,
|
|
40
|
-
nextRoot: {
|
|
41
|
-
...parent,
|
|
42
|
-
children: newChildren,
|
|
43
|
-
sizes: parent.sizes?.slice(0, newChildren.length),
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export function addPanelNode(root, newNode, placement) {
|
|
48
|
-
if (!root)
|
|
49
|
-
return newNode;
|
|
50
|
-
const found = findPanelNodeById(root, placement.relativeTo);
|
|
51
|
-
if (!found)
|
|
52
|
-
return root;
|
|
53
|
-
const { node, parent } = found;
|
|
54
|
-
if (!parent) {
|
|
55
|
-
return {
|
|
56
|
-
type: 'group',
|
|
57
|
-
direction: placement.direction,
|
|
58
|
-
children: placement.position === 'before' ? [newNode, node] : [node, newNode],
|
|
59
|
-
sizes: [50, 50],
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
const index = parent.children.indexOf(node);
|
|
63
|
-
const newChildren = [...parent.children];
|
|
64
|
-
const newSizes = [
|
|
65
|
-
...(parent.sizes ||
|
|
66
|
-
parent.children.map(() => 100 / parent.children.length)),
|
|
67
|
-
];
|
|
68
|
-
if (parent.direction === placement.direction) {
|
|
69
|
-
newChildren.splice(placement.position === 'before' ? index : index + 1, 0, newNode);
|
|
70
|
-
const size = newSizes[index] / 2;
|
|
71
|
-
newSizes.splice(placement.position === 'before' ? index : index + 1, 0, size);
|
|
72
|
-
newSizes[placement.position === 'before' ? index + 1 : index] = size;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
const wrapper = {
|
|
76
|
-
type: 'group',
|
|
77
|
-
direction: placement.direction,
|
|
78
|
-
children: placement.position === 'before' ? [newNode, node] : [node, newNode],
|
|
79
|
-
sizes: [50, 50],
|
|
80
|
-
};
|
|
81
|
-
newChildren[index] = wrapper;
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
...parent,
|
|
85
|
-
children: newChildren,
|
|
86
|
-
sizes: newSizes,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
export function getVisiblePanels(root) {
|
|
90
|
-
const visiblePanels = [];
|
|
91
|
-
if (!root)
|
|
92
|
-
return visiblePanels;
|
|
93
|
-
if (root.type === 'leaf') {
|
|
94
|
-
visiblePanels.push(root.id);
|
|
95
|
-
}
|
|
96
|
-
else if (root.type === 'group') {
|
|
97
|
-
root.children.forEach((child) => {
|
|
98
|
-
visiblePanels.push(...getVisiblePanels(child));
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
return visiblePanels;
|
|
102
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// Internal helper functions
|
|
2
|
-
export function mosaicToResizablePanels(node) {
|
|
3
|
-
if (!node)
|
|
4
|
-
return [];
|
|
5
|
-
if (typeof node === 'string')
|
|
6
|
-
return [{ id: node }];
|
|
7
|
-
const { direction, first, second, splitPercentage = 50 } = node;
|
|
8
|
-
const firstPanels = mosaicToResizablePanels(first);
|
|
9
|
-
const secondPanels = mosaicToResizablePanels(second);
|
|
10
|
-
if (firstPanels.length === 0)
|
|
11
|
-
return secondPanels;
|
|
12
|
-
if (secondPanels.length === 0)
|
|
13
|
-
return firstPanels;
|
|
14
|
-
// Set the split percentage for the first panel
|
|
15
|
-
firstPanels[firstPanels.length - 1].defaultSize = splitPercentage;
|
|
16
|
-
// Set the split percentage for the second panel
|
|
17
|
-
secondPanels[0].defaultSize = 100 - splitPercentage;
|
|
18
|
-
return [...firstPanels, ...secondPanels];
|
|
19
|
-
}
|
|
20
|
-
export function resizablePanelsToMosaic(panels, originalNode) {
|
|
21
|
-
if (panels.length === 0)
|
|
22
|
-
return null;
|
|
23
|
-
if (panels.length === 1)
|
|
24
|
-
return panels[0].id;
|
|
25
|
-
// Preserve the original direction from the mosaic node
|
|
26
|
-
const direction = (typeof originalNode === 'object' ? originalNode?.direction : 'row') ??
|
|
27
|
-
'row';
|
|
28
|
-
// Build the mosaic tree from right to left
|
|
29
|
-
return panels.slice(1).reduce((acc, panel, index) => {
|
|
30
|
-
return {
|
|
31
|
-
direction,
|
|
32
|
-
first: typeof acc === 'string' ? acc : acc,
|
|
33
|
-
second: panel.id,
|
|
34
|
-
splitPercentage: panels[index].size,
|
|
35
|
-
};
|
|
36
|
-
}, panels[0].id);
|
|
37
|
-
}
|
|
38
|
-
// We'll need to implement these if we want to handle layout changes
|
|
39
|
-
export function updateSplitPercentage(node, path, splitPercentage) {
|
|
40
|
-
if (typeof node === 'string' || path.length === 0)
|
|
41
|
-
return node;
|
|
42
|
-
const [current, ...rest] = path;
|
|
43
|
-
if (rest.length === 0) {
|
|
44
|
-
return {
|
|
45
|
-
...node,
|
|
46
|
-
splitPercentage,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
...node,
|
|
51
|
-
[current]: updateSplitPercentage(current === 'first' ? node.first : node.second, rest, splitPercentage),
|
|
52
|
-
};
|
|
53
|
-
}
|