@noya-app/noya-designsystem 0.1.63 → 0.1.65

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 (143) hide show
  1. package/.turbo/turbo-build.log +13 -10
  2. package/CHANGELOG.md +25 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +648 -333
  5. package/dist/index.d.ts +648 -333
  6. package/dist/index.js +13813 -9157
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +13949 -9269
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +10 -22
  11. package/src/__tests__/validateDropIndicator.test.ts +26 -41
  12. package/src/__tests__/workspaceLayout.test.ts +281 -0
  13. package/src/components/ActionMenu.tsx +2 -0
  14. package/src/components/ActivityIndicator.tsx +13 -6
  15. package/src/components/ActivityLog.tsx +197 -0
  16. package/src/components/AnimatePresence.tsx +43 -26
  17. package/src/components/Avatar.tsx +45 -26
  18. package/src/components/Banner.tsx +57 -11
  19. package/src/components/BaseToolbar.tsx +67 -34
  20. package/src/components/Breadcrumbs.tsx +4 -2
  21. package/src/components/Button.tsx +28 -23
  22. package/src/components/Checkbox.tsx +6 -35
  23. package/src/components/Chip.tsx +47 -33
  24. package/src/components/Collection.tsx +20 -12
  25. package/src/components/ColorSwatch.tsx +42 -22
  26. package/src/components/ColorSwatchControl.tsx +7 -5
  27. package/src/components/Combobox.tsx +8 -6
  28. package/src/components/ComboboxMenu.tsx +6 -5
  29. package/src/components/CommandPalette.tsx +3 -1
  30. package/src/components/ContextMenu.tsx +3 -1
  31. package/src/components/Dialog.tsx +9 -13
  32. package/src/components/DimensionInput.tsx +2 -0
  33. package/src/components/Divider.tsx +18 -14
  34. package/src/components/DraggableMenuButton.tsx +11 -5
  35. package/src/components/Drawer.tsx +14 -6
  36. package/src/components/DropdownMenu.tsx +4 -2
  37. package/src/components/EditableText.tsx +4 -2
  38. package/src/components/Fade.tsx +13 -13
  39. package/src/components/FileUploadIndicator.tsx +108 -0
  40. package/src/components/FloatingWindow.tsx +4 -2
  41. package/src/components/Grid.tsx +58 -42
  42. package/src/components/GridView.tsx +65 -36
  43. package/src/components/IVirtualizedList.tsx +5 -0
  44. package/src/components/IconButton.tsx +2 -0
  45. package/src/components/Icons.tsx +24 -4
  46. package/src/components/InputField.tsx +21 -19
  47. package/src/components/InspectorContainer.tsx +2 -2
  48. package/src/components/InspectorPrimitives.tsx +15 -9
  49. package/src/components/Label.tsx +4 -3
  50. package/src/components/LabeledElementView.tsx +9 -5
  51. package/src/components/LabeledField.tsx +8 -6
  52. package/src/components/List.tsx +112 -46
  53. package/src/components/ListMenu.tsx +91 -0
  54. package/src/components/ListNavigator.tsx +106 -0
  55. package/src/components/ListView.tsx +22 -1147
  56. package/src/components/MediaThumbnail.tsx +84 -14
  57. package/src/components/Message.tsx +11 -12
  58. package/src/components/Navigator.tsx +461 -0
  59. package/src/components/NoyaLogo.tsx +1 -1
  60. package/src/components/Popover.tsx +12 -6
  61. package/src/components/Progress.tsx +31 -8
  62. package/src/components/ResizableContainer.tsx +187 -0
  63. package/src/components/RingProgress.tsx +128 -0
  64. package/src/components/ScrollArea.tsx +7 -5
  65. package/src/components/ScrollableSidebar.tsx +10 -0
  66. package/src/components/SearchCompletionMenu.tsx +5 -3
  67. package/src/components/Section.tsx +109 -57
  68. package/src/components/SegmentedControl.tsx +51 -25
  69. package/src/components/SelectMenu.tsx +16 -21
  70. package/src/components/SelectionToolbar.tsx +7 -4
  71. package/src/components/Slider.tsx +12 -10
  72. package/src/components/Spacer.tsx +2 -2
  73. package/src/components/StackNavigator.tsx +378 -0
  74. package/src/components/Stepper.tsx +88 -0
  75. package/src/components/Switch.tsx +7 -5
  76. package/src/components/Tabs.tsx +6 -4
  77. package/src/components/Text.tsx +29 -18
  78. package/src/components/TextArea.tsx +5 -3
  79. package/src/components/Toast.tsx +5 -5
  80. package/src/components/Toolbar.tsx +57 -10
  81. package/src/components/ToolbarDrawer.tsx +29 -0
  82. package/src/components/Tooltip.tsx +2 -2
  83. package/src/components/TreeView.tsx +13 -4
  84. package/src/components/UserPointer.tsx +6 -4
  85. package/src/components/ai-assistant/AIAssistantLayout.tsx +10 -8
  86. package/src/components/blocks/ImageBlockComponent.tsx +162 -0
  87. package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +6 -4
  88. package/src/components/file-explorer/FileExplorerLayout.tsx +22 -8
  89. package/src/components/internal/Checkmark.tsx +24 -0
  90. package/src/components/internal/Menu.tsx +24 -19
  91. package/src/components/internal/MenuViewport.tsx +15 -6
  92. package/src/components/internal/SelectItem.tsx +7 -26
  93. package/src/components/internal/TextInput.tsx +7 -1
  94. package/src/components/listView/ListViewContexts.tsx +68 -0
  95. package/src/components/listView/ListViewEditableRowTitle.tsx +55 -0
  96. package/src/components/listView/ListViewRoot.tsx +521 -0
  97. package/src/components/listView/ListViewRow.tsx +475 -0
  98. package/src/components/listView/ListViewRowTitle.tsx +21 -0
  99. package/src/components/listView/types.ts +11 -0
  100. package/src/components/pipeline/PipelineResultLayout.tsx +6 -6
  101. package/src/components/sorting/DragRegistration.tsx +10 -5
  102. package/src/components/sorting/SharedDragProvider.tsx +134 -27
  103. package/src/components/sorting/Sortable.tsx +90 -27
  104. package/src/components/sorting/createSharedDrag.tsx +7 -6
  105. package/src/components/sorting/sorting.ts +6 -9
  106. package/src/components/workspace/DrawerWorkspaceLayout.tsx +110 -29
  107. package/src/components/workspace/PanelWorkspaceLayout.tsx +148 -99
  108. package/src/components/workspace/VerticalTabMenu.tsx +46 -0
  109. package/src/components/workspace/WorkspaceLayout.tsx +76 -63
  110. package/src/components/workspace/constants.ts +4 -0
  111. package/src/components/workspace/panelStorage.ts +216 -0
  112. package/src/components/workspace/types.ts +11 -4
  113. package/src/contexts/DesignSystemConfiguration.tsx +12 -5
  114. package/src/contexts/DialogContext.tsx +19 -5
  115. package/src/contexts/FloatingWindowContext.tsx +2 -0
  116. package/src/contexts/GlobalInputBlurContext.tsx +2 -0
  117. package/src/contexts/ImageDataContext.tsx +2 -0
  118. package/src/contexts/LinkComponentContext.tsx +17 -0
  119. package/src/contexts/OpenPortalsContext.tsx +2 -0
  120. package/src/contexts/PortalScopeContext.tsx +2 -0
  121. package/src/hooks/mergeEventHandlers.ts +1 -1
  122. package/src/hooks/useHover.ts +30 -17
  123. package/src/hooks/useIndent.ts +5 -8
  124. package/src/hooks/useLabel.ts +2 -0
  125. package/src/hooks/useObjectURL.ts +5 -3
  126. package/src/hooks/usePlatform.ts +5 -3
  127. package/src/hooks/useTheme.ts +3 -1
  128. package/src/index.css +43 -10
  129. package/src/index.tsx +15 -7
  130. package/src/utils/classNames.ts +56 -9
  131. package/src/utils/combobox.ts +2 -0
  132. package/src/utils/editableBlockStyles.ts +2 -2
  133. package/src/utils/formatByteSize.ts +9 -0
  134. package/src/utils/inputs.ts +8 -6
  135. package/src/utils/sketchColor.ts +0 -34
  136. package/src/utils/withSeparatorElements.ts +1 -1
  137. package/tailwind.config.ts +1 -0
  138. package/src/components/FillInputField.tsx +0 -37
  139. package/src/components/FillPreviewBackground.tsx +0 -132
  140. package/src/components/GradientPicker.tsx +0 -88
  141. package/src/hooks/usePreservePanelSize.tsx +0 -183
  142. package/src/mediaQuery.ts +0 -13
  143. package/src/utils/getGradientBackground.tsx +0 -31
@@ -1,12 +1,13 @@
1
+ "use client";
2
+
1
3
  import { memoGeneric } from "@noya-app/react-utils";
2
- import React, { useLayoutEffect, useRef, useState } from "react";
3
- import {
4
- EDITOR_PANEL_GROUP_ID,
5
- LEFT_SIDEBAR_ID,
6
- RIGHT_SIDEBAR_ID,
7
- } from "../../hooks/usePreservePanelSize";
4
+ import React, { useMemo, useRef, useState } from "react";
5
+ import { DividerVertical } from "../Divider";
8
6
  import { Drawer } from "../Drawer";
9
- import { LayoutProps } from "./types";
7
+ import { isSelectableMenuItem, MenuItem } from "../internal/Menu";
8
+ import { EDITOR_PANEL_GROUP_ID, RIGHT_SIDEBAR_ID } from "./constants";
9
+ import { LayoutProps, PanelLayoutState } from "./types";
10
+ import { VerticalTabMenu } from "./VerticalTabMenu";
10
11
 
11
12
  export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
12
13
  LeftTab extends string = string,
@@ -17,66 +18,146 @@ export const DrawerWorkspaceLayout = memoGeneric(function DrawerWorkspaceLayout<
17
18
  rightPanel,
18
19
  rightSidebarRef,
19
20
  centerPanel,
20
- internalLayoutState,
21
- handleChangeLayoutState,
21
+ leftTabItems,
22
+ leftTabValue,
23
+ rightTabItems,
24
+ rightTabValue,
25
+ onChangeRightTab,
26
+ onChangeLeftTab,
22
27
  }: LayoutProps<LeftTab, RightTab>) {
23
28
  const portalContainer = useRef<HTMLDivElement>(null);
24
- const [mounted, setMounted] = useState(false);
25
-
26
- useLayoutEffect(() => {
27
- if (mounted) return;
28
29
 
29
- setMounted(true);
30
- handleChangeLayoutState({
30
+ const [{ leftSidebarCollapsed, rightSidebarCollapsed }, setLayoutState] =
31
+ useState<PanelLayoutState>({
31
32
  leftSidebarCollapsed: true,
32
33
  rightSidebarCollapsed: true,
33
34
  });
34
- }, [handleChangeLayoutState, mounted]);
35
35
 
36
- const leftSidebarCollapsed =
37
- internalLayoutState?.leftSidebarCollapsed ?? false;
38
- const rightSidebarCollapsed =
39
- internalLayoutState?.rightSidebarCollapsed ?? false;
36
+ const allTabItems = useMemo(
37
+ () =>
38
+ [
39
+ ...(leftPanel ? leftTabItems ?? [] : []),
40
+ ...(rightPanel ? rightTabItems ?? [] : []),
41
+ ] as MenuItem<LeftTab | RightTab>[],
42
+ [leftTabItems, rightTabItems, leftPanel, rightPanel]
43
+ );
44
+
45
+ const hasTabs = allTabItems.length > 0;
46
+
47
+ const leftSelectableTabItems = useMemo(
48
+ () => (leftTabItems ?? []).filter(isSelectableMenuItem),
49
+ [leftTabItems]
50
+ );
51
+
52
+ const rightSelectableTabItems = useMemo(
53
+ () => (rightTabItems ?? []).filter(isSelectableMenuItem),
54
+ [rightTabItems]
55
+ );
56
+
57
+ const { activeValue, isSidebarCollapsed } =
58
+ leftSelectableTabItems.length > 0 && !leftSidebarCollapsed
59
+ ? { activeValue: leftTabValue, isSidebarCollapsed: leftSidebarCollapsed }
60
+ : rightSelectableTabItems.length > 0 && !rightSidebarCollapsed
61
+ ? {
62
+ activeValue: rightTabValue,
63
+ isSidebarCollapsed: rightSidebarCollapsed,
64
+ }
65
+ : { activeValue: undefined, isSidebarCollapsed: true };
40
66
 
41
67
  return (
42
68
  <div
43
69
  ref={portalContainer}
44
70
  id={EDITOR_PANEL_GROUP_ID}
45
- className="flex flex-1 relative focus:outline-none"
71
+ className="n-flex n-flex-1 n-relative focus:n-outline-none"
46
72
  >
73
+ {hasTabs && (
74
+ <VerticalTabMenu
75
+ tooltipSide="right"
76
+ items={allTabItems}
77
+ activeValue={activeValue}
78
+ isSidebarCollapsed={isSidebarCollapsed}
79
+ onChange={(value) => {
80
+ if (leftSelectableTabItems.some((item) => item.value === value)) {
81
+ if (value === leftTabValue) {
82
+ if (leftSidebarRef.current?.isExpanded()) {
83
+ leftSidebarRef.current?.collapse();
84
+ } else {
85
+ leftSidebarRef.current?.expand();
86
+ }
87
+ } else {
88
+ if (!leftSidebarRef.current?.isExpanded()) {
89
+ leftSidebarRef.current?.expand();
90
+ }
91
+
92
+ onChangeLeftTab?.(value as LeftTab);
93
+ }
94
+ } else if (
95
+ rightSelectableTabItems.some((item) => item.value === value)
96
+ ) {
97
+ if (value === rightTabValue) {
98
+ if (rightSidebarRef.current?.isExpanded()) {
99
+ rightSidebarRef.current?.collapse();
100
+ } else {
101
+ rightSidebarRef.current?.expand();
102
+ }
103
+ } else {
104
+ if (!rightSidebarRef.current?.isExpanded()) {
105
+ rightSidebarRef.current?.expand();
106
+ }
107
+
108
+ onChangeRightTab?.(value as RightTab);
109
+ }
110
+ }
111
+ }}
112
+ />
113
+ )}
114
+ {hasTabs && <DividerVertical className="n-h-full" />}
115
+ <div className="n-flex-1 n-flex n-relative">{centerPanel}</div>
47
116
  {leftPanel && (
48
117
  <Drawer
49
- id={LEFT_SIDEBAR_ID}
50
118
  ref={leftSidebarRef}
51
- className="flex-1"
119
+ className="n-flex-1"
120
+ style={{
121
+ left: 48,
122
+ maxWidth: "calc(100% - 48px)",
123
+ }}
124
+ overlayStyle={{
125
+ left: 48,
126
+ }}
52
127
  open={!leftSidebarCollapsed}
53
128
  positioning="absolute"
54
129
  side="left"
55
130
  trigger={null}
56
131
  portalContainer={portalContainer.current}
57
132
  onOpenChange={(open) => {
58
- handleChangeLayoutState({
59
- rightSidebarCollapsed: rightSidebarCollapsed,
133
+ setLayoutState({
60
134
  leftSidebarCollapsed: !open,
135
+ rightSidebarCollapsed: rightSidebarCollapsed,
61
136
  });
62
137
  }}
63
138
  >
64
139
  {leftPanel}
65
140
  </Drawer>
66
141
  )}
67
- {centerPanel}
68
142
  {rightPanel && (
69
143
  <Drawer
70
144
  id={RIGHT_SIDEBAR_ID}
71
145
  ref={rightSidebarRef}
72
- className="flex-1"
146
+ className="n-flex-1"
147
+ style={{
148
+ left: 48,
149
+ maxWidth: "calc(100% - 48px)",
150
+ }}
151
+ overlayStyle={{
152
+ left: 48,
153
+ }}
73
154
  open={!rightSidebarCollapsed}
74
155
  positioning="absolute"
75
- side="right"
156
+ side="left"
76
157
  trigger={null}
77
158
  portalContainer={portalContainer.current}
78
159
  onOpenChange={(open) => {
79
- handleChangeLayoutState({
160
+ setLayoutState({
80
161
  leftSidebarCollapsed: leftSidebarCollapsed,
81
162
  rightSidebarCollapsed: !open,
82
163
  });
@@ -1,5 +1,11 @@
1
- import { memoGeneric } from "@noya-app/react-utils";
2
- import React, { ComponentProps, useRef } from "react";
1
+ "use client";
2
+
3
+ import {
4
+ clientStorage,
5
+ memoGeneric,
6
+ usePersistentStateObject,
7
+ } from "@noya-app/react-utils";
8
+ import React, { useCallback, useMemo, useRef } from "react";
3
9
  import {
4
10
  ImperativePanelGroupHandle,
5
11
  ImperativePanelHandle,
@@ -7,19 +13,25 @@ import {
7
13
  PanelGroup,
8
14
  PanelResizeHandle,
9
15
  } from "react-resizable-panels";
16
+ import { DividerVertical } from "../Divider";
10
17
  import {
11
18
  CONTENT_AREA_ID,
12
19
  EDITOR_PANEL_GROUP_ID,
13
20
  LEFT_SIDEBAR_ID,
14
21
  RIGHT_SIDEBAR_ID,
15
- usePreservePanelSize,
16
- } from "../../hooks/usePreservePanelSize";
17
- import { cssVarNames } from "../../theme";
18
- import { DividerVertical } from "../Divider";
19
- import { MenuItem } from "../internal/Menu";
20
- import { ToolbarMenu } from "../Toolbar";
21
- import { Tooltip } from "../Tooltip";
22
- import { LayoutProps } from "./types";
22
+ } 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";
34
+ import { VerticalTabMenu } from "./VerticalTabMenu";
23
35
 
24
36
  export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
25
37
  LeftTab extends string,
@@ -32,7 +44,6 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
32
44
  rightSidebarOptions,
33
45
  centerPanelPercentage,
34
46
  autoSavePrefix,
35
- internalLayoutState,
36
47
  leftSidebarRef,
37
48
  rightSidebarRef,
38
49
  leftTabItems,
@@ -41,56 +52,140 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
41
52
  rightTabValue,
42
53
  onChangeLeftTab,
43
54
  onChangeRightTab,
44
- handleChangeLayoutState,
45
55
  }: LayoutProps<LeftTab, RightTab>) {
46
56
  const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
47
57
 
48
- usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
58
+ const hasLeftPanel = !!leftPanel;
59
+ const hasRightPanel = !!rightPanel;
60
+ const hasCenterPanel = !!centerPanel;
61
+
62
+ const autoSaveId = useMemo(() => {
63
+ return autoSavePrefix
64
+ ? `${autoSavePrefix}--v2--${EDITOR_PANEL_GROUP_ID}`
65
+ : Math.random().toString(36).substring(2, 15);
66
+ }, [autoSavePrefix]);
67
+
68
+ const layoutIds = getLayoutIds({
69
+ hasLeftPanel,
70
+ hasRightPanel,
71
+ hasCenterPanel,
72
+ });
73
+ const storageKey = getStorageKey(autoSaveId);
74
+ const propertyKey = getPropertyKey(layoutIds);
75
+
76
+ setInitialLayout({
77
+ storageKey,
78
+ propertyKey,
79
+ calculateLayout: () => {
80
+ return getInitialLayout({
81
+ layoutIds,
82
+ leftSidebarOptions,
83
+ rightSidebarOptions,
84
+ centerPanelPercentage,
85
+ hasLeftPanel,
86
+ hasRightPanel,
87
+ hasCenterPanel,
88
+ });
89
+ },
90
+ });
91
+
92
+ const [data, setData] = usePersistentStateObject<
93
+ WorkspaceLayoutState,
94
+ string
95
+ >(clientStorage, storageKey, {});
96
+
97
+ const layoutGroup = data?.[propertyKey];
98
+
99
+ const { leftSidebarCollapsed, rightSidebarCollapsed } = useMemo(() => {
100
+ return getLayoutCollapsedState({
101
+ layoutGroup,
102
+ propertyKey,
103
+ layoutIds,
104
+ hasLeftPanel,
105
+ hasRightPanel,
106
+ });
107
+ }, [layoutGroup, propertyKey, layoutIds, hasLeftPanel, hasRightPanel]);
108
+
109
+ const handleLeftTabChange = useCallback(
110
+ (value: LeftTab) => {
111
+ if (value === leftTabValue) {
112
+ if (leftSidebarRef.current?.isExpanded()) {
113
+ leftSidebarRef.current?.collapse();
114
+ } else {
115
+ leftSidebarRef.current?.expand();
116
+ }
117
+ } else {
118
+ if (!leftSidebarRef.current?.isExpanded()) {
119
+ leftSidebarRef.current?.expand();
120
+ }
121
+ onChangeLeftTab?.(value);
122
+ }
123
+ },
124
+ [leftSidebarRef, leftTabValue, onChangeLeftTab]
125
+ );
126
+
127
+ const handleRightTabChange = useCallback(
128
+ (value: RightTab) => {
129
+ if (value === rightTabValue) {
130
+ if (rightSidebarRef.current?.isExpanded()) {
131
+ rightSidebarRef.current?.collapse();
132
+ } else {
133
+ rightSidebarRef.current?.expand();
134
+ }
135
+ } else {
136
+ if (!rightSidebarRef.current?.isExpanded()) {
137
+ rightSidebarRef.current?.expand();
138
+ }
139
+ onChangeRightTab?.(value);
140
+ }
141
+ },
142
+ [onChangeRightTab, rightSidebarRef, rightTabValue]
143
+ );
144
+
145
+ const handleLayoutChange = useCallback(
146
+ (layout: number[]) => {
147
+ setData((prev) => {
148
+ const newData = {
149
+ ...prev,
150
+ [propertyKey]: {
151
+ layout: layout.map((size) => toPixelSize(size)),
152
+ expandToSizes: prev?.[propertyKey]?.expandToSizes ?? {},
153
+ },
154
+ };
155
+
156
+ return newData;
157
+ });
158
+ },
159
+ [setData, propertyKey]
160
+ );
49
161
 
50
162
  return (
51
163
  <PanelGroup
52
164
  ref={panelGroupRef}
53
165
  id={EDITOR_PANEL_GROUP_ID}
54
- className="flex-1"
166
+ className="n-flex-1"
55
167
  direction="horizontal"
56
- autoSaveId={
57
- autoSavePrefix
58
- ? `${autoSavePrefix}--${EDITOR_PANEL_GROUP_ID}`
59
- : undefined
60
- }
168
+ storage={panelStorage}
169
+ autoSaveId={autoSaveId}
170
+ onLayout={handleLayoutChange}
61
171
  >
62
172
  {leftPanel && (
63
173
  <>
64
- {leftTabItems && (
174
+ {leftSidebarOptions.showTabs && leftTabItems && (
65
175
  <VerticalTabMenu
66
176
  tooltipSide="right"
67
177
  items={leftTabItems}
68
178
  activeValue={leftTabValue}
69
- isSidebarCollapsed={
70
- internalLayoutState?.leftSidebarCollapsed ?? false
71
- }
72
- onChange={(value) => {
73
- if (value === leftTabValue) {
74
- if (leftSidebarRef.current?.isExpanded()) {
75
- leftSidebarRef.current?.collapse();
76
- } else {
77
- leftSidebarRef.current?.expand();
78
- }
79
- } else {
80
- if (!leftSidebarRef.current?.isExpanded()) {
81
- leftSidebarRef.current?.expand();
82
- }
83
- onChangeLeftTab?.(value);
84
- }
85
- }}
179
+ isSidebarCollapsed={leftSidebarCollapsed}
180
+ onChange={handleLeftTabChange}
86
181
  />
87
182
  )}
88
- {leftTabItems && !internalLayoutState?.leftSidebarCollapsed && (
89
- <DividerVertical className="h-full" />
90
- )}
183
+ {leftSidebarOptions.showTabs &&
184
+ leftTabItems &&
185
+ !leftSidebarCollapsed && <DividerVertical className="n-h-full" />}
91
186
  <Panel
92
187
  id={LEFT_SIDEBAR_ID}
93
- className="relative"
188
+ className="n-relative"
94
189
  order={1}
95
190
  ref={leftSidebarRef as React.RefObject<ImperativePanelHandle>}
96
191
  defaultSize={leftSidebarOptions.initialSize}
@@ -103,9 +198,9 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
103
198
  }
104
199
  collapsible
105
200
  >
106
- {internalLayoutState?.leftSidebarCollapsed ? null : leftPanel}
201
+ {leftSidebarCollapsed ? null : leftPanel}
107
202
  </Panel>
108
- <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
203
+ <PanelResizeHandle className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
109
204
  </>
110
205
  )}
111
206
  <Panel
@@ -113,16 +208,16 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
113
208
  order={2}
114
209
  defaultSize={centerPanelPercentage}
115
210
  minSize={10}
116
- className="flex relative"
211
+ className="n-flex n-relative"
117
212
  >
118
213
  {centerPanel}
119
214
  </Panel>
120
215
  {rightPanel && (
121
216
  <>
122
- <PanelResizeHandle className="cursor-col-resize w-px h-full bg-divider" />
217
+ <PanelResizeHandle className="n-cursor-col-resize n-w-px n-h-full n-bg-divider" />
123
218
  <Panel
124
219
  id={RIGHT_SIDEBAR_ID}
125
- className="relative"
220
+ className="n-relative"
126
221
  order={3}
127
222
  ref={rightSidebarRef as React.RefObject<ImperativePanelHandle>}
128
223
  minSize={rightSidebarOptions.minSize}
@@ -135,33 +230,18 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
135
230
  }
136
231
  collapsible
137
232
  >
138
- {internalLayoutState?.rightSidebarCollapsed ? null : rightPanel}
233
+ {rightSidebarCollapsed ? null : rightPanel}
139
234
  </Panel>
140
- {rightTabItems && !internalLayoutState?.rightSidebarCollapsed && (
141
- <DividerVertical className="h-full" />
142
- )}
143
- {rightTabItems && (
235
+ {rightSidebarOptions.showTabs &&
236
+ rightTabItems &&
237
+ !rightSidebarCollapsed && <DividerVertical className="n-h-full" />}
238
+ {rightSidebarOptions.showTabs && rightTabItems && (
144
239
  <VerticalTabMenu
145
240
  tooltipSide="left"
146
241
  items={rightTabItems}
147
242
  activeValue={rightTabValue}
148
- isSidebarCollapsed={
149
- internalLayoutState?.rightSidebarCollapsed ?? false
150
- }
151
- onChange={(value) => {
152
- if (value === rightTabValue) {
153
- if (rightSidebarRef.current?.isExpanded()) {
154
- rightSidebarRef.current?.collapse();
155
- } else {
156
- rightSidebarRef.current?.expand();
157
- }
158
- } else {
159
- if (!rightSidebarRef.current?.isExpanded()) {
160
- rightSidebarRef.current?.expand();
161
- }
162
- onChangeRightTab?.(value);
163
- }
164
- }}
243
+ isSidebarCollapsed={rightSidebarCollapsed}
244
+ onChange={handleRightTabChange}
165
245
  />
166
246
  )}
167
247
  </>
@@ -169,34 +249,3 @@ export const PanelWorkspaceLayout = memoGeneric(function PanelWorkspaceLayout<
169
249
  </PanelGroup>
170
250
  );
171
251
  });
172
-
173
- function VerticalTabMenu<TabValue extends string>({
174
- items,
175
- activeValue,
176
- isSidebarCollapsed,
177
- onChange,
178
- tooltipSide,
179
- }: {
180
- items: MenuItem<TabValue>[];
181
- activeValue: TabValue | undefined;
182
- isSidebarCollapsed: boolean;
183
- onChange: (value: TabValue) => void;
184
- tooltipSide?: ComponentProps<typeof Tooltip>["side"];
185
- }) {
186
- return (
187
- <div
188
- className="w-[47px] h-full bg-sidebar-background flex flex-col items-center py-3 gap-3"
189
- style={{
190
- [cssVarNames.colors.inputBackground]: "transparent",
191
- [cssVarNames.colors.buttonBackground]: "transparent",
192
- }}
193
- >
194
- <ToolbarMenu
195
- items={items}
196
- activeValue={isSidebarCollapsed ? undefined : activeValue}
197
- onSelectMenuItem={onChange}
198
- tooltipSide={tooltipSide}
199
- />
200
- </div>
201
- );
202
- }
@@ -0,0 +1,46 @@
1
+ import { memoGeneric } from "@noya-app/react-utils";
2
+ import React, { ComponentProps, useMemo } from "react";
3
+ import { cssVarNames } from "../../theme";
4
+ import { MenuItem } from "../internal/Menu";
5
+ import { ToolbarMenu } from "../Toolbar";
6
+ import { Tooltip } from "../Tooltip";
7
+
8
+ type VerticalTabMenuProps<TabValue extends string> = {
9
+ items: MenuItem<TabValue>[];
10
+ activeValue: TabValue | undefined;
11
+ isSidebarCollapsed: boolean;
12
+ onChange: (value: TabValue) => void;
13
+ tooltipSide?: ComponentProps<typeof Tooltip>["side"];
14
+ };
15
+
16
+ export const VerticalTabMenu = memoGeneric(function VerticalTabMenu<
17
+ TabValue extends string,
18
+ >({
19
+ items,
20
+ activeValue,
21
+ isSidebarCollapsed,
22
+ onChange,
23
+ tooltipSide,
24
+ }: VerticalTabMenuProps<TabValue>) {
25
+ const style = useMemo(() => {
26
+ return {
27
+ [cssVarNames.colors.inputBackground]: "transparent",
28
+ [cssVarNames.colors.buttonBackground]: "transparent",
29
+ };
30
+ }, []);
31
+
32
+ return (
33
+ <div
34
+ className="n-w-[47px] n-h-full n-bg-sidebar-background n-flex n-flex-col n-items-center n-py-3 n-gap-3"
35
+ style={style}
36
+ >
37
+ <ToolbarMenu
38
+ items={items}
39
+ activeValue={isSidebarCollapsed ? undefined : activeValue}
40
+ onSelectMenuItem={onChange}
41
+ tooltipSide={tooltipSide}
42
+ displayFilter="iconOnly"
43
+ />
44
+ </div>
45
+ );
46
+ });