@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.
- package/.turbo/turbo-build.log +13 -10
- package/CHANGELOG.md +25 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +648 -333
- package/dist/index.d.ts +648 -333
- package/dist/index.js +13813 -9157
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13949 -9269
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -22
- package/src/__tests__/validateDropIndicator.test.ts +26 -41
- package/src/__tests__/workspaceLayout.test.ts +281 -0
- package/src/components/ActionMenu.tsx +2 -0
- package/src/components/ActivityIndicator.tsx +13 -6
- package/src/components/ActivityLog.tsx +197 -0
- package/src/components/AnimatePresence.tsx +43 -26
- package/src/components/Avatar.tsx +45 -26
- package/src/components/Banner.tsx +57 -11
- package/src/components/BaseToolbar.tsx +67 -34
- package/src/components/Breadcrumbs.tsx +4 -2
- package/src/components/Button.tsx +28 -23
- package/src/components/Checkbox.tsx +6 -35
- package/src/components/Chip.tsx +47 -33
- package/src/components/Collection.tsx +20 -12
- package/src/components/ColorSwatch.tsx +42 -22
- package/src/components/ColorSwatchControl.tsx +7 -5
- package/src/components/Combobox.tsx +8 -6
- package/src/components/ComboboxMenu.tsx +6 -5
- package/src/components/CommandPalette.tsx +3 -1
- package/src/components/ContextMenu.tsx +3 -1
- package/src/components/Dialog.tsx +9 -13
- package/src/components/DimensionInput.tsx +2 -0
- package/src/components/Divider.tsx +18 -14
- package/src/components/DraggableMenuButton.tsx +11 -5
- package/src/components/Drawer.tsx +14 -6
- package/src/components/DropdownMenu.tsx +4 -2
- package/src/components/EditableText.tsx +4 -2
- package/src/components/Fade.tsx +13 -13
- package/src/components/FileUploadIndicator.tsx +108 -0
- package/src/components/FloatingWindow.tsx +4 -2
- package/src/components/Grid.tsx +58 -42
- package/src/components/GridView.tsx +65 -36
- package/src/components/IVirtualizedList.tsx +5 -0
- package/src/components/IconButton.tsx +2 -0
- package/src/components/Icons.tsx +24 -4
- package/src/components/InputField.tsx +21 -19
- package/src/components/InspectorContainer.tsx +2 -2
- package/src/components/InspectorPrimitives.tsx +15 -9
- package/src/components/Label.tsx +4 -3
- package/src/components/LabeledElementView.tsx +9 -5
- package/src/components/LabeledField.tsx +8 -6
- package/src/components/List.tsx +112 -46
- package/src/components/ListMenu.tsx +91 -0
- package/src/components/ListNavigator.tsx +106 -0
- package/src/components/ListView.tsx +22 -1147
- package/src/components/MediaThumbnail.tsx +84 -14
- package/src/components/Message.tsx +11 -12
- package/src/components/Navigator.tsx +461 -0
- package/src/components/NoyaLogo.tsx +1 -1
- package/src/components/Popover.tsx +12 -6
- package/src/components/Progress.tsx +31 -8
- package/src/components/ResizableContainer.tsx +187 -0
- package/src/components/RingProgress.tsx +128 -0
- package/src/components/ScrollArea.tsx +7 -5
- package/src/components/ScrollableSidebar.tsx +10 -0
- package/src/components/SearchCompletionMenu.tsx +5 -3
- package/src/components/Section.tsx +109 -57
- package/src/components/SegmentedControl.tsx +51 -25
- package/src/components/SelectMenu.tsx +16 -21
- package/src/components/SelectionToolbar.tsx +7 -4
- package/src/components/Slider.tsx +12 -10
- package/src/components/Spacer.tsx +2 -2
- package/src/components/StackNavigator.tsx +378 -0
- package/src/components/Stepper.tsx +88 -0
- package/src/components/Switch.tsx +7 -5
- package/src/components/Tabs.tsx +6 -4
- package/src/components/Text.tsx +29 -18
- package/src/components/TextArea.tsx +5 -3
- package/src/components/Toast.tsx +5 -5
- package/src/components/Toolbar.tsx +57 -10
- package/src/components/ToolbarDrawer.tsx +29 -0
- package/src/components/Tooltip.tsx +2 -2
- package/src/components/TreeView.tsx +13 -4
- package/src/components/UserPointer.tsx +6 -4
- package/src/components/ai-assistant/AIAssistantLayout.tsx +10 -8
- package/src/components/blocks/ImageBlockComponent.tsx +162 -0
- package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +6 -4
- package/src/components/file-explorer/FileExplorerLayout.tsx +22 -8
- package/src/components/internal/Checkmark.tsx +24 -0
- package/src/components/internal/Menu.tsx +24 -19
- package/src/components/internal/MenuViewport.tsx +15 -6
- package/src/components/internal/SelectItem.tsx +7 -26
- package/src/components/internal/TextInput.tsx +7 -1
- package/src/components/listView/ListViewContexts.tsx +68 -0
- package/src/components/listView/ListViewEditableRowTitle.tsx +55 -0
- package/src/components/listView/ListViewRoot.tsx +521 -0
- package/src/components/listView/ListViewRow.tsx +475 -0
- package/src/components/listView/ListViewRowTitle.tsx +21 -0
- package/src/components/listView/types.ts +11 -0
- package/src/components/pipeline/PipelineResultLayout.tsx +6 -6
- package/src/components/sorting/DragRegistration.tsx +10 -5
- package/src/components/sorting/SharedDragProvider.tsx +134 -27
- package/src/components/sorting/Sortable.tsx +90 -27
- package/src/components/sorting/createSharedDrag.tsx +7 -6
- package/src/components/sorting/sorting.ts +6 -9
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +110 -29
- package/src/components/workspace/PanelWorkspaceLayout.tsx +148 -99
- package/src/components/workspace/VerticalTabMenu.tsx +46 -0
- package/src/components/workspace/WorkspaceLayout.tsx +76 -63
- package/src/components/workspace/constants.ts +4 -0
- package/src/components/workspace/panelStorage.ts +216 -0
- package/src/components/workspace/types.ts +11 -4
- package/src/contexts/DesignSystemConfiguration.tsx +12 -5
- package/src/contexts/DialogContext.tsx +19 -5
- package/src/contexts/FloatingWindowContext.tsx +2 -0
- package/src/contexts/GlobalInputBlurContext.tsx +2 -0
- package/src/contexts/ImageDataContext.tsx +2 -0
- package/src/contexts/LinkComponentContext.tsx +17 -0
- package/src/contexts/OpenPortalsContext.tsx +2 -0
- package/src/contexts/PortalScopeContext.tsx +2 -0
- package/src/hooks/mergeEventHandlers.ts +1 -1
- package/src/hooks/useHover.ts +30 -17
- package/src/hooks/useIndent.ts +5 -8
- package/src/hooks/useLabel.ts +2 -0
- package/src/hooks/useObjectURL.ts +5 -3
- package/src/hooks/usePlatform.ts +5 -3
- package/src/hooks/useTheme.ts +3 -1
- package/src/index.css +43 -10
- package/src/index.tsx +15 -7
- package/src/utils/classNames.ts +56 -9
- package/src/utils/combobox.ts +2 -0
- package/src/utils/editableBlockStyles.ts +2 -2
- package/src/utils/formatByteSize.ts +9 -0
- package/src/utils/inputs.ts +8 -6
- package/src/utils/sketchColor.ts +0 -34
- package/src/utils/withSeparatorElements.ts +1 -1
- package/tailwind.config.ts +1 -0
- package/src/components/FillInputField.tsx +0 -37
- package/src/components/FillPreviewBackground.tsx +0 -132
- package/src/components/GradientPicker.tsx +0 -88
- package/src/hooks/usePreservePanelSize.tsx +0 -183
- package/src/mediaQuery.ts +0 -13
- package/src/utils/getGradientBackground.tsx +0 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noya-app/noya-designsystem",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.65",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -22,33 +22,21 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@dnd-kit/core": "6.3.1",
|
|
24
24
|
"@dnd-kit/sortable": "10.0.0",
|
|
25
|
-
"@noya-app/noya-colorpicker": "0.1.
|
|
26
|
-
"@noya-app/noya-utils": "0.1.
|
|
27
|
-
"@noya-app/noya-geometry": "0.1.
|
|
28
|
-
"@noya-app/noya-icons": "0.1.
|
|
29
|
-
"@noya-app/noya-keymap": "0.1.
|
|
30
|
-
"@noya-app/noya-tailwind-config": "0.1.
|
|
31
|
-
"
|
|
32
|
-
"@radix-ui/react-avatar": "^1.0.1",
|
|
25
|
+
"@noya-app/noya-colorpicker": "0.1.28",
|
|
26
|
+
"@noya-app/noya-utils": "0.1.7",
|
|
27
|
+
"@noya-app/noya-geometry": "0.1.14",
|
|
28
|
+
"@noya-app/noya-icons": "0.1.13",
|
|
29
|
+
"@noya-app/noya-keymap": "0.1.4",
|
|
30
|
+
"@noya-app/noya-tailwind-config": "0.1.7",
|
|
31
|
+
"radix-ui": "1.4.2",
|
|
33
32
|
"@radix-ui/react-compose-refs": "^1.0.0",
|
|
34
|
-
"@radix-ui/
|
|
35
|
-
"@radix-ui/react-dialog": "^1.0.2",
|
|
36
|
-
"@radix-ui/react-dropdown-menu": "^2.0.1",
|
|
37
|
-
"@radix-ui/react-popover": "^1.0.2",
|
|
38
|
-
"@radix-ui/react-progress": "^1.0.1",
|
|
39
|
-
"@radix-ui/react-scroll-area": "^1.0.2",
|
|
40
|
-
"@radix-ui/react-slider": "^1.2.2",
|
|
41
|
-
"@radix-ui/react-switch": "^1.0.1",
|
|
42
|
-
"@radix-ui/react-toast": "^1.1.4",
|
|
43
|
-
"@radix-ui/react-toggle-group": "^1.0.1",
|
|
44
|
-
"@radix-ui/react-tooltip": "^1.0.2",
|
|
33
|
+
"@radix-ui/primitive": "^1.0.1",
|
|
45
34
|
"@radix-ui/react-utils": "^0.0.5",
|
|
46
|
-
"@radix-ui/react-select": "^2.1.1",
|
|
47
35
|
"@radix-ui/react-popper": "1.2.3",
|
|
48
36
|
"@radix-ui/utils": "0.0.3",
|
|
49
37
|
"immer": "9.0.5",
|
|
50
38
|
"kiwi.js": "^1.1.3",
|
|
51
|
-
"react-resizable-panels": "
|
|
39
|
+
"react-resizable-panels": "3.0.3",
|
|
52
40
|
"react-window": "^1.8.8",
|
|
53
41
|
"vscode-fuzzy-scorer": "^0.0.4",
|
|
54
42
|
"react-virtualized": "9.22.6"
|
|
@@ -118,15 +118,12 @@ describe("validateDropIndicator", () => {
|
|
|
118
118
|
return parameters.position !== "below";
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
const keys = ["item1", "item2", "item3"];
|
|
122
|
-
|
|
123
121
|
describe("with above and inside positions allowed, but not below", () => {
|
|
124
122
|
it("should return 'inside' when cursor is in the middle third", () => {
|
|
125
123
|
const result = validateDropIndicator({
|
|
126
124
|
acceptsDrop: mockAcceptsAboveAndInside,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
overId: "item2",
|
|
125
|
+
activeIndex: 0,
|
|
126
|
+
overIndex: 1,
|
|
130
127
|
offsetStart: 50, // offsetStart in middle third
|
|
131
128
|
elementStart: 0, // elementStart
|
|
132
129
|
elementSize: 100, // elementSize
|
|
@@ -139,9 +136,8 @@ describe("validateDropIndicator", () => {
|
|
|
139
136
|
it("should return 'above' when cursor is in the top third", () => {
|
|
140
137
|
const result = validateDropIndicator({
|
|
141
138
|
acceptsDrop: mockAcceptsAboveAndInside,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
overId: "item2",
|
|
139
|
+
activeIndex: 0,
|
|
140
|
+
overIndex: 1,
|
|
145
141
|
offsetStart: 20, // offsetStart in top third
|
|
146
142
|
elementStart: 0, // elementStart
|
|
147
143
|
elementSize: 100, // elementSize
|
|
@@ -154,9 +150,8 @@ describe("validateDropIndicator", () => {
|
|
|
154
150
|
it("should fallback to 'inside' when cursor is in bottom third since 'below' is not allowed", () => {
|
|
155
151
|
const result = validateDropIndicator({
|
|
156
152
|
acceptsDrop: mockAcceptsAboveAndInside,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
overId: "item2",
|
|
153
|
+
activeIndex: 0,
|
|
154
|
+
overIndex: 1,
|
|
160
155
|
offsetStart: 80, // offsetStart in bottom third
|
|
161
156
|
elementStart: 0, // elementStart
|
|
162
157
|
elementSize: 100, // elementSize
|
|
@@ -171,9 +166,8 @@ describe("validateDropIndicator", () => {
|
|
|
171
166
|
it("should prefer 'inside' when cursor is in the middle third", () => {
|
|
172
167
|
const result = validateDropIndicator({
|
|
173
168
|
acceptsDrop: mockAcceptsAll,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
overId: "item2",
|
|
169
|
+
activeIndex: 0,
|
|
170
|
+
overIndex: 1,
|
|
177
171
|
offsetStart: 50, // offsetStart in middle third
|
|
178
172
|
elementStart: 0, // elementStart
|
|
179
173
|
elementSize: 100, // elementSize
|
|
@@ -186,9 +180,8 @@ describe("validateDropIndicator", () => {
|
|
|
186
180
|
it("should prefer 'above' when cursor is in the top third", () => {
|
|
187
181
|
const result = validateDropIndicator({
|
|
188
182
|
acceptsDrop: mockAcceptsAll,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
overId: "item2",
|
|
183
|
+
activeIndex: 0,
|
|
184
|
+
overIndex: 1,
|
|
192
185
|
offsetStart: 20, // offsetStart in top third
|
|
193
186
|
elementStart: 0, // elementStart
|
|
194
187
|
elementSize: 100, // elementSize
|
|
@@ -201,9 +194,8 @@ describe("validateDropIndicator", () => {
|
|
|
201
194
|
it("should prefer 'below' when cursor is in the bottom third", () => {
|
|
202
195
|
const result = validateDropIndicator({
|
|
203
196
|
acceptsDrop: mockAcceptsAll,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
overId: "item2",
|
|
197
|
+
activeIndex: 0,
|
|
198
|
+
overIndex: 1,
|
|
207
199
|
offsetStart: 80, // offsetStart in bottom third
|
|
208
200
|
elementStart: 0, // elementStart
|
|
209
201
|
elementSize: 100, // elementSize
|
|
@@ -216,9 +208,8 @@ describe("validateDropIndicator", () => {
|
|
|
216
208
|
it("should handle non-zero elementStart position", () => {
|
|
217
209
|
const result = validateDropIndicator({
|
|
218
210
|
acceptsDrop: mockAcceptsAll,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
overId: "item2",
|
|
211
|
+
activeIndex: 0,
|
|
212
|
+
overIndex: 1,
|
|
222
213
|
offsetStart: 120, // offsetStart in middle third relative to elementStart
|
|
223
214
|
elementStart: 100, // elementStart
|
|
224
215
|
elementSize: 60, // elementSize
|
|
@@ -232,9 +223,8 @@ describe("validateDropIndicator", () => {
|
|
|
232
223
|
it("should return 'inside' when cursor is in the middle third and inside drops are allowed", () => {
|
|
233
224
|
const result = validateDropIndicator({
|
|
234
225
|
acceptsDrop: mockAcceptsDrop,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
overId: "item2",
|
|
226
|
+
activeIndex: 0,
|
|
227
|
+
overIndex: 1,
|
|
238
228
|
offsetStart: 50, // offsetStart in middle third
|
|
239
229
|
elementStart: 0, // elementStart
|
|
240
230
|
elementSize: 100, // elementSize
|
|
@@ -247,9 +237,8 @@ describe("validateDropIndicator", () => {
|
|
|
247
237
|
it("should return 'above' when cursor is in top half and above drops are allowed", () => {
|
|
248
238
|
const result = validateDropIndicator({
|
|
249
239
|
acceptsDrop: mockAcceptsDropAboveBelow,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
overId: "item2",
|
|
240
|
+
activeIndex: 0,
|
|
241
|
+
overIndex: 1,
|
|
253
242
|
offsetStart: 20, // offsetStart in top half
|
|
254
243
|
elementStart: 0, // elementStart
|
|
255
244
|
elementSize: 100, // elementSize
|
|
@@ -262,9 +251,8 @@ describe("validateDropIndicator", () => {
|
|
|
262
251
|
it("should return 'below' when cursor is in bottom half and below drops are allowed", () => {
|
|
263
252
|
const result = validateDropIndicator({
|
|
264
253
|
acceptsDrop: mockAcceptsDropAboveBelow,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
overId: "item2",
|
|
254
|
+
activeIndex: 0,
|
|
255
|
+
overIndex: 1,
|
|
268
256
|
offsetStart: 70, // offsetStart in bottom half
|
|
269
257
|
elementStart: 0, // elementStart
|
|
270
258
|
elementSize: 100, // elementSize
|
|
@@ -277,9 +265,8 @@ describe("validateDropIndicator", () => {
|
|
|
277
265
|
it("should fallback to inside when above/below not allowed and inside is allowed", () => {
|
|
278
266
|
const result = validateDropIndicator({
|
|
279
267
|
acceptsDrop: mockAcceptsDrop,
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
overId: "item2",
|
|
268
|
+
activeIndex: 0,
|
|
269
|
+
overIndex: 1,
|
|
283
270
|
offsetStart: 20, // offsetStart in top half
|
|
284
271
|
elementStart: 0, // elementStart
|
|
285
272
|
elementSize: 100, // elementSize
|
|
@@ -293,9 +280,8 @@ describe("validateDropIndicator", () => {
|
|
|
293
280
|
const neverAllowDrop = () => false;
|
|
294
281
|
const result = validateDropIndicator({
|
|
295
282
|
acceptsDrop: neverAllowDrop,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
overId: "item2",
|
|
283
|
+
activeIndex: 0,
|
|
284
|
+
overIndex: 1,
|
|
299
285
|
offsetStart: 50,
|
|
300
286
|
elementStart: 0,
|
|
301
287
|
elementSize: 100,
|
|
@@ -308,9 +294,8 @@ describe("validateDropIndicator", () => {
|
|
|
308
294
|
it("should ignore items not in the keys array", () => {
|
|
309
295
|
const result = validateDropIndicator({
|
|
310
296
|
acceptsDrop: mockAcceptsDrop,
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
overId: "item2",
|
|
297
|
+
activeIndex: -1,
|
|
298
|
+
overIndex: 1,
|
|
314
299
|
offsetStart: 50,
|
|
315
300
|
elementStart: 0,
|
|
316
301
|
elementSize: 100,
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { expect, it } from "bun:test";
|
|
2
|
+
import { MockClientStorage } from "../../../noya-react-utils/src/__tests__/MockClientStorage";
|
|
3
|
+
import {
|
|
4
|
+
CONTENT_AREA_ID,
|
|
5
|
+
LEFT_SIDEBAR_ID,
|
|
6
|
+
RIGHT_SIDEBAR_ID,
|
|
7
|
+
} from "../components/workspace/constants";
|
|
8
|
+
import {
|
|
9
|
+
getInitialLayout,
|
|
10
|
+
getLayoutCollapsedState,
|
|
11
|
+
getLayoutIds,
|
|
12
|
+
getPropertyKey,
|
|
13
|
+
getStorageKey,
|
|
14
|
+
mapWorkspaceLayoutState,
|
|
15
|
+
setInitialLayout,
|
|
16
|
+
toPercentageSize,
|
|
17
|
+
toPixelSize,
|
|
18
|
+
} from "../components/workspace/panelStorage";
|
|
19
|
+
import { WorkspaceLayoutState } from "../components/workspace/types";
|
|
20
|
+
|
|
21
|
+
const TEST_WINDOW_WIDTH = 1000;
|
|
22
|
+
|
|
23
|
+
it("gets layout ids", () => {
|
|
24
|
+
expect(
|
|
25
|
+
getLayoutIds({
|
|
26
|
+
hasLeftPanel: true,
|
|
27
|
+
hasRightPanel: false,
|
|
28
|
+
hasCenterPanel: true,
|
|
29
|
+
})
|
|
30
|
+
).toEqual([LEFT_SIDEBAR_ID, CONTENT_AREA_ID]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("gets layout ids with all panels", () => {
|
|
34
|
+
expect(
|
|
35
|
+
getLayoutIds({
|
|
36
|
+
hasLeftPanel: true,
|
|
37
|
+
hasRightPanel: true,
|
|
38
|
+
hasCenterPanel: true,
|
|
39
|
+
})
|
|
40
|
+
).toEqual([LEFT_SIDEBAR_ID, CONTENT_AREA_ID, RIGHT_SIDEBAR_ID]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("gets layout ids with no panels", () => {
|
|
44
|
+
expect(
|
|
45
|
+
getLayoutIds({
|
|
46
|
+
hasLeftPanel: false,
|
|
47
|
+
hasRightPanel: false,
|
|
48
|
+
hasCenterPanel: false,
|
|
49
|
+
})
|
|
50
|
+
).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("converts to pixel size", () => {
|
|
54
|
+
expect(toPixelSize(25, TEST_WINDOW_WIDTH)).toBe(250); // 25% of 1000px = 250px
|
|
55
|
+
expect(toPixelSize(50, TEST_WINDOW_WIDTH)).toBe(500); // 50% of 1000px = 500px
|
|
56
|
+
expect(toPixelSize(75, TEST_WINDOW_WIDTH)).toBe(750); // 75% of 1000px = 750px
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("converts to percentage size", () => {
|
|
60
|
+
expect(toPercentageSize(250, TEST_WINDOW_WIDTH)).toBe(25); // 250px of 1000px = 25%
|
|
61
|
+
expect(toPercentageSize(500, TEST_WINDOW_WIDTH)).toBe(50); // 500px of 1000px = 50%
|
|
62
|
+
expect(toPercentageSize(750, TEST_WINDOW_WIDTH)).toBe(75); // 750px of 1000px = 75%
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("maps workspace layout state", () => {
|
|
66
|
+
const layout: WorkspaceLayoutState = {
|
|
67
|
+
"left,center": {
|
|
68
|
+
layout: [20, 80],
|
|
69
|
+
expandToSizes: { left: 30, center: 70 },
|
|
70
|
+
},
|
|
71
|
+
"left,center,right": {
|
|
72
|
+
layout: [20, 60, 20],
|
|
73
|
+
expandToSizes: { left: 25, center: 50, right: 25 },
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const mapped = mapWorkspaceLayoutState(layout, (size) => size * 2);
|
|
78
|
+
|
|
79
|
+
expect(mapped).toEqual({
|
|
80
|
+
"left,center": {
|
|
81
|
+
layout: [40, 160],
|
|
82
|
+
expandToSizes: { left: 60, center: 140 },
|
|
83
|
+
},
|
|
84
|
+
"left,center,right": {
|
|
85
|
+
layout: [40, 120, 40],
|
|
86
|
+
expandToSizes: { left: 50, center: 100, right: 50 },
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("gets property key", () => {
|
|
92
|
+
expect(getPropertyKey([LEFT_SIDEBAR_ID, CONTENT_AREA_ID])).toBe(
|
|
93
|
+
[CONTENT_AREA_ID, LEFT_SIDEBAR_ID].sort().join(",")
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("gets storage key", () => {
|
|
98
|
+
expect(getStorageKey("test-workspace")).toBe(
|
|
99
|
+
"react-resizable-panels:test-workspace"
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("gets initial layout with left panel only", () => {
|
|
104
|
+
const result = getInitialLayout({
|
|
105
|
+
layoutIds: [LEFT_SIDEBAR_ID, CONTENT_AREA_ID],
|
|
106
|
+
leftSidebarOptions: {
|
|
107
|
+
initialSize: 20,
|
|
108
|
+
defaultCollapsed: false,
|
|
109
|
+
},
|
|
110
|
+
rightSidebarOptions: {
|
|
111
|
+
initialSize: 20,
|
|
112
|
+
defaultCollapsed: false,
|
|
113
|
+
},
|
|
114
|
+
centerPanelPercentage: 80,
|
|
115
|
+
hasLeftPanel: true,
|
|
116
|
+
hasRightPanel: false,
|
|
117
|
+
hasCenterPanel: true,
|
|
118
|
+
windowWidth: TEST_WINDOW_WIDTH,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
expect(result).toEqual([200, 800]); // 20% and 80% of 1000px
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("gets initial layout with collapsed left panel", () => {
|
|
125
|
+
const result = getInitialLayout({
|
|
126
|
+
layoutIds: [LEFT_SIDEBAR_ID, CONTENT_AREA_ID],
|
|
127
|
+
leftSidebarOptions: {
|
|
128
|
+
initialSize: 20,
|
|
129
|
+
defaultCollapsed: true,
|
|
130
|
+
},
|
|
131
|
+
rightSidebarOptions: {
|
|
132
|
+
initialSize: 20,
|
|
133
|
+
defaultCollapsed: false,
|
|
134
|
+
},
|
|
135
|
+
centerPanelPercentage: 80,
|
|
136
|
+
hasLeftPanel: true,
|
|
137
|
+
hasRightPanel: false,
|
|
138
|
+
hasCenterPanel: true,
|
|
139
|
+
windowWidth: TEST_WINDOW_WIDTH,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(result).toEqual([0, 1000]); // Collapsed left panel, center takes full width
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("gets initial layout with all panels", () => {
|
|
146
|
+
const result = getInitialLayout({
|
|
147
|
+
layoutIds: [LEFT_SIDEBAR_ID, CONTENT_AREA_ID, RIGHT_SIDEBAR_ID],
|
|
148
|
+
leftSidebarOptions: {
|
|
149
|
+
initialSize: 20,
|
|
150
|
+
defaultCollapsed: false,
|
|
151
|
+
},
|
|
152
|
+
rightSidebarOptions: {
|
|
153
|
+
initialSize: 20,
|
|
154
|
+
defaultCollapsed: false,
|
|
155
|
+
},
|
|
156
|
+
centerPanelPercentage: 60,
|
|
157
|
+
hasLeftPanel: true,
|
|
158
|
+
hasRightPanel: true,
|
|
159
|
+
hasCenterPanel: true,
|
|
160
|
+
windowWidth: TEST_WINDOW_WIDTH,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(result).toEqual([200, 600, 200]); // 20%, 60%, 20% of 1000px
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("sets initial layout in storage", () => {
|
|
167
|
+
const mockStorage = new MockClientStorage();
|
|
168
|
+
|
|
169
|
+
setInitialLayout({
|
|
170
|
+
storageKey: "test-key",
|
|
171
|
+
propertyKey: "left,center",
|
|
172
|
+
calculateLayout: () => [200, 800],
|
|
173
|
+
storage: mockStorage,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(mockStorage.hasItem("test-key")).toBe(true);
|
|
177
|
+
expect(mockStorage.getItemParsed<WorkspaceLayoutState>("test-key")).toEqual({
|
|
178
|
+
"left,center": {
|
|
179
|
+
layout: [200, 800],
|
|
180
|
+
expandToSizes: {},
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("does not update existing layout property in storage", () => {
|
|
186
|
+
const existingLayout: WorkspaceLayoutState = {
|
|
187
|
+
center: {
|
|
188
|
+
layout: [1000],
|
|
189
|
+
expandToSizes: {},
|
|
190
|
+
},
|
|
191
|
+
// Already has the property we're trying to set
|
|
192
|
+
"left,center": {
|
|
193
|
+
layout: [100, 900],
|
|
194
|
+
expandToSizes: {},
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const mockStorage = new MockClientStorage();
|
|
199
|
+
mockStorage.setItem("test-key", JSON.stringify(existingLayout));
|
|
200
|
+
|
|
201
|
+
setInitialLayout({
|
|
202
|
+
storageKey: "test-key",
|
|
203
|
+
propertyKey: "left,center",
|
|
204
|
+
calculateLayout: () => [200, 800],
|
|
205
|
+
storage: mockStorage,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// setInitialLayout doesn't update existing properties, so the layout should remain unchanged
|
|
209
|
+
expect(mockStorage.getItemParsed<WorkspaceLayoutState>("test-key")).toEqual(
|
|
210
|
+
existingLayout
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("adds new layout property to existing storage", () => {
|
|
215
|
+
const existingLayout: WorkspaceLayoutState = {
|
|
216
|
+
center: {
|
|
217
|
+
layout: [1000],
|
|
218
|
+
expandToSizes: {},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const mockStorage = new MockClientStorage();
|
|
223
|
+
mockStorage.setItem("test-key", JSON.stringify(existingLayout));
|
|
224
|
+
|
|
225
|
+
// The propertyId should be sorted
|
|
226
|
+
const sortedPropertyId = [LEFT_SIDEBAR_ID, CONTENT_AREA_ID].sort().join(",");
|
|
227
|
+
|
|
228
|
+
setInitialLayout({
|
|
229
|
+
storageKey: "test-key",
|
|
230
|
+
propertyKey: sortedPropertyId,
|
|
231
|
+
calculateLayout: () => [200, 800],
|
|
232
|
+
storage: mockStorage,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(mockStorage.getItemParsed<WorkspaceLayoutState>("test-key")).toEqual({
|
|
236
|
+
center: {
|
|
237
|
+
layout: [1000],
|
|
238
|
+
expandToSizes: {},
|
|
239
|
+
},
|
|
240
|
+
[sortedPropertyId]: {
|
|
241
|
+
layout: [200, 800],
|
|
242
|
+
expandToSizes: {},
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("gets layout collapsed state", () => {
|
|
248
|
+
const layoutGroup = {
|
|
249
|
+
layout: [0, 800, 200],
|
|
250
|
+
expandToSizes: {},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const result = getLayoutCollapsedState({
|
|
254
|
+
layoutGroup,
|
|
255
|
+
propertyKey: "left,center,right",
|
|
256
|
+
layoutIds: [LEFT_SIDEBAR_ID, CONTENT_AREA_ID, RIGHT_SIDEBAR_ID],
|
|
257
|
+
hasLeftPanel: true,
|
|
258
|
+
hasRightPanel: true,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
expect(result.leftSidebarCollapsed).toBe(true); // size is 0
|
|
262
|
+
expect(result.rightSidebarCollapsed).toBe(false); // size is 200
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("handles panels that don't exist", () => {
|
|
266
|
+
const layoutGroup = {
|
|
267
|
+
layout: [1000],
|
|
268
|
+
expandToSizes: {},
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const result = getLayoutCollapsedState({
|
|
272
|
+
layoutGroup,
|
|
273
|
+
propertyKey: "center",
|
|
274
|
+
layoutIds: [CONTENT_AREA_ID],
|
|
275
|
+
hasLeftPanel: false,
|
|
276
|
+
hasRightPanel: false,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(result.leftSidebarCollapsed).toBe(false); // Panel doesn't exist
|
|
280
|
+
expect(result.rightSidebarCollapsed).toBe(false); // Panel doesn't exist
|
|
281
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import * as React from "react";
|
|
2
4
|
import { cx } from "../utils/classNames";
|
|
3
5
|
|
|
@@ -7,6 +9,7 @@ interface Props {
|
|
|
7
9
|
color?: string;
|
|
8
10
|
trackColor?: string;
|
|
9
11
|
className?: string;
|
|
12
|
+
style?: React.CSSProperties;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
@@ -15,8 +18,12 @@ export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
|
15
18
|
color = "black",
|
|
16
19
|
trackColor = "rgba(0, 0, 0, 0.1)",
|
|
17
20
|
className,
|
|
21
|
+
style,
|
|
18
22
|
}: Props) {
|
|
19
|
-
const
|
|
23
|
+
const containerStyle = React.useMemo(
|
|
24
|
+
() => ({ opacity, ...style }),
|
|
25
|
+
[opacity, style]
|
|
26
|
+
);
|
|
20
27
|
const dynamicStyles = React.useMemo(
|
|
21
28
|
() => ({
|
|
22
29
|
border: `2px solid ${trackColor}`,
|
|
@@ -27,11 +34,11 @@ export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
|
27
34
|
[size, color, trackColor]
|
|
28
35
|
);
|
|
29
36
|
return (
|
|
30
|
-
<
|
|
31
|
-
className={cx("flex justify-center items-center", className)}
|
|
32
|
-
style={
|
|
37
|
+
<span
|
|
38
|
+
className={cx("n-flex n-justify-center n-items-center", className)}
|
|
39
|
+
style={containerStyle}
|
|
33
40
|
>
|
|
34
|
-
<
|
|
35
|
-
</
|
|
41
|
+
<span style={dynamicStyles} className="n-animate-spin n-rounded-[50%]" />
|
|
42
|
+
</span>
|
|
36
43
|
);
|
|
37
44
|
});
|