@noya-app/noya-designsystem 0.1.42 → 0.1.44

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.
@@ -1,6 +1,7 @@
1
1
  import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
2
2
  import React, {
3
3
  forwardRef,
4
+ memo,
4
5
  useCallback,
5
6
  useImperativeHandle,
6
7
  useRef,
@@ -22,63 +23,67 @@ import {
22
23
  usePreservePanelSize,
23
24
  } from "../hooks/usePreservePanelSize";
24
25
  import { useWindowSize } from "../hooks/useWindowSize";
25
- import { cssVars } from "../theme";
26
+ import { cx } from "../utils/classNames";
26
27
 
27
28
  interface Props {
28
- autoSavePrefix?: string;
29
- leftSidebarContent?: React.ReactNode;
30
- children?: React.ReactNode;
31
- rightSidebarContent?: React.ReactNode;
32
- hasRightSidebar?: boolean;
33
- hasLeftSidebar?: boolean;
34
- onChangeLayoutState?: (layoutState: PanelLayoutState) => void;
35
- leftSidebarCanResize?: boolean;
36
- rightSidebarCanResize?: boolean;
37
29
  id?: string;
38
30
  className?: string;
39
31
  style?: React.CSSProperties;
32
+ autoSavePrefix?: string;
33
+ left?: React.ReactNode;
34
+ leftOptions?: SideOptions;
35
+ children?: React.ReactNode;
36
+ right?: React.ReactNode;
37
+ rightOptions?: SideOptions;
38
+ toolbar?: React.ReactNode;
39
+ onChangeLayoutState?: (layoutState: PanelLayoutState) => void;
40
+ }
40
41
 
41
- /**
42
- * Accepts a number (px) or % string (e.g. "50%").
43
- * Use % to avoid flicker server-rendering.
44
- */
45
- leftSidebarInitialSize?: number | string;
46
- leftSidebarMinSize?: number | string;
42
+ export type IWorkspaceLayout = {
43
+ setLeftExpanded: (expanded: boolean) => void;
44
+ setRightExpanded: (expanded: boolean) => void;
45
+ toggleSides: () => void;
46
+ toggleLeft: () => void;
47
+ toggleRight: () => void;
48
+ };
47
49
 
50
+ export type SideOptions = {
51
+ style?: React.CSSProperties;
52
+ className?: string;
53
+ resizable?: boolean;
48
54
  /**
49
55
  * Accepts a number (px) or % string (e.g. "50%").
50
56
  * Use % to avoid flicker server-rendering.
51
57
  */
52
- rightSidebarInitialSize?: number | string;
53
- rightSidebarMinSize?: number | string;
54
- }
55
-
56
- export type IWorkspaceLayout = {
57
- setLeftSidebarExpanded: (expanded: boolean) => void;
58
- setRightSidebarExpanded: (expanded: boolean) => void;
59
- toggleAllSidebars: () => void;
60
- toggleLeftSidebar: () => void;
61
- toggleRightSidebar: () => void;
58
+ initialSize?: number | string;
59
+ minSize?: number | string;
62
60
  };
63
61
 
64
- const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
62
+ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
65
63
  {
66
64
  autoSavePrefix,
67
- leftSidebarContent: leftPanelContent,
68
- children: centerPanelContent,
69
- rightSidebarContent: rightPanelContent,
70
- hasLeftSidebar = !!leftPanelContent,
71
- hasRightSidebar = !!rightPanelContent,
72
- onChangeLayoutState,
73
- leftSidebarInitialSize = 280,
74
- rightSidebarInitialSize = 400,
75
- leftSidebarMinSize,
76
- rightSidebarMinSize,
77
- leftSidebarCanResize = false,
78
- rightSidebarCanResize = false,
65
+ left,
66
+ right,
79
67
  id,
80
68
  className,
81
69
  style,
70
+ toolbar,
71
+ children,
72
+ onChangeLayoutState,
73
+ leftOptions: {
74
+ initialSize: leftInitialSize = 280,
75
+ minSize: leftMinSize,
76
+ resizable: leftResizable = true,
77
+ style: leftStyle,
78
+ className: leftClassName,
79
+ } = {},
80
+ rightOptions: {
81
+ initialSize: rightInitialSize = 280,
82
+ minSize: rightMinSize,
83
+ resizable: rightResizable = true,
84
+ style: rightStyle,
85
+ className: rightClassName,
86
+ } = {},
82
87
  }: Props,
83
88
  forwardedRef: React.ForwardedRef<IWorkspaceLayout>
84
89
  ) {
@@ -88,16 +93,13 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
88
93
  ? parseFloat(size)
89
94
  : (size / windowSize.width) * 100;
90
95
  }
91
- const leftSidebarPercentage = getPercentage(leftSidebarInitialSize);
92
- const rightSidebarPercentage = getPercentage(rightSidebarInitialSize);
96
+
97
+ const leftSidebarPercentage = getPercentage(leftInitialSize);
98
+ const rightSidebarPercentage = getPercentage(rightInitialSize);
93
99
  const leftSidebarMinPercentage =
94
- leftSidebarMinSize !== undefined
95
- ? getPercentage(leftSidebarMinSize)
96
- : undefined;
100
+ leftMinSize !== undefined ? getPercentage(leftMinSize) : undefined;
97
101
  const rightSidebarMinPercentage =
98
- rightSidebarMinSize !== undefined
99
- ? getPercentage(rightSidebarMinSize)
100
- : undefined;
102
+ rightMinSize !== undefined ? getPercentage(rightMinSize) : undefined;
101
103
 
102
104
  const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
103
105
  const leftSidebarRef = useRef<ImperativePanelHandle>(null);
@@ -116,21 +118,21 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
116
118
  usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
117
119
 
118
120
  useImperativeHandle(forwardedRef, () => ({
119
- setLeftSidebarExpanded: (expanded: boolean) => {
121
+ setLeftExpanded: (expanded: boolean) => {
120
122
  if (expanded) {
121
123
  leftSidebarRef.current?.expand();
122
124
  } else {
123
125
  leftSidebarRef.current?.collapse();
124
126
  }
125
127
  },
126
- setRightSidebarExpanded: (expanded: boolean) => {
128
+ setRightExpanded: (expanded: boolean) => {
127
129
  if (expanded) {
128
130
  rightSidebarRef.current?.expand();
129
131
  } else {
130
132
  rightSidebarRef.current?.collapse();
131
133
  }
132
134
  },
133
- toggleAllSidebars: () => {
135
+ toggleSides: () => {
134
136
  const isLeftSidebarExpanded = leftSidebarRef.current?.isExpanded();
135
137
  const isRightSidebarExpanded = rightSidebarRef.current?.isExpanded();
136
138
 
@@ -142,7 +144,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
142
144
  rightSidebarRef.current?.expand();
143
145
  }
144
146
  },
145
- toggleLeftSidebar: () => {
147
+ toggleLeft: () => {
146
148
  const isLeftSidebarExpanded = leftSidebarRef.current?.isExpanded();
147
149
 
148
150
  if (isLeftSidebarExpanded) {
@@ -151,7 +153,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
151
153
  leftSidebarRef.current?.expand();
152
154
  }
153
155
  },
154
- toggleRightSidebar: () => {
156
+ toggleRight: () => {
155
157
  const isRightSidebarExpanded = rightSidebarRef.current?.isExpanded();
156
158
 
157
159
  if (isRightSidebarExpanded) {
@@ -179,114 +181,105 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
179
181
 
180
182
  const centerPanelPercentage =
181
183
  100 -
182
- (leftPanelContent ? leftSidebarPercentage : 0) -
183
- (rightPanelContent ? rightSidebarPercentage : 0);
184
+ (left ? leftSidebarPercentage : 0) -
185
+ (right ? rightSidebarPercentage : 0);
184
186
 
185
187
  return (
186
188
  <div
187
189
  id={id}
188
- className={className}
189
- style={{
190
- backgroundColor: cssVars.colors.canvasBackground,
191
- display: "flex",
192
- flexDirection: "row",
193
- ...style,
194
- }}
190
+ className={cx("flex flex-col bg-canvas-background", className)}
191
+ style={style}
195
192
  >
196
- <PanelGroup
197
- ref={panelGroupRef}
198
- id={EDITOR_PANEL_GROUP_ID}
199
- direction="horizontal"
200
- autoSaveId={
201
- autoSavePrefix
202
- ? `${autoSavePrefix}--${EDITOR_PANEL_GROUP_ID}`
203
- : undefined
204
- }
205
- style={{ flex: "1" }}
206
- >
207
- {hasLeftSidebar && (
208
- <>
209
- <Panel
210
- id={LEFT_SIDEBAR_ID}
211
- order={1}
212
- ref={leftSidebarRef}
213
- defaultSize={leftSidebarPercentage}
214
- minSize={leftSidebarMinPercentage ?? leftSidebarPercentage}
215
- {...(!leftSidebarCanResize && { maxSize: leftSidebarPercentage })}
216
- collapsible
217
- style={{
218
- display: "flex",
219
- flexDirection: "row",
220
- position: "relative",
221
- }}
222
- >
223
- {internalLayoutState?.leftSidebarCollapsed
224
- ? null
225
- : leftPanelContent}
226
- </Panel>
227
- <PanelResizeHandle
228
- style={{
229
- cursor: "col-resize",
230
- width: "1px",
231
- height: "100%",
232
- backgroundColor: cssVars.colors.divider,
233
- }}
234
- />
235
- </>
236
- )}
237
- <Panel
238
- id={CONTENT_AREA_ID}
239
- order={2}
240
- defaultSize={centerPanelPercentage}
241
- minSize={10}
242
- style={{
243
- display: "flex",
244
- flexDirection: "row",
245
- position: "relative",
246
- }}
193
+ {toolbar}
194
+ <div className="flex flex-row flex-1">
195
+ <PanelGroup
196
+ ref={panelGroupRef}
197
+ id={EDITOR_PANEL_GROUP_ID}
198
+ className="flex-1"
199
+ direction="horizontal"
200
+ autoSaveId={
201
+ autoSavePrefix
202
+ ? `${autoSavePrefix}--${EDITOR_PANEL_GROUP_ID}`
203
+ : undefined
204
+ }
247
205
  >
248
- {centerPanelContent}
249
- </Panel>
250
- {hasRightSidebar && (
251
- <>
252
- <PanelResizeHandle
253
- style={{
254
- cursor: "col-resize",
255
- width: "1px",
256
- height: "100%",
257
- backgroundColor: cssVars.colors.divider,
258
- }}
259
- />
260
- <Panel
261
- id={RIGHT_SIDEBAR_ID}
262
- order={3}
263
- ref={rightSidebarRef}
264
- minSize={rightSidebarMinPercentage ?? rightSidebarPercentage}
265
- defaultSize={rightSidebarPercentage}
266
- {...(!rightSidebarCanResize && {
267
- maxSize: rightSidebarPercentage,
268
- })}
269
- collapsible
270
- style={{
271
- display: "flex",
272
- flexDirection: "row",
273
- position: "relative",
274
- }}
275
- >
276
- {internalLayoutState?.rightSidebarCollapsed
277
- ? null
278
- : rightPanelContent}
279
- </Panel>
280
- </>
281
- )}
282
- </PanelGroup>
206
+ {left && (
207
+ <>
208
+ <Panel
209
+ id={LEFT_SIDEBAR_ID}
210
+ className="relative"
211
+ order={1}
212
+ ref={leftSidebarRef}
213
+ defaultSize={leftSidebarPercentage}
214
+ minSize={leftSidebarMinPercentage ?? leftSidebarPercentage}
215
+ {...(!leftResizable && { maxSize: leftSidebarPercentage })}
216
+ collapsible
217
+ >
218
+ {internalLayoutState?.leftSidebarCollapsed ? null : (
219
+ <PanelInner style={leftStyle} className={leftClassName}>
220
+ {left}
221
+ </PanelInner>
222
+ )}
223
+ </Panel>
224
+ <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
225
+ </>
226
+ )}
227
+ <Panel
228
+ id={CONTENT_AREA_ID}
229
+ order={2}
230
+ defaultSize={centerPanelPercentage}
231
+ minSize={10}
232
+ className="flex relative"
233
+ >
234
+ {children}
235
+ </Panel>
236
+ {right && (
237
+ <>
238
+ <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
239
+ <Panel
240
+ id={RIGHT_SIDEBAR_ID}
241
+ className="relative"
242
+ order={3}
243
+ ref={rightSidebarRef}
244
+ minSize={rightSidebarMinPercentage ?? rightSidebarPercentage}
245
+ defaultSize={rightSidebarPercentage}
246
+ {...(!rightResizable && {
247
+ maxSize: rightSidebarPercentage,
248
+ })}
249
+ collapsible
250
+ >
251
+ {internalLayoutState?.rightSidebarCollapsed ? null : (
252
+ <PanelInner style={rightStyle} className={rightClassName}>
253
+ {right}
254
+ </PanelInner>
255
+ )}
256
+ </Panel>
257
+ </>
258
+ )}
259
+ </PanelGroup>
260
+ </div>
283
261
  </div>
284
262
  );
285
263
  });
286
264
 
287
- export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
288
- props: Props,
289
- forwardedRef: React.ForwardedRef<IWorkspaceLayout>
290
- ) {
291
- return <WorkspaceLayoutWithTheme {...props} ref={forwardedRef} />;
265
+ const PanelInner = memo(function PanelInner({
266
+ children,
267
+ style,
268
+ className,
269
+ }: {
270
+ children: React.ReactNode;
271
+ style?: React.CSSProperties;
272
+ className?: string;
273
+ }) {
274
+ return (
275
+ <div
276
+ style={style}
277
+ className={cx(
278
+ "absolute inset-0 flex flex-col bg-sidebar-background",
279
+ className
280
+ )}
281
+ >
282
+ {children}
283
+ </div>
284
+ );
292
285
  });