@noya-app/noya-designsystem 0.1.46 → 0.1.48

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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +16 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +208 -98
  5. package/dist/index.d.ts +208 -98
  6. package/dist/index.js +2148 -1604
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +2153 -1618
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -7
  11. package/src/__tests__/validateDropIndicator.test.ts +263 -0
  12. package/src/components/ActionMenu.tsx +40 -0
  13. package/src/components/ActivityIndicator.tsx +7 -1
  14. package/src/components/Collection.tsx +12 -2
  15. package/src/components/Combobox.tsx +14 -1
  16. package/src/components/ComboboxMenu.tsx +14 -5
  17. package/src/components/Dialog.tsx +28 -31
  18. package/src/components/Drawer.tsx +98 -0
  19. package/src/components/Grid.tsx +57 -27
  20. package/src/components/GridView.tsx +39 -25
  21. package/src/components/InputField.tsx +87 -92
  22. package/src/components/Label.tsx +7 -7
  23. package/src/components/List.tsx +42 -16
  24. package/src/components/ListView.tsx +21 -17
  25. package/src/components/MediaThumbnail.tsx +117 -0
  26. package/src/components/SearchCompletionMenu.tsx +31 -37
  27. package/src/components/SelectMenu.tsx +19 -17
  28. package/src/components/Sortable.tsx +70 -44
  29. package/src/components/Switch.tsx +1 -1
  30. package/src/components/internal/Menu.tsx +38 -23
  31. package/src/components/internal/MenuViewport.tsx +7 -1
  32. package/src/components/internal/SelectItem.tsx +51 -27
  33. package/src/components/internal/__tests__/Menu.test.tsx +12 -0
  34. package/src/components/workspace/DrawerWorkspaceLayout.tsx +86 -0
  35. package/src/components/workspace/PanelWorkspaceLayout.tsx +102 -0
  36. package/src/components/{WorkspaceLayout.tsx → workspace/WorkspaceLayout.tsx} +109 -106
  37. package/src/components/workspace/types.ts +31 -0
  38. package/src/contexts/DialogContext.tsx +91 -30
  39. package/src/hooks/usePreservePanelSize.tsx +1 -5
  40. package/src/index.css +3 -1
  41. package/src/index.tsx +4 -1
  42. package/tailwind.config.ts +1 -0
@@ -3,8 +3,10 @@ import { renderIcon } from "../Icons";
3
3
  import { CheckIcon } from "@noya-app/noya-icons";
4
4
  import * as Select from "@radix-ui/react-select";
5
5
  import React, { useCallback } from "react";
6
+ import { cx } from "../../utils/classNames";
6
7
  import { Spacer } from "../Spacer";
7
8
  import {
9
+ CHECKBOX_INDENT_WIDTH,
8
10
  CHECKBOX_RIGHT_INSET,
9
11
  CHECKBOX_WIDTH,
10
12
  KeyboardShortcut,
@@ -24,6 +26,7 @@ export const SelectItem = React.forwardRef(
24
26
  onSelect,
25
27
  shortcut,
26
28
  indented,
29
+ testSelected,
27
30
  ...props
28
31
  }: Select.SelectItemProps & {
29
32
  icon?: React.ReactNode;
@@ -32,6 +35,7 @@ export const SelectItem = React.forwardRef(
32
35
  onSelect?: (value: any) => void;
33
36
  shortcut?: string;
34
37
  indented?: boolean;
38
+ testSelected?: boolean;
35
39
  },
36
40
  forwardedRef: React.ForwardedRef<HTMLDivElement>
37
41
  ) => {
@@ -40,48 +44,68 @@ export const SelectItem = React.forwardRef(
40
44
  onSelect?.(value);
41
45
  }, [onSelect, value]);
42
46
 
47
+ // Prevent the click from propagating outside the menu
48
+ const cancelClickPropagation = useCallback(
49
+ (event: React.MouseEvent<HTMLDivElement>) => {
50
+ event.stopPropagation();
51
+ },
52
+ []
53
+ );
54
+
43
55
  if (checked && Components.CheckboxItem) {
44
56
  return (
45
- <Components.CheckboxItem
46
- checked={checked}
47
- disabled={disabled}
48
- onSelect={handleSelectItem}
49
- className={styles.itemStyle({ disabled })}
50
- >
51
- {Components.ItemIndicator && (
52
- <Components.ItemIndicator className={styles.itemIndicatorStyle}>
53
- <CheckIcon />
54
- </Components.ItemIndicator>
55
- )}
56
- {icon && (
57
- <>
58
- {renderIcon(icon)}
59
- <Spacer.Horizontal size={8} />
60
- </>
61
- )}
62
- {children}
63
- {shortcut && (
64
- <>
65
- <Spacer.Horizontal />
66
- <Spacer.Horizontal size={24} />
67
- <KeyboardShortcut shortcut={shortcut} />
68
- </>
69
- )}
70
- </Components.CheckboxItem>
57
+ <div className="px-1">
58
+ <Components.CheckboxItem
59
+ checked={checked}
60
+ disabled={disabled}
61
+ onSelect={handleSelectItem}
62
+ className={cx(
63
+ styles.itemStyle({ disabled }),
64
+ styles.selectedItemStyle,
65
+ testSelected && styles.testSelectedItemStyle
66
+ )}
67
+ >
68
+ {Components.ItemIndicator && (
69
+ <Components.ItemIndicator className={styles.itemIndicatorStyle}>
70
+ <CheckIcon />
71
+ </Components.ItemIndicator>
72
+ )}
73
+ {icon && (
74
+ <>
75
+ {renderIcon(icon)}
76
+ <Spacer.Horizontal size={8} />
77
+ </>
78
+ )}
79
+ {children}
80
+ {shortcut && (
81
+ <>
82
+ <Spacer.Horizontal />
83
+ <Spacer.Horizontal size={24} />
84
+ <KeyboardShortcut shortcut={shortcut} />
85
+ </>
86
+ )}
87
+ </Components.CheckboxItem>
88
+ </div>
71
89
  );
72
90
  }
73
91
 
74
92
  return (
75
93
  <div className="px-1">
76
94
  <Components.Item
77
- className={styles.itemStyle({ disabled })}
95
+ className={cx(
96
+ styles.itemStyle({ disabled }),
97
+ styles.selectedItemStyle,
98
+ testSelected && styles.testSelectedItemStyle
99
+ )}
78
100
  disabled={disabled}
79
101
  value={value}
80
102
  ref={forwardedRef}
103
+ onClick={cancelClickPropagation}
81
104
  onSelect={handleSelectItem}
82
105
  {...props}
83
106
  >
84
107
  <div className="flex flex-1 items-center">
108
+ {indented && <Spacer.Horizontal size={CHECKBOX_INDENT_WIDTH} />}
85
109
  {checked ? (
86
110
  <div className={styles.itemIndicatorStyle}>
87
111
  <CheckIcon />
@@ -0,0 +1,12 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { styles } from "../Menu";
3
+
4
+ describe("Menu", () => {
5
+ test("styles.selectedItemStyle should have the same styles as styles.testSelectedItemStyle without the focus: prefix", () => {
6
+ const selectedWithoutFocus = styles.selectedItemStyle.replace(
7
+ /focus:/g,
8
+ ""
9
+ );
10
+ expect(selectedWithoutFocus).toEqual(styles.testSelectedItemStyle);
11
+ });
12
+ });
@@ -0,0 +1,86 @@
1
+ import React, { memo, useLayoutEffect, useRef, useState } from "react";
2
+ import {
3
+ EDITOR_PANEL_GROUP_ID,
4
+ LEFT_SIDEBAR_ID,
5
+ RIGHT_SIDEBAR_ID,
6
+ } from "../../hooks/usePreservePanelSize";
7
+ import { Drawer } from "../Drawer";
8
+ import { LayoutProps } from "./types";
9
+
10
+ export const DrawerWorkspaceLayout = memo(function DrawerWorkspaceLayout({
11
+ leftPanel,
12
+ leftSidebarRef,
13
+ rightPanel,
14
+ rightSidebarRef,
15
+ centerPanel,
16
+ internalLayoutState,
17
+ handleChangeLayoutState,
18
+ }: LayoutProps) {
19
+ const portalContainer = useRef<HTMLDivElement>(null);
20
+ const [mounted, setMounted] = useState(false);
21
+
22
+ useLayoutEffect(() => {
23
+ if (mounted) return;
24
+
25
+ setMounted(true);
26
+ handleChangeLayoutState({
27
+ leftSidebarCollapsed: true,
28
+ rightSidebarCollapsed: true,
29
+ });
30
+ }, [handleChangeLayoutState, mounted]);
31
+
32
+ const leftSidebarCollapsed =
33
+ internalLayoutState?.leftSidebarCollapsed ?? false;
34
+ const rightSidebarCollapsed =
35
+ internalLayoutState?.rightSidebarCollapsed ?? false;
36
+
37
+ return (
38
+ <div
39
+ ref={portalContainer}
40
+ id={EDITOR_PANEL_GROUP_ID}
41
+ className="flex flex-1 relative focus:outline-none"
42
+ >
43
+ {leftPanel && (
44
+ <Drawer
45
+ id={LEFT_SIDEBAR_ID}
46
+ ref={leftSidebarRef}
47
+ className="flex-1"
48
+ open={!leftSidebarCollapsed}
49
+ positioning="absolute"
50
+ side="left"
51
+ trigger={null}
52
+ portalContainer={portalContainer.current}
53
+ onOpenChange={(open) => {
54
+ handleChangeLayoutState({
55
+ rightSidebarCollapsed: rightSidebarCollapsed,
56
+ leftSidebarCollapsed: !open,
57
+ });
58
+ }}
59
+ >
60
+ {leftPanel}
61
+ </Drawer>
62
+ )}
63
+ {centerPanel}
64
+ {rightPanel && (
65
+ <Drawer
66
+ id={RIGHT_SIDEBAR_ID}
67
+ ref={rightSidebarRef}
68
+ className="flex-1"
69
+ open={!rightSidebarCollapsed}
70
+ positioning="absolute"
71
+ side="right"
72
+ trigger={null}
73
+ portalContainer={portalContainer.current}
74
+ onOpenChange={(open) => {
75
+ handleChangeLayoutState({
76
+ leftSidebarCollapsed: leftSidebarCollapsed,
77
+ rightSidebarCollapsed: !open,
78
+ });
79
+ }}
80
+ >
81
+ {rightPanel}
82
+ </Drawer>
83
+ )}
84
+ </div>
85
+ );
86
+ });
@@ -0,0 +1,102 @@
1
+ import React, { memo, useRef } from "react";
2
+ import {
3
+ ImperativePanelGroupHandle,
4
+ ImperativePanelHandle,
5
+ Panel,
6
+ PanelGroup,
7
+ PanelResizeHandle,
8
+ } from "react-resizable-panels";
9
+ import {
10
+ CONTENT_AREA_ID,
11
+ EDITOR_PANEL_GROUP_ID,
12
+ LEFT_SIDEBAR_ID,
13
+ RIGHT_SIDEBAR_ID,
14
+ usePreservePanelSize,
15
+ } from "../../hooks/usePreservePanelSize";
16
+ import { LayoutProps } from "./types";
17
+
18
+ export const PanelWorkspaceLayout = memo(function PanelWorkspaceLayout({
19
+ leftPanel,
20
+ rightPanel,
21
+ centerPanel,
22
+ leftSidebarOptions,
23
+ rightSidebarOptions,
24
+ centerPanelPercentage,
25
+ autoSavePrefix,
26
+ internalLayoutState,
27
+ leftSidebarRef,
28
+ rightSidebarRef,
29
+ handleChangeLayoutState,
30
+ }: LayoutProps) {
31
+ const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
32
+
33
+ usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
34
+
35
+ return (
36
+ <PanelGroup
37
+ ref={panelGroupRef}
38
+ id={EDITOR_PANEL_GROUP_ID}
39
+ className="flex-1"
40
+ direction="horizontal"
41
+ autoSaveId={
42
+ autoSavePrefix
43
+ ? `${autoSavePrefix}--${EDITOR_PANEL_GROUP_ID}`
44
+ : undefined
45
+ }
46
+ >
47
+ {leftPanel && (
48
+ <>
49
+ <Panel
50
+ id={LEFT_SIDEBAR_ID}
51
+ className="relative"
52
+ order={1}
53
+ ref={leftSidebarRef as React.RefObject<ImperativePanelHandle>}
54
+ defaultSize={leftSidebarOptions.initialSize}
55
+ minSize={leftSidebarOptions.minSize}
56
+ maxSize={
57
+ leftSidebarOptions.maxSize ??
58
+ (!leftSidebarOptions.resizable
59
+ ? leftSidebarOptions.initialSize
60
+ : undefined)
61
+ }
62
+ collapsible
63
+ >
64
+ {internalLayoutState?.leftSidebarCollapsed ? null : leftPanel}
65
+ </Panel>
66
+ <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
67
+ </>
68
+ )}
69
+ <Panel
70
+ id={CONTENT_AREA_ID}
71
+ order={2}
72
+ defaultSize={centerPanelPercentage}
73
+ minSize={10}
74
+ className="flex relative"
75
+ >
76
+ {centerPanel}
77
+ </Panel>
78
+ {rightPanel && (
79
+ <>
80
+ <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
81
+ <Panel
82
+ id={RIGHT_SIDEBAR_ID}
83
+ className="relative"
84
+ order={3}
85
+ ref={rightSidebarRef as React.RefObject<ImperativePanelHandle>}
86
+ minSize={rightSidebarOptions.minSize}
87
+ defaultSize={rightSidebarOptions.initialSize}
88
+ maxSize={
89
+ rightSidebarOptions.maxSize ??
90
+ (!rightSidebarOptions.resizable
91
+ ? rightSidebarOptions.initialSize
92
+ : undefined)
93
+ }
94
+ collapsible
95
+ >
96
+ {internalLayoutState?.rightSidebarCollapsed ? null : rightPanel}
97
+ </Panel>
98
+ </>
99
+ )}
100
+ </PanelGroup>
101
+ );
102
+ });
@@ -1,4 +1,5 @@
1
1
  import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
2
+ import { useSize } from "@noya-app/react-utils";
2
3
  import React, {
3
4
  forwardRef,
4
5
  memo,
@@ -7,23 +8,19 @@ import React, {
7
8
  useRef,
8
9
  useState,
9
10
  } from "react";
11
+ import { useWindowSize } from "../../hooks/useWindowSize";
12
+ import { cx } from "../../utils/classNames";
13
+ import { DrawerWorkspaceLayout } from "./DrawerWorkspaceLayout";
14
+ import { PanelWorkspaceLayout } from "./PanelWorkspaceLayout";
10
15
  import {
11
- ImperativePanelGroupHandle,
12
- ImperativePanelHandle,
13
- Panel,
14
- PanelGroup,
15
- PanelResizeHandle,
16
- } from "react-resizable-panels";
17
- import {
18
- CONTENT_AREA_ID,
19
- EDITOR_PANEL_GROUP_ID,
20
- LEFT_SIDEBAR_ID,
21
16
  PanelLayoutState,
22
- RIGHT_SIDEBAR_ID,
23
- usePreservePanelSize,
24
- } from "../hooks/usePreservePanelSize";
25
- import { useWindowSize } from "../hooks/useWindowSize";
26
- import { cx } from "../utils/classNames";
17
+ PercentageSidebarOptions,
18
+ SidebarRef,
19
+ } from "./types";
20
+
21
+ export type SideType = "auto" | "panel" | "drawer";
22
+
23
+ export type DetectSizeType = "container" | "window";
27
24
 
28
25
  export interface WorkspaceLayoutProps {
29
26
  id?: string;
@@ -37,10 +34,13 @@ export interface WorkspaceLayoutProps {
37
34
  right?: React.ReactNode;
38
35
  rightOptions?: SideOptions;
39
36
  toolbar?: React.ReactNode;
37
+ sideType?: SideType;
38
+ sideTypeBreakpoint?: number;
39
+ detectSize?: DetectSizeType;
40
40
  onChangeLayoutState?: (layoutState: PanelLayoutState) => void;
41
41
  }
42
42
 
43
- export type IWorkspaceLayout = {
43
+ export type WorkspaceLayoutRef = {
44
44
  setLeftExpanded: (expanded: boolean) => void;
45
45
  setRightExpanded: (expanded: boolean) => void;
46
46
  toggleSides: () => void;
@@ -72,6 +72,9 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
72
72
  toolbar,
73
73
  children,
74
74
  onChangeLayoutState,
75
+ sideType = "auto",
76
+ sideTypeBreakpoint = 800,
77
+ detectSize = "container",
75
78
  leftOptions: {
76
79
  minSize: leftMinSize = 200,
77
80
  maxSize: leftMaxSize = 500,
@@ -90,13 +93,25 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
90
93
  } = {},
91
94
  theme,
92
95
  }: WorkspaceLayoutProps,
93
- forwardedRef: React.ForwardedRef<IWorkspaceLayout>
96
+ forwardedRef: React.ForwardedRef<WorkspaceLayoutRef>
94
97
  ) {
98
+ const containerRef = React.useRef<HTMLDivElement | null>(null);
99
+ const containerSize = useSize(containerRef);
95
100
  const windowSize = useWindowSize();
101
+
102
+ // If we're in embedded (iframed) mode, use the window size.
103
+ // Otherwise, use the container size (if it's available).
104
+ const parentSize =
105
+ detectSize === "window"
106
+ ? windowSize
107
+ : containerSize && containerSize.width > 0
108
+ ? containerSize
109
+ : windowSize;
110
+
96
111
  function getPercentage(size: number | string) {
97
112
  return typeof size === "string"
98
113
  ? parseFloat(size)
99
- : (size / windowSize.width) * 100;
114
+ : (size / parentSize.width) * 100;
100
115
  }
101
116
 
102
117
  function clampPercentage(
@@ -134,12 +149,12 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
134
149
  rightSidebarMaxPercentage
135
150
  );
136
151
 
137
- const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
138
- const leftSidebarRef = useRef<ImperativePanelHandle>(null);
139
- const rightSidebarRef = useRef<ImperativePanelHandle>(null);
152
+ const leftSidebarRef = useRef<SidebarRef>(null);
153
+ const rightSidebarRef = useRef<SidebarRef>(null);
140
154
 
141
155
  const [internalLayoutState, setInternalLayoutState] =
142
156
  useState<PanelLayoutState | null>(null);
157
+
143
158
  const handleChangeLayoutState = useCallback(
144
159
  (state: PanelLayoutState) => {
145
160
  setInternalLayoutState(state);
@@ -148,8 +163,6 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
148
163
  [onChangeLayoutState]
149
164
  );
150
165
 
151
- usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
152
-
153
166
  useImperativeHandle(forwardedRef, () => ({
154
167
  setLeftExpanded: (expanded: boolean) => {
155
168
  if (expanded) {
@@ -217,96 +230,86 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
217
230
  (left ? leftSidebarPercentage : 0) -
218
231
  (right ? rightSidebarPercentage : 0);
219
232
 
233
+ const leftPanel = left ? (
234
+ <PanelInner
235
+ style={leftStyle}
236
+ className={cx("bg-sidebar-background flex-col", leftClassName)}
237
+ >
238
+ {left}
239
+ </PanelInner>
240
+ ) : null;
241
+
242
+ const rightPanel = right ? (
243
+ <PanelInner
244
+ style={rightStyle}
245
+ className={cx("bg-sidebar-background flex-col", rightClassName)}
246
+ >
247
+ {right}
248
+ </PanelInner>
249
+ ) : null;
250
+
251
+ const centerPanel = (
252
+ <PanelInner className="bg-canvas-background">{children}</PanelInner>
253
+ );
254
+
255
+ const leftSidebarOptions: PercentageSidebarOptions = {
256
+ minSize: leftSidebarMinPercentage,
257
+ maxSize: leftSidebarMaxPercentage,
258
+ initialSize: leftSidebarPercentage,
259
+ resizable: leftResizable,
260
+ };
261
+
262
+ const rightSidebarOptions: PercentageSidebarOptions = {
263
+ minSize: rightSidebarMinPercentage,
264
+ maxSize: rightSidebarMaxPercentage,
265
+ initialSize: rightSidebarPercentage,
266
+ resizable: rightResizable,
267
+ };
268
+
269
+ const LayoutComponent =
270
+ sideType === "panel"
271
+ ? PanelWorkspaceLayout
272
+ : sideType === "drawer"
273
+ ? DrawerWorkspaceLayout
274
+ : parentSize.width > sideTypeBreakpoint
275
+ ? PanelWorkspaceLayout
276
+ : DrawerWorkspaceLayout;
277
+
278
+ // Wait until the container size is available to render the layout.
279
+ // This is to avoid flickering when the layout is initially rendered.
280
+ // If we're in embedded (iframed) mode, we don't need to wait for the container size,
281
+ // because the window size is guaranteed to be available.
282
+ //
283
+ // We could always wait for the container size, but this lets us render
284
+ // sooner in the embedded case.
285
+ const readyToRender =
286
+ detectSize === "window" || (containerSize && containerSize.width > 0);
287
+
220
288
  return (
221
289
  <div
290
+ ref={containerRef}
222
291
  id={id}
223
- className={cx("flex flex-col bg-canvas-background", className)}
292
+ className={cx("flex flex-col bg-canvas-background relative", className)}
224
293
  style={style}
225
294
  data-theme={theme}
226
295
  >
227
296
  {toolbar}
228
- <div className="flex flex-row flex-1">
229
- <PanelGroup
230
- ref={panelGroupRef}
231
- id={EDITOR_PANEL_GROUP_ID}
232
- className="flex-1"
233
- direction="horizontal"
234
- autoSaveId={
235
- autoSavePrefix
236
- ? `${autoSavePrefix}--${EDITOR_PANEL_GROUP_ID}`
237
- : undefined
238
- }
239
- >
240
- {left && (
241
- <>
242
- <Panel
243
- id={LEFT_SIDEBAR_ID}
244
- className="relative"
245
- order={1}
246
- ref={leftSidebarRef}
247
- defaultSize={leftSidebarPercentage}
248
- minSize={leftSidebarMinPercentage ?? leftSidebarPercentage}
249
- maxSize={
250
- leftSidebarMaxPercentage ??
251
- (!leftResizable ? leftSidebarPercentage : undefined)
252
- }
253
- collapsible
254
- >
255
- {internalLayoutState?.leftSidebarCollapsed ? null : (
256
- <PanelInner
257
- style={leftStyle}
258
- className={cx(
259
- "bg-sidebar-background flex-col",
260
- leftClassName
261
- )}
262
- >
263
- {left}
264
- </PanelInner>
265
- )}
266
- </Panel>
267
- <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
268
- </>
269
- )}
270
- <Panel
271
- id={CONTENT_AREA_ID}
272
- order={2}
273
- defaultSize={centerPanelPercentage}
274
- minSize={10}
275
- className="flex relative"
276
- >
277
- <PanelInner className="bg-canvas-background">{children}</PanelInner>
278
- </Panel>
279
- {right && (
280
- <>
281
- <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
282
- <Panel
283
- id={RIGHT_SIDEBAR_ID}
284
- className="relative"
285
- order={3}
286
- ref={rightSidebarRef}
287
- minSize={rightSidebarMinPercentage ?? rightSidebarPercentage}
288
- defaultSize={rightSidebarPercentage}
289
- maxSize={
290
- rightSidebarMaxPercentage ??
291
- (!rightResizable ? rightSidebarPercentage : undefined)
292
- }
293
- collapsible
294
- >
295
- {internalLayoutState?.rightSidebarCollapsed ? null : (
296
- <PanelInner
297
- style={rightStyle}
298
- className={cx(
299
- "bg-sidebar-background flex-col",
300
- rightClassName
301
- )}
302
- >
303
- {right}
304
- </PanelInner>
305
- )}
306
- </Panel>
307
- </>
308
- )}
309
- </PanelGroup>
297
+ <div className="flex flex-row flex-1 relative">
298
+ {readyToRender && (
299
+ <LayoutComponent
300
+ leftPanel={leftPanel}
301
+ rightPanel={rightPanel}
302
+ centerPanel={centerPanel}
303
+ leftSidebarOptions={leftSidebarOptions}
304
+ rightSidebarOptions={rightSidebarOptions}
305
+ centerPanelPercentage={centerPanelPercentage}
306
+ autoSavePrefix={autoSavePrefix}
307
+ internalLayoutState={internalLayoutState}
308
+ leftSidebarRef={leftSidebarRef}
309
+ rightSidebarRef={rightSidebarRef}
310
+ handleChangeLayoutState={handleChangeLayoutState}
311
+ />
312
+ )}
310
313
  </div>
311
314
  </div>
312
315
  );
@@ -0,0 +1,31 @@
1
+ export type SidebarRef = {
2
+ expand: () => void;
3
+ collapse: () => void;
4
+ isExpanded: () => boolean;
5
+ };
6
+
7
+ export type PercentageSidebarOptions = {
8
+ minSize?: number;
9
+ maxSize?: number;
10
+ initialSize?: number;
11
+ resizable?: boolean;
12
+ };
13
+
14
+ export type PanelLayoutState = {
15
+ leftSidebarCollapsed: boolean;
16
+ rightSidebarCollapsed: boolean;
17
+ };
18
+
19
+ export type LayoutProps = {
20
+ leftPanel: React.ReactNode;
21
+ rightPanel: React.ReactNode;
22
+ centerPanel: React.ReactNode;
23
+ leftSidebarOptions: PercentageSidebarOptions;
24
+ rightSidebarOptions: PercentageSidebarOptions;
25
+ centerPanelPercentage: number;
26
+ autoSavePrefix?: string;
27
+ internalLayoutState: PanelLayoutState | null;
28
+ leftSidebarRef: React.RefObject<SidebarRef>;
29
+ rightSidebarRef: React.RefObject<SidebarRef>;
30
+ handleChangeLayoutState: (state: PanelLayoutState) => void;
31
+ };