@noya-app/noya-designsystem 0.1.76 → 0.1.78

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 (86) hide show
  1. package/.turbo/turbo-build.log +20 -12
  2. package/CHANGELOG.md +19 -0
  3. package/dist/chunk-D57E6H3M.mjs +36 -0
  4. package/dist/chunk-D57E6H3M.mjs.map +1 -0
  5. package/dist/emojis.d.mts +1 -0
  6. package/dist/emojis.d.ts +1 -0
  7. package/dist/emojis.js +31 -0
  8. package/dist/emojis.js.map +1 -0
  9. package/dist/emojis.mjs +8 -0
  10. package/dist/emojis.mjs.map +1 -0
  11. package/dist/index.css +1 -1
  12. package/dist/index.d.mts +192 -93
  13. package/dist/index.d.ts +192 -93
  14. package/dist/index.js +3355 -1763
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +3622 -2030
  17. package/dist/index.mjs.map +1 -1
  18. package/package.json +13 -9
  19. package/src/__tests__/__snapshots__/fuzzyScorer.test.ts.snap +1 -1
  20. package/src/components/Avatar.tsx +10 -10
  21. package/src/components/Banner.tsx +1 -1
  22. package/src/components/BaseToolbar.tsx +20 -6
  23. package/src/components/Button.tsx +2 -1
  24. package/src/components/Chip.tsx +1 -1
  25. package/src/components/ColorSwatchControl.tsx +22 -14
  26. package/src/components/CommandPalette.tsx +10 -6
  27. package/src/components/ContextMenu.tsx +249 -38
  28. package/src/components/Dialog.tsx +70 -67
  29. package/src/components/Drawer.tsx +56 -17
  30. package/src/components/DropdownMenu.tsx +307 -46
  31. package/src/components/EditableText.tsx +1 -1
  32. package/src/components/EmojiPicker.tsx +645 -0
  33. package/src/components/GridBackground.tsx +40 -0
  34. package/src/components/GridView.tsx +5 -1
  35. package/src/components/IVirtualizedList.tsx +21 -1
  36. package/src/components/InputField.tsx +2 -10
  37. package/src/components/InspectorContainer.tsx +4 -2
  38. package/src/components/Message.tsx +5 -16
  39. package/src/components/OverlayToolbar.tsx +97 -0
  40. package/src/components/Popover.tsx +73 -107
  41. package/src/components/Progress.tsx +18 -18
  42. package/src/components/ScrollArea.tsx +66 -31
  43. package/src/components/ScrollableSidebar.tsx +1 -1
  44. package/src/components/SegmentedControl.tsx +166 -38
  45. package/src/components/SelectMenu.tsx +193 -101
  46. package/src/components/Slider.tsx +40 -38
  47. package/src/components/StackNavigator.tsx +1 -0
  48. package/src/components/Switch.tsx +4 -4
  49. package/src/components/TextArea.tsx +1 -1
  50. package/src/components/Toast.tsx +99 -26
  51. package/src/components/Toolbar.tsx +133 -24
  52. package/src/components/Tooltip.tsx +18 -8
  53. package/src/components/UserPointer.tsx +5 -3
  54. package/src/components/Virtualized.tsx +193 -14
  55. package/src/components/VisuallyHidden.tsx +20 -0
  56. package/src/components/__tests__/Virtualized.math.test.ts +426 -1
  57. package/src/components/__tests__/Virtualized.test.tsx +129 -1
  58. package/src/components/ai-assistant/AIAssistantLayout.tsx +11 -6
  59. package/src/components/internal/Menu.tsx +4 -0
  60. package/src/components/listView/ListViewEditableRowTitle.tsx +1 -1
  61. package/src/components/listView/ListViewRoot.tsx +5 -1
  62. package/src/components/resizablePanels/Panel.tsx +94 -0
  63. package/src/components/resizablePanels/PanelGroup.tsx +498 -0
  64. package/src/components/resizablePanels/PanelGroupContext.tsx +14 -0
  65. package/src/components/resizablePanels/PanelResizeHandle.tsx +61 -0
  66. package/src/components/resizablePanels/index.ts +7 -0
  67. package/src/components/resizablePanels/types.ts +65 -0
  68. package/src/components/workspace/DrawerWorkspaceLayout.tsx +22 -7
  69. package/src/components/workspace/PanelWorkspaceLayout.tsx +30 -84
  70. package/src/components/workspace/WorkspaceLayout.tsx +82 -76
  71. package/src/components/workspace/types.ts +6 -4
  72. package/src/contexts/DialogContext.tsx +15 -24
  73. package/src/emojis.ts +1 -0
  74. package/src/hooks/useTriggerToggle.ts +95 -0
  75. package/src/index.css +2 -0
  76. package/src/index.tsx +3 -2
  77. package/src/theme/proseTheme.ts +22 -0
  78. package/src/utils/mergeProps.ts +57 -0
  79. package/src/utils/skinTone.ts +90 -0
  80. package/tailwind.config.ts +6 -1
  81. package/tsup.config.ts +1 -1
  82. package/src/__tests__/workspaceLayout.test.ts +0 -281
  83. package/src/components/ScrollArea2.tsx +0 -76
  84. package/src/components/internal/MenuViewport.tsx +0 -178
  85. package/src/components/internal/SelectItem.tsx +0 -138
  86. package/src/components/workspace/panelStorage.ts +0 -216
@@ -0,0 +1,65 @@
1
+ import { ReactNode, RefObject } from "react";
2
+
3
+ export interface PanelGroupProps {
4
+ id?: string;
5
+ className?: string;
6
+ direction: "horizontal";
7
+ autoSaveId?: string;
8
+ onLayout?: (sizes: number[]) => void;
9
+ children: ReactNode;
10
+ ref?: RefObject<ImperativePanelGroupHandle | null>;
11
+ }
12
+
13
+ export interface PanelProps {
14
+ id?: string;
15
+ order: number;
16
+ className?: string;
17
+ defaultSize?: number;
18
+ minSize?: number;
19
+ maxSize?: number;
20
+ collapsible?: boolean;
21
+ defaultCollapsed?: boolean;
22
+ children?: ReactNode;
23
+ }
24
+
25
+ export interface ImperativePanelHandle {
26
+ expand: () => void;
27
+ collapse: () => void;
28
+ isExpanded: () => boolean;
29
+ getSize: () => number;
30
+ }
31
+
32
+ export interface ImperativePanelGroupHandle {
33
+ getLayout: () => number[];
34
+ setLayout: (sizes: number[]) => void;
35
+ }
36
+
37
+ export interface PanelResizeHandleProps {
38
+ className?: string;
39
+ disabled?: boolean;
40
+ /** The index of this handle (0 = between panels 0 and 1, 1 = between panels 1 and 2, etc.) */
41
+ index: number;
42
+ }
43
+
44
+ export interface PanelRegistration {
45
+ id: string;
46
+ order: number;
47
+ defaultSize?: number;
48
+ minSize?: number;
49
+ maxSize?: number;
50
+ collapsible?: boolean;
51
+ defaultCollapsed?: boolean;
52
+ }
53
+
54
+ export interface PanelGroupContextValue {
55
+ registerPanel: (panel: PanelRegistration) => void;
56
+ unregisterPanel: (id: string) => void;
57
+ getPanelSize: (id: string) => number;
58
+ setPanelSize: (id: string, size: number) => void;
59
+ getPanelIndex: (id: string) => number;
60
+ expandPanel: (id: string) => void;
61
+ collapsePanel: (id: string) => void;
62
+ isPanelExpanded: (id: string) => boolean;
63
+ startResize: (handleIndex: number, startX: number) => void;
64
+ containerWidth: number;
65
+ }
@@ -2,13 +2,13 @@
2
2
 
3
3
  import { memoGeneric } from "@noya-app/react-utils";
4
4
  import React, { useMemo, useRef, useState } from "react";
5
+ import { Button } from "../Button";
5
6
  import { DividerVertical } from "../Divider";
6
7
  import { Drawer } from "../Drawer";
7
8
  import { isSelectableMenuItem, MenuItem } from "../internal/Menu";
8
9
  import { EDITOR_PANEL_GROUP_ID, RIGHT_SIDEBAR_ID } from "./constants";
9
10
  import { LayoutProps, PanelLayoutState, SidebarRef } from "./types";
10
11
  import { VerticalTabMenu } from "./VerticalTabMenu";
11
- import { Button } from "../Button";
12
12
 
13
13
  export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
14
14
  LeftTab extends string = string,
@@ -138,16 +138,29 @@ export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
138
138
  }}
139
139
  icon={allSelectableTabItems[0].icon}
140
140
  tooltip={
141
- allSelectableTabItems[0].tooltip ?? allSelectableTabItems[0].title
141
+ allSelectableTabItems[0].tooltip ??
142
+ allSelectableTabItems[0].title
142
143
  }
143
144
  active={(() => {
144
- const value = allSelectableTabItems[0].value as LeftTab | RightTab;
145
- const isLeftItem = leftSelectableTabItems.some((i) => i.value === value);
146
- const isRightItem = rightSelectableTabItems.some((i) => i.value === value);
147
- return isLeftItem ? !leftSidebarCollapsed : isRightItem ? !rightSidebarCollapsed : false;
145
+ const value = allSelectableTabItems[0].value as
146
+ | LeftTab
147
+ | RightTab;
148
+ const isLeftItem = leftSelectableTabItems.some(
149
+ (i) => i.value === value
150
+ );
151
+ const isRightItem = rightSelectableTabItems.some(
152
+ (i) => i.value === value
153
+ );
154
+ return isLeftItem
155
+ ? !leftSidebarCollapsed
156
+ : isRightItem
157
+ ? !rightSidebarCollapsed
158
+ : false;
148
159
  })()}
149
160
  onClick={() => {
150
- const value = allSelectableTabItems[0].value as LeftTab | RightTab;
161
+ const value = allSelectableTabItems[0].value as
162
+ | LeftTab
163
+ | RightTab;
151
164
  handleSelectTab(value);
152
165
  }}
153
166
  />
@@ -159,6 +172,7 @@ export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
159
172
 
160
173
  {leftPanel && (
161
174
  <Drawer
175
+ modal={false}
162
176
  ref={leftSidebarRef}
163
177
  className="n-flex-1"
164
178
  style={
@@ -185,6 +199,7 @@ export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
185
199
  {rightPanel && (
186
200
  <Drawer
187
201
  id={RIGHT_SIDEBAR_ID}
202
+ modal={false}
188
203
  ref={rightSidebarRef}
189
204
  className="n-flex-1"
190
205
  style={
@@ -1,18 +1,14 @@
1
1
  "use client";
2
2
 
3
- import {
4
- clientStorage,
5
- memoGeneric,
6
- usePersistentStateObject,
7
- } from "@noya-app/react-utils";
8
- import React, { useCallback, useMemo, useRef } from "react";
3
+ import { memoGeneric } from "@noya-app/react-utils";
4
+ import React, { useCallback, useMemo, useRef, useState } from "react";
9
5
  import {
10
6
  ImperativePanelGroupHandle,
11
7
  ImperativePanelHandle,
12
8
  Panel,
13
9
  PanelGroup,
14
10
  PanelResizeHandle,
15
- } from "react-resizable-panels";
11
+ } from "../resizablePanels";
16
12
  import { DividerVertical } from "../Divider";
17
13
  import {
18
14
  CONTENT_AREA_ID,
@@ -20,17 +16,7 @@ import {
20
16
  LEFT_SIDEBAR_ID,
21
17
  RIGHT_SIDEBAR_ID,
22
18
  } from "./constants";
23
- import {
24
- getInitialLayout,
25
- getLayoutCollapsedState,
26
- getLayoutIds,
27
- getPropertyKey,
28
- getStorageKey,
29
- panelStorage,
30
- setInitialLayout,
31
- toPixelSize,
32
- } from "./panelStorage";
33
- import { LayoutProps, WorkspaceLayoutState } from "./types";
19
+ import { LayoutProps } from "./types";
34
20
  import { VerticalTabMenu } from "./VerticalTabMenu";
35
21
 
36
22
  export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
@@ -42,7 +28,6 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
42
28
  centerPanel,
43
29
  leftSidebarOptions,
44
30
  rightSidebarOptions,
45
- centerPanelPercentage,
46
31
  autoSavePrefix,
47
32
  leftSidebarRef,
48
33
  rightSidebarRef,
@@ -56,56 +41,35 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
56
41
  }: LayoutProps<LeftTab, RightTab>) {
57
42
  const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
58
43
 
59
- const hasLeftPanel = !!leftPanel;
60
- const hasRightPanel = !!rightPanel;
61
- const hasCenterPanel = !!centerPanel;
62
-
63
44
  const autoSaveId = useMemo(() => {
64
45
  return autoSavePrefix
65
- ? `${autoSavePrefix}--v2--${EDITOR_PANEL_GROUP_ID}`
46
+ ? `${autoSavePrefix}--v3--${EDITOR_PANEL_GROUP_ID}`
66
47
  : Math.random().toString(36).substring(2, 15);
67
48
  }, [autoSavePrefix]);
68
49
 
69
- const layoutIds = getLayoutIds({
70
- hasLeftPanel,
71
- hasRightPanel,
72
- hasCenterPanel,
73
- });
74
- const storageKey = getStorageKey(autoSaveId);
75
- const propertyKey = getPropertyKey(layoutIds);
76
-
77
- setInitialLayout({
78
- storageKey,
79
- propertyKey,
80
- calculateLayout: () => {
81
- return getInitialLayout({
82
- layoutIds,
83
- leftSidebarOptions,
84
- rightSidebarOptions,
85
- centerPanelPercentage,
86
- hasLeftPanel,
87
- hasRightPanel,
88
- hasCenterPanel,
89
- });
90
- },
91
- });
92
-
93
- const [data, setData] = usePersistentStateObject<
94
- WorkspaceLayoutState,
95
- string
96
- >(clientStorage, storageKey, {});
50
+ // Track collapsed state based on layout changes
51
+ const [leftSidebarCollapsed, setLeftSidebarCollapsed] = useState(
52
+ leftSidebarOptions.defaultCollapsed ?? false
53
+ );
54
+ const [rightSidebarCollapsed, setRightSidebarCollapsed] = useState(
55
+ rightSidebarOptions.defaultCollapsed ?? false
56
+ );
97
57
 
98
- const layoutGroup = data?.[propertyKey];
58
+ const handleLayoutChange = useCallback(
59
+ (sizes: number[]) => {
60
+ // Update collapsed state based on sizes
61
+ const leftIndex = leftPanel ? 0 : -1;
62
+ const rightIndex = rightPanel ? (leftPanel ? 2 : 1) : -1;
99
63
 
100
- const { leftSidebarCollapsed, rightSidebarCollapsed } = useMemo(() => {
101
- return getLayoutCollapsedState({
102
- layoutGroup,
103
- propertyKey,
104
- layoutIds,
105
- hasLeftPanel,
106
- hasRightPanel,
107
- });
108
- }, [layoutGroup, propertyKey, layoutIds, hasLeftPanel, hasRightPanel]);
64
+ if (leftIndex >= 0) {
65
+ setLeftSidebarCollapsed(sizes[leftIndex] === 0);
66
+ }
67
+ if (rightIndex >= 0) {
68
+ setRightSidebarCollapsed(sizes[rightIndex] === 0);
69
+ }
70
+ },
71
+ [leftPanel, rightPanel]
72
+ );
109
73
 
110
74
  const handleLeftTabChange = useCallback(
111
75
  (value: LeftTab) => {
@@ -143,23 +107,6 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
143
107
  [onChangeRightTab, rightSidebarRef, rightTabValue]
144
108
  );
145
109
 
146
- const handleLayoutChange = useCallback(
147
- (layout: number[]) => {
148
- setData((prev) => {
149
- const newData = {
150
- ...prev,
151
- [propertyKey]: {
152
- layout: layout.map((size) => toPixelSize(size)),
153
- expandToSizes: prev?.[propertyKey]?.expandToSizes ?? {},
154
- },
155
- };
156
-
157
- return newData;
158
- });
159
- },
160
- [setData, propertyKey]
161
- );
162
-
163
110
  const showLeftTabs =
164
111
  !!leftSidebarOptions.showTabs &&
165
112
  !!leftTabItems &&
@@ -173,7 +120,6 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
173
120
  id={EDITOR_PANEL_GROUP_ID}
174
121
  className="n-flex-1"
175
122
  direction="horizontal"
176
- storage={panelStorage}
177
123
  autoSaveId={autoSaveId}
178
124
  onLayout={handleLayoutChange}
179
125
  >
@@ -205,24 +151,23 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
205
151
  : undefined)
206
152
  }
207
153
  collapsible
154
+ defaultCollapsed={leftSidebarOptions.defaultCollapsed}
208
155
  >
209
156
  {leftSidebarCollapsed ? null : leftPanel}
210
157
  </Panel>
211
- <PanelResizeHandle className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
158
+ <PanelResizeHandle index={0} className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
212
159
  </>
213
160
  )}
214
161
  <Panel
215
162
  id={CONTENT_AREA_ID}
216
163
  order={2}
217
- defaultSize={centerPanelPercentage}
218
- minSize={10}
219
164
  className="n-flex n-relative"
220
165
  >
221
166
  {centerPanel}
222
167
  </Panel>
223
168
  {rightPanel && (
224
169
  <>
225
- <PanelResizeHandle className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
170
+ <PanelResizeHandle index={1} className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
226
171
  <Panel
227
172
  id={RIGHT_SIDEBAR_ID}
228
173
  className="n-relative"
@@ -237,6 +182,7 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
237
182
  : undefined)
238
183
  }
239
184
  collapsible
185
+ defaultCollapsed={rightSidebarOptions.defaultCollapsed}
240
186
  >
241
187
  {rightSidebarCollapsed ? null : rightPanel}
242
188
  </Panel>
@@ -16,13 +16,14 @@ import React, {
16
16
  } from "react";
17
17
  import { cx } from "../../utils/classNames";
18
18
  import { MenuItem } from "../internal/Menu";
19
+ import { OverlayLayout, OverlayToolbar } from "../OverlayToolbar";
19
20
  import { DrawerWorkspaceLayout } from "./DrawerWorkspaceLayout";
20
21
  import { PanelWorkspaceLayout } from "./PanelWorkspaceLayout";
21
22
  import { renderPanelChildren } from "./renderPanelChildren";
22
23
  import {
23
24
  LayoutProps,
24
- PercentageSidebarOptions,
25
25
  RenderPanel,
26
+ SidebarOptions,
26
27
  SidebarRef,
27
28
  } from "./types";
28
29
  import { WorkspaceSideProvider } from "./WorkspaceSideContext";
@@ -31,6 +32,8 @@ export type SideType = "auto" | "panel" | "drawer";
31
32
 
32
33
  export type DetectSizeType = "container" | "window";
33
34
 
35
+ export type ToolbarVariant = "default" | "overlay";
36
+
34
37
  export interface WorkspaceLayoutProps<
35
38
  LeftTab extends string,
36
39
  RightTab extends string,
@@ -54,6 +57,24 @@ export interface WorkspaceLayoutProps<
54
57
  right?: RenderPanel<RightTab>;
55
58
  rightOptions?: SideOptions;
56
59
  toolbar?: React.ReactNode;
60
+ /**
61
+ * Toolbar variant - "default" renders above content, "overlay" renders floating panels
62
+ * @default "default"
63
+ */
64
+ toolbarVariant?: ToolbarVariant;
65
+ /**
66
+ * Content for the left/bottom-center overlay panel (when toolbarVariant is "overlay")
67
+ */
68
+ overlayToolbarLeft?: React.ReactNode;
69
+ /**
70
+ * Content for the right overlay panel (when toolbarVariant is "overlay")
71
+ */
72
+ overlayToolbarRight?: React.ReactNode;
73
+ /**
74
+ * Layout configuration for overlay toolbar
75
+ * @default "bottomCenterTopRight"
76
+ */
77
+ overlayLayout?: OverlayLayout;
57
78
  sideType?: SideType;
58
79
  sideTypeBreakpoint?: number;
59
80
  detectSize?: DetectSizeType;
@@ -125,6 +146,10 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
125
146
  className,
126
147
  style,
127
148
  toolbar,
149
+ toolbarVariant = "default",
150
+ overlayToolbarLeft,
151
+ overlayToolbarRight,
152
+ overlayLayout,
128
153
  children,
129
154
  sideType = "auto",
130
155
  sideTypeBreakpoint = 800,
@@ -169,46 +194,22 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
169
194
  ? containerSize
170
195
  : windowSize;
171
196
 
172
- function getPercentage(size: number | string) {
173
- return typeof size === "string"
174
- ? parseFloat(size)
175
- : (size / parentSize.width) * 100;
197
+ // Convert size to pixels (handles both number and percentage string)
198
+ function toPixels(size: number | string | undefined): number | undefined {
199
+ if (size === undefined) return undefined;
200
+ if (typeof size === "number") return size;
201
+ // Parse percentage string like "20%"
202
+ const percentage = parseFloat(size);
203
+ return Math.round((percentage / 100) * parentSize.width);
176
204
  }
177
205
 
178
- function clampPercentage(
179
- value: number,
180
- min: number | undefined,
181
- max: number | undefined
182
- ) {
183
- let result = value;
184
- if (min !== undefined) {
185
- result = Math.max(result, min);
186
- }
187
- if (max !== undefined) {
188
- result = Math.min(result, max);
189
- }
190
- return result;
191
- }
206
+ const leftSidebarMinPixels = toPixels(leftMinSize);
207
+ const leftSidebarMaxPixels = toPixels(leftMaxSize);
208
+ const leftSidebarInitialPixels = toPixels(leftInitialSize) ?? 280;
192
209
 
193
- const leftSidebarMinPercentage =
194
- leftMinSize !== undefined ? getPercentage(leftMinSize) : undefined;
195
- const rightSidebarMinPercentage =
196
- rightMinSize !== undefined ? getPercentage(rightMinSize) : undefined;
197
- const leftSidebarMaxPercentage =
198
- leftMaxSize !== undefined ? getPercentage(leftMaxSize) : undefined;
199
- const rightSidebarMaxPercentage =
200
- rightMaxSize !== undefined ? getPercentage(rightMaxSize) : undefined;
201
-
202
- const leftSidebarPercentage = clampPercentage(
203
- getPercentage(leftInitialSize),
204
- leftSidebarMinPercentage,
205
- leftSidebarMaxPercentage
206
- );
207
- const rightSidebarPercentage = clampPercentage(
208
- getPercentage(rightInitialSize),
209
- rightSidebarMinPercentage,
210
- rightSidebarMaxPercentage
211
- );
210
+ const rightSidebarMinPixels = toPixels(rightMinSize);
211
+ const rightSidebarMaxPixels = toPixels(rightMaxSize);
212
+ const rightSidebarInitialPixels = toPixels(rightInitialSize) ?? 280;
212
213
 
213
214
  const leftSidebarRef = useRef<SidebarRef>(null);
214
215
  const rightSidebarRef = useRef<SidebarRef>(null);
@@ -288,11 +289,6 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
288
289
  },
289
290
  });
290
291
 
291
- const centerPanelPercentage =
292
- 100 -
293
- (left ? leftSidebarPercentage : 0) -
294
- (right ? rightSidebarPercentage : 0);
295
-
296
292
  const isDrawerActive =
297
293
  sideType === "drawer" ||
298
294
  (sideType === "auto" && parentSize.width <= sideTypeBreakpoint);
@@ -365,38 +361,38 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
365
361
  <PanelInner className="n-bg-canvas-background">{children}</PanelInner>
366
362
  );
367
363
 
368
- const leftSidebarOptions: PercentageSidebarOptions = useMemo(
364
+ const leftSidebarOptions: SidebarOptions = useMemo(
369
365
  () => ({
370
- minSize: leftSidebarMinPercentage,
371
- maxSize: leftSidebarMaxPercentage,
372
- initialSize: leftSidebarPercentage,
366
+ minSize: leftSidebarMinPixels,
367
+ maxSize: leftSidebarMaxPixels,
368
+ initialSize: leftSidebarInitialPixels,
373
369
  resizable: leftResizable,
374
370
  defaultCollapsed: leftDefaultCollapsed,
375
371
  showTabs: leftShowTabs,
376
372
  }),
377
373
  [
378
- leftSidebarMinPercentage,
379
- leftSidebarMaxPercentage,
380
- leftSidebarPercentage,
374
+ leftSidebarMinPixels,
375
+ leftSidebarMaxPixels,
376
+ leftSidebarInitialPixels,
381
377
  leftResizable,
382
378
  leftDefaultCollapsed,
383
379
  leftShowTabs,
384
380
  ]
385
381
  );
386
382
 
387
- const rightSidebarOptions: PercentageSidebarOptions = useMemo(
383
+ const rightSidebarOptions: SidebarOptions = useMemo(
388
384
  () => ({
389
- minSize: rightSidebarMinPercentage,
390
- maxSize: rightSidebarMaxPercentage,
391
- initialSize: rightSidebarPercentage,
385
+ minSize: rightSidebarMinPixels,
386
+ maxSize: rightSidebarMaxPixels,
387
+ initialSize: rightSidebarInitialPixels,
392
388
  resizable: rightResizable,
393
389
  defaultCollapsed: rightDefaultCollapsed,
394
390
  showTabs: rightShowTabs,
395
391
  }),
396
392
  [
397
- rightSidebarMinPercentage,
398
- rightSidebarMaxPercentage,
399
- rightSidebarPercentage,
393
+ rightSidebarMinPixels,
394
+ rightSidebarMaxPixels,
395
+ rightSidebarInitialPixels,
400
396
  rightResizable,
401
397
  rightDefaultCollapsed,
402
398
  rightShowTabs,
@@ -422,6 +418,8 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
422
418
  const readyToRender =
423
419
  detectSize === "window" || (containerSize && containerSize.width > 0);
424
420
 
421
+ const isOverlay = toolbarVariant === "overlay";
422
+
425
423
  return (
426
424
  <div
427
425
  ref={containerRef}
@@ -433,27 +431,35 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
433
431
  style={style}
434
432
  data-theme={theme}
435
433
  >
436
- {toolbar}
434
+ {!isOverlay && toolbar}
437
435
  <div className="n-flex n-flex-row n-flex-1 n-relative">
438
436
  {readyToRender && (
439
- <LayoutComponent
440
- leftPanel={leftPanel}
441
- rightPanel={rightPanel}
442
- centerPanel={centerPanel}
443
- leftTabItems={leftTabItems}
444
- leftTabValue={leftTabValue}
445
- onChangeLeftTab={setLeftTabValue}
446
- rightTabItems={rightTabItems}
447
- rightTabValue={rightTabValue}
448
- onChangeRightTab={setRightTabValue}
449
- leftSidebarOptions={leftSidebarOptions}
450
- rightSidebarOptions={rightSidebarOptions}
451
- centerPanelPercentage={centerPanelPercentage}
452
- autoSavePrefix={autoSavePrefix}
453
- leftSidebarRef={leftSidebarRef}
454
- rightSidebarRef={rightSidebarRef}
455
- compactDrawerMenu={compactDrawerMenu}
456
- />
437
+ <>
438
+ <LayoutComponent
439
+ leftPanel={leftPanel}
440
+ rightPanel={rightPanel}
441
+ centerPanel={centerPanel}
442
+ leftTabItems={leftTabItems}
443
+ leftTabValue={leftTabValue}
444
+ onChangeLeftTab={setLeftTabValue}
445
+ rightTabItems={rightTabItems}
446
+ rightTabValue={rightTabValue}
447
+ onChangeRightTab={setRightTabValue}
448
+ leftSidebarOptions={leftSidebarOptions}
449
+ rightSidebarOptions={rightSidebarOptions}
450
+ autoSavePrefix={autoSavePrefix}
451
+ leftSidebarRef={leftSidebarRef}
452
+ rightSidebarRef={rightSidebarRef}
453
+ compactDrawerMenu={compactDrawerMenu}
454
+ />
455
+ {isOverlay && (
456
+ <OverlayToolbar
457
+ left={overlayToolbarLeft}
458
+ right={overlayToolbarRight}
459
+ overlayLayout={overlayLayout}
460
+ />
461
+ )}
462
+ </>
457
463
  )}
458
464
  </div>
459
465
  </div>
@@ -7,7 +7,10 @@ export type SidebarRef = {
7
7
  isExpanded: () => boolean;
8
8
  };
9
9
 
10
- export type PercentageSidebarOptions = {
10
+ /**
11
+ * Sidebar options with pixel-based sizing.
12
+ */
13
+ export type SidebarOptions = {
11
14
  minSize?: number;
12
15
  maxSize?: number;
13
16
  initialSize?: number;
@@ -45,9 +48,8 @@ export type LayoutProps<
45
48
  rightTabValue?: RightTab;
46
49
  onChangeRightTab?: (value: RightTab) => void;
47
50
  centerPanel: React.ReactNode;
48
- leftSidebarOptions: PercentageSidebarOptions;
49
- rightSidebarOptions: PercentageSidebarOptions;
50
- centerPanelPercentage: number;
51
+ leftSidebarOptions: SidebarOptions;
52
+ rightSidebarOptions: SidebarOptions;
51
53
  autoSavePrefix?: string;
52
54
  leftSidebarRef: React.RefObject<SidebarRef | null>;
53
55
  rightSidebarRef: React.RefObject<SidebarRef | null>;
@@ -231,6 +231,21 @@ export const DialogProvider = function DialogProvider({
231
231
  const confirmButtonRef = useRef<HTMLButtonElement>(null);
232
232
  const dialogRef = useRef<IDialog>(null);
233
233
 
234
+ // Handle auto-focus when dialog opens
235
+ React.useEffect(() => {
236
+ if (!contents) return;
237
+
238
+ // Use requestAnimationFrame to ensure the dialog is rendered
239
+ requestAnimationFrame(() => {
240
+ if (contents.type === "input") {
241
+ inputRef.current?.focus();
242
+ inputRef.current?.setSelectionRange(0, inputRef.current.value.length);
243
+ } else if (contents.type === "confirmation") {
244
+ confirmButtonRef.current?.focus();
245
+ }
246
+ });
247
+ }, [contents]);
248
+
234
249
  const containsElement = useCallback((element: HTMLElement) => {
235
250
  if (!dialogRef.current) return false;
236
251
 
@@ -267,30 +282,6 @@ export const DialogProvider = function DialogProvider({
267
282
  },
268
283
  [close]
269
284
  )}
270
- onOpenAutoFocus={useCallback(
271
- (event: Event) => {
272
- if (!contents) return;
273
-
274
- if (contents.type === "input") {
275
- event.stopPropagation();
276
- event.preventDefault();
277
- inputRef.current?.focus();
278
- inputRef.current?.setSelectionRange(
279
- 0,
280
- inputRef.current.value.length
281
- );
282
- return;
283
- }
284
-
285
- if (contents.type === "confirmation") {
286
- event.stopPropagation();
287
- event.preventDefault();
288
- confirmButtonRef.current?.focus();
289
- return;
290
- }
291
- },
292
- [contents]
293
- )}
294
285
  >
295
286
  {contents?.type === "confirmation" ? (
296
287
  <div className="n-flex n-flex-1 n-flex-row n-items-center">
package/src/emojis.ts ADDED
@@ -0,0 +1 @@
1
+ export { gemoji as emojis } from "gemoji";