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 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
- export declare function Layout(props: {
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 getPanelElementHeader = (node) => node.children[0];
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 < headerHeight) {
126
- size = (headerHeight / parentHeight) * total;
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 < headerHeight) {
130
- nextSize = (headerHeight / parentHeight) * total;
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.includes(name)) {
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
- pushZone("CENTER", left, top, width, height);
218
- pushZone("TAB", left, top, width, getPanelElementHeader(element).offsetHeight);
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
- export function Layout(props) {
344
- const children = React.Children.toArray(props.children);
345
- const namedChildren = Object.fromEntries(children.map((c, i) => [
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(props.defaultConfig || {
393
+ const [rootConfig, setRootConfig] = useState(defaultConfig || {
354
394
  kind: "row",
355
395
  size: 1,
356
- children: children.map((c, i) => ({
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 / children.length,
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 (props.wrapDnd) {
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
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-simple-dock",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "main": "index.js",
5
5
  "description": "Simple dock component for React",
6
6
  "repository": "https://github.com/percevalw/react-simple-dock",