react-simple-dock 0.1.3 → 0.1.4
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/index.css +3 -0
- package/index.d.ts +22 -6
- package/index.js +60 -23
- package/package.json +1 -1
package/index.css
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* Light Theme, feel free to override */
|
|
2
2
|
:root {
|
|
3
3
|
--sd-grid-gap: 3px;
|
|
4
|
+
--sd-panel-border: solid;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
:root[data-theme="light"] {
|
|
@@ -110,6 +111,8 @@ body[data-jp-theme-light] {
|
|
|
110
111
|
.leaf > .panel-content {
|
|
111
112
|
position: relative;
|
|
112
113
|
flex: 1;
|
|
114
|
+
border: var(--sd-panel-border, solid) var(--sd-tab-border-color, #bdbdbd);
|
|
115
|
+
border-width: 0 1px 1px 1px;
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
.leaf > .panel-content > div {
|
package/index.d.ts
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import "./index.css";
|
|
3
3
|
import { LayoutConfig, PanelProps } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* A Panel component.
|
|
6
|
+
*
|
|
7
|
+
* This component represents a Panel within the layout.
|
|
8
|
+
*
|
|
9
|
+
* @param props.name The unique identifier of the panel.
|
|
10
|
+
* @param props.header The content to render in the panel header.
|
|
11
|
+
* @param props.children The content to render within the panel.
|
|
12
|
+
*/
|
|
4
13
|
export declare const Panel: (props: PanelProps) => any;
|
|
5
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Main layout component that organizes panels and handles drag and drop.
|
|
16
|
+
*
|
|
17
|
+
* The Layout component takes child panel components, constructs an initial layout configuration,
|
|
18
|
+
* and renders the panel structure using NestedPanel. It also wraps the layout in a DndProvider
|
|
19
|
+
* if drag and drop support is enabled.
|
|
20
|
+
*
|
|
21
|
+
* @param children The children `Panel` components to render within the layout.
|
|
22
|
+
* @param defaultConfig The default layout configuration to use.
|
|
23
|
+
* @param wrapDnd A boolean flag to enable or disable drag and drop support (default: true).
|
|
24
|
+
* @returns A React element representing the complete panel layout.
|
|
25
|
+
*/
|
|
26
|
+
export declare function Layout({ children, defaultConfig, wrapDnd, }: {
|
|
6
27
|
children: React.ReactElement<PanelProps>[] | React.ReactElement<PanelProps>;
|
|
7
28
|
defaultConfig?: LayoutConfig;
|
|
8
29
|
wrapDnd?: boolean;
|
|
9
30
|
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
export declare namespace Layout {
|
|
11
|
-
var defaultProps: {
|
|
12
|
-
wrapDnd: boolean;
|
|
13
|
-
};
|
|
14
|
-
}
|
package/index.js
CHANGED
|
@@ -4,14 +4,24 @@ import "./index.css";
|
|
|
4
4
|
import { DndProvider, useDrag, useDragDropManager, useDrop } from "react-dnd";
|
|
5
5
|
import { filterPanels, movePanel } from "./utils";
|
|
6
6
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
|
7
|
-
export const Panel = (props) => {
|
|
8
|
-
return null;
|
|
9
|
-
};
|
|
10
7
|
function useForceUpdate() {
|
|
11
8
|
const [value, setValue] = useState(0); // integer state
|
|
12
9
|
return () => setValue((value) => value + 1); // update state to force render
|
|
13
10
|
}
|
|
14
|
-
const
|
|
11
|
+
const getPanelElementMaxHeaderHeight = (config, panelElements) => {
|
|
12
|
+
// If we have a leaf, then the header height is the max of each tabs header height
|
|
13
|
+
if (config.kind === "leaf") {
|
|
14
|
+
return Math.max(...config.tabs.map((tab) => panelElements.get(config).children[0].offsetHeight));
|
|
15
|
+
}
|
|
16
|
+
// If we have a row, then the header height is the max of each child's max header height
|
|
17
|
+
else if (config.kind === "row") {
|
|
18
|
+
return Math.max(...config.children.map((c) => getPanelElementMaxHeaderHeight(c, panelElements)));
|
|
19
|
+
}
|
|
20
|
+
// If we have a column, then the header height is the sum of each child's max header height
|
|
21
|
+
else {
|
|
22
|
+
return config.children.reduce((a, b) => a + getPanelElementMaxHeaderHeight(b, panelElements), 0);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
15
25
|
const TabHandle = ({ name, index, visible, onClick, children, }) => {
|
|
16
26
|
const getItem = () => ({
|
|
17
27
|
name,
|
|
@@ -119,15 +129,16 @@ const NestedPanel = React.memo(({ leaves, config, index, onResize, saveSizes, is
|
|
|
119
129
|
let size = savedSizes.current[idx] * ratio;
|
|
120
130
|
let nextSize = savedSizes.current[idx + 1] + (savedSizes.current[idx] - size);
|
|
121
131
|
const total = savedSizes.current.reduce((a, b) => a + b, 0);
|
|
122
|
-
const headerHeight = getPanelElementHeader(target.parentElement).offsetHeight;
|
|
123
132
|
if (config.kind === "column") {
|
|
133
|
+
const headerHeightBefore = getPanelElementMaxHeaderHeight(config.children[idx], panelElements);
|
|
134
|
+
const headerHeightAfter = getPanelElementMaxHeaderHeight(config.children[idx + 1], panelElements);
|
|
124
135
|
const parentHeight = panelContentRef.current.offsetHeight;
|
|
125
|
-
if ((size * parentHeight) / total <
|
|
126
|
-
size = (
|
|
136
|
+
if ((size * parentHeight) / total < headerHeightBefore) {
|
|
137
|
+
size = (headerHeightBefore / parentHeight) * total;
|
|
127
138
|
nextSize = savedSizes.current[idx + 1] + (savedSizes.current[idx] - size);
|
|
128
139
|
}
|
|
129
|
-
else if ((nextSize * parentHeight) / total <
|
|
130
|
-
nextSize = (
|
|
140
|
+
else if ((nextSize * parentHeight) / total < headerHeightAfter) {
|
|
141
|
+
nextSize = (headerHeightAfter / parentHeight) * total;
|
|
131
142
|
size = savedSizes.current[idx] + (savedSizes.current[idx + 1] - nextSize);
|
|
132
143
|
}
|
|
133
144
|
}
|
|
@@ -148,7 +159,7 @@ const NestedPanel = React.memo(({ leaves, config, index, onResize, saveSizes, is
|
|
|
148
159
|
};
|
|
149
160
|
const panelContentRef = useRef(null);
|
|
150
161
|
const panelRef = useRef(null);
|
|
151
|
-
return (_jsxs("div", { className: `${config.kind} panel`, style: style, ref: panelRef, children: [config.kind === "leaf" ? (_jsx(TabHeader, { config: config, leaves: leaves, onClick: handleHeaderClick })) : null, _jsx("div", { className: "panel-content", ref: panelContentRef, style: makeStyle(), children: config.kind === "leaf" ? (config.tabIndex < config.tabs.length ? (_jsx("div", { children: leaves[config.tabs[config.tabIndex]].element })) : (_jsx("div", { style: { width: "100%", height: "100%" } }))) : (config.children.map((c, i) => (_jsx(NestedPanel, { config: c, leaves: leaves, saveSizes: handleSaveSizes, index: i, onResize: handleResize, isLast: i === config.children.length - 1, direction: config.kind, panelElements: panelElements }, i)))) }), !isLast && direction === "column" && (_jsx("div", { className: "resize-border bottom", onMouseDown: (e) => handleMouseDown(e, "bottom") })), !isLast && direction === "row" && (_jsx("div", { className: "resize-border right", onMouseDown: (e) => handleMouseDown(e, "right") }))] }));
|
|
162
|
+
return (_jsxs("div", { className: `${config.kind} panel`, style: style, ref: panelRef, children: [config.kind === "leaf" ? (_jsx(TabHeader, { config: config, leaves: leaves, onClick: handleHeaderClick })) : null, _jsx("div", { className: "panel-content", ref: panelContentRef, style: makeStyle(), children: config.kind === "leaf" ? (config.tabIndex < config.tabs.length ? (_jsx("div", { children: leaves[config.tabs[config.tabIndex]].element }, config.tabs[config.tabIndex])) : (_jsx("div", { style: { width: "100%", height: "100%" } }))) : (config.children.map((c, i) => (_jsx(NestedPanel, { config: c, leaves: leaves, saveSizes: handleSaveSizes, index: i, onResize: handleResize, isLast: i === config.children.length - 1, direction: config.kind, panelElements: panelElements }, i)))) }), !isLast && direction === "column" && (_jsx("div", { className: "resize-border bottom", onMouseDown: (e) => handleMouseDown(e, "bottom") })), !isLast && direction === "row" && (_jsx("div", { className: "resize-border right", onMouseDown: (e) => handleMouseDown(e, "right") }))] }));
|
|
152
163
|
});
|
|
153
164
|
const Overlay = ({ panelElements, onDrop, rootConfig, }) => {
|
|
154
165
|
const closestRef = useRef(null);
|
|
@@ -208,14 +219,19 @@ const Overlay = ({ panelElements, onDrop, rootConfig, }) => {
|
|
|
208
219
|
zones.push({ rect, config, index, element });
|
|
209
220
|
};
|
|
210
221
|
if (config.kind === "leaf") {
|
|
211
|
-
if (!config.tabs.
|
|
222
|
+
if (!(config.tabs.length == 1 && config.tabs[0] == name)) {
|
|
212
223
|
pushZone("TOP", left, top, width, height / 2);
|
|
213
224
|
pushZone("BOTTOM", left, top + height / 2, width, height / 2);
|
|
214
225
|
pushZone("LEFT", left, top, width / 2, height);
|
|
215
226
|
pushZone("RIGHT", left + width / 2, top, width / 2, height);
|
|
216
227
|
}
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
// Only allow center zone if it's for the panel to stay at the same spot.
|
|
229
|
+
// Indeed, it was confusing since it appears like it's going to create
|
|
230
|
+
// a new panel, when in reality it just creates a new tab in the target panel.
|
|
231
|
+
else {
|
|
232
|
+
pushZone("CENTER", left, top, width, height);
|
|
233
|
+
}
|
|
234
|
+
pushZone("TAB", left, top, width, element.children[0].offsetHeight);
|
|
219
235
|
}
|
|
220
236
|
else {
|
|
221
237
|
const firstTabs = config.children?.[0]?.tabs || [null];
|
|
@@ -340,9 +356,33 @@ const Overlay = ({ panelElements, onDrop, rootConfig, }) => {
|
|
|
340
356
|
const overlayRef = useRef(null);
|
|
341
357
|
return _jsx("div", { className: "tab-handle-overlay", ref: overlayRef });
|
|
342
358
|
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
359
|
+
/**
|
|
360
|
+
* A Panel component.
|
|
361
|
+
*
|
|
362
|
+
* This component represents a Panel within the layout.
|
|
363
|
+
*
|
|
364
|
+
* @param props.name The unique identifier of the panel.
|
|
365
|
+
* @param props.header The content to render in the panel header.
|
|
366
|
+
* @param props.children The content to render within the panel.
|
|
367
|
+
*/
|
|
368
|
+
export const Panel = (props) => {
|
|
369
|
+
return null;
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* Main layout component that organizes panels and handles drag and drop.
|
|
373
|
+
*
|
|
374
|
+
* The Layout component takes child panel components, constructs an initial layout configuration,
|
|
375
|
+
* and renders the panel structure using NestedPanel. It also wraps the layout in a DndProvider
|
|
376
|
+
* if drag and drop support is enabled.
|
|
377
|
+
*
|
|
378
|
+
* @param children The children `Panel` components to render within the layout.
|
|
379
|
+
* @param defaultConfig The default layout configuration to use.
|
|
380
|
+
* @param wrapDnd A boolean flag to enable or disable drag and drop support (default: true).
|
|
381
|
+
* @returns A React element representing the complete panel layout.
|
|
382
|
+
*/
|
|
383
|
+
export function Layout({ children, defaultConfig, wrapDnd = true, }) {
|
|
384
|
+
const children_array = React.Children.toArray(children);
|
|
385
|
+
const namedChildren = Object.fromEntries(children_array.map((c, i) => [
|
|
346
386
|
c.props.name || (c.key !== null ? c.key.toString().slice(2) : `unnamed-${i}`),
|
|
347
387
|
{
|
|
348
388
|
element: c.props.children,
|
|
@@ -350,14 +390,14 @@ export function Layout(props) {
|
|
|
350
390
|
},
|
|
351
391
|
]));
|
|
352
392
|
const panelElements = useRef(new Map());
|
|
353
|
-
const [rootConfig, setRootConfig] = useState(
|
|
393
|
+
const [rootConfig, setRootConfig] = useState(defaultConfig || {
|
|
354
394
|
kind: "row",
|
|
355
395
|
size: 1,
|
|
356
|
-
children:
|
|
396
|
+
children: children_array.map((c, i) => ({
|
|
357
397
|
kind: "leaf",
|
|
358
398
|
tabs: [c.props.name || (c.key !== null ? c.key.toString().slice(2) : `unnamed-${i}`)],
|
|
359
399
|
tabIndex: 0,
|
|
360
|
-
size: 100 /
|
|
400
|
+
size: 100 / children_array.length,
|
|
361
401
|
})),
|
|
362
402
|
});
|
|
363
403
|
let config = rootConfig;
|
|
@@ -373,11 +413,8 @@ export function Layout(props) {
|
|
|
373
413
|
setRootConfig(newConfig);
|
|
374
414
|
};
|
|
375
415
|
const container = (_jsxs("div", { className: "container", children: [_jsx(NestedPanel, { leaves: namedChildren, config: config, panelElements: panelElements.current }), _jsx(Overlay, { panelElements: panelElements, onDrop: handleDrop, rootConfig: config })] }));
|
|
376
|
-
if (
|
|
416
|
+
if (wrapDnd) {
|
|
377
417
|
return _jsx(DndProvider, { backend: HTML5Backend, children: container });
|
|
378
418
|
}
|
|
379
419
|
return container;
|
|
380
420
|
}
|
|
381
|
-
Layout.defaultProps = {
|
|
382
|
-
wrapDnd: true,
|
|
383
|
-
};
|