@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 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-alpha.0",
3
+ "version": "0.0.1",
4
4
  "main": "dist/index.js",
5
- "types": "src/index.ts",
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-alpha.0",
14
- "@sqlrooms/ui": "0.0.1-alpha.0"
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": "8e3c0b884db7755c8b892a590af49c0081336d8d"
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,9 +0,0 @@
1
- import { FC } from 'react';
2
- type Props = {
3
- id: string;
4
- content: React.ReactNode;
5
- isDragging: boolean;
6
- };
7
- declare const PanelTile: FC<Props>;
8
- export default PanelTile;
9
- //# sourceMappingURL=PanelTile.d.ts.map
@@ -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"}
@@ -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,3 +0,0 @@
1
- declare const StyledMosaic: any;
2
- export default StyledMosaic;
3
- //# sourceMappingURL=StyledMosaic.d.ts.map
@@ -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
- }