@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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
2
4
|
import {
|
|
3
5
|
forwardRefGeneric,
|
|
@@ -5,13 +7,7 @@ import {
|
|
|
5
7
|
useSize,
|
|
6
8
|
useWindowSize,
|
|
7
9
|
} from "@noya-app/react-utils";
|
|
8
|
-
import React, {
|
|
9
|
-
memo,
|
|
10
|
-
useCallback,
|
|
11
|
-
useImperativeHandle,
|
|
12
|
-
useRef,
|
|
13
|
-
useState,
|
|
14
|
-
} from "react";
|
|
10
|
+
import React, { memo, useImperativeHandle, useMemo, useRef } from "react";
|
|
15
11
|
import { cx } from "../../utils/classNames";
|
|
16
12
|
import { MenuItem } from "../internal/Menu";
|
|
17
13
|
import { DrawerWorkspaceLayout } from "./DrawerWorkspaceLayout";
|
|
@@ -19,7 +15,6 @@ import { PanelWorkspaceLayout } from "./PanelWorkspaceLayout";
|
|
|
19
15
|
import { renderPanelChildren } from "./renderPanelChildren";
|
|
20
16
|
import {
|
|
21
17
|
LayoutProps,
|
|
22
|
-
PanelLayoutState,
|
|
23
18
|
PercentageSidebarOptions,
|
|
24
19
|
RenderPanel,
|
|
25
20
|
SidebarRef,
|
|
@@ -55,7 +50,6 @@ export interface WorkspaceLayoutProps<
|
|
|
55
50
|
sideType?: SideType;
|
|
56
51
|
sideTypeBreakpoint?: number;
|
|
57
52
|
detectSize?: DetectSizeType;
|
|
58
|
-
onChangeLayoutState?: (layoutState: PanelLayoutState) => void;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
export type WorkspaceLayoutRef = {
|
|
@@ -67,6 +61,8 @@ export type WorkspaceLayoutRef = {
|
|
|
67
61
|
};
|
|
68
62
|
|
|
69
63
|
export type SideOptions = {
|
|
64
|
+
// Whether to show the sidebar. Defaults to true.
|
|
65
|
+
visible?: boolean;
|
|
70
66
|
style?: React.CSSProperties;
|
|
71
67
|
className?: string;
|
|
72
68
|
resizable?: boolean;
|
|
@@ -78,23 +74,24 @@ export type SideOptions = {
|
|
|
78
74
|
minSize?: number | string;
|
|
79
75
|
maxSize?: number | string;
|
|
80
76
|
defaultCollapsed?: boolean;
|
|
77
|
+
showTabs?: boolean;
|
|
81
78
|
};
|
|
82
79
|
|
|
83
80
|
const defaultLeftTabItems: MenuItem<string>[] = [
|
|
84
81
|
{
|
|
85
82
|
title: "",
|
|
86
|
-
value: "
|
|
83
|
+
value: "defaultLeft",
|
|
87
84
|
icon: "BorderLeftIcon",
|
|
88
|
-
tooltip: "Sidebar",
|
|
85
|
+
tooltip: "Left Sidebar",
|
|
89
86
|
},
|
|
90
87
|
];
|
|
91
88
|
|
|
92
89
|
const defaultRightTabItems: MenuItem<string>[] = [
|
|
93
90
|
{
|
|
94
91
|
title: "",
|
|
95
|
-
value: "
|
|
92
|
+
value: "defaultRight",
|
|
96
93
|
icon: "BorderRightIcon",
|
|
97
|
-
tooltip: "Sidebar",
|
|
94
|
+
tooltip: "Right Sidebar",
|
|
98
95
|
},
|
|
99
96
|
];
|
|
100
97
|
|
|
@@ -117,11 +114,11 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
117
114
|
style,
|
|
118
115
|
toolbar,
|
|
119
116
|
children,
|
|
120
|
-
onChangeLayoutState,
|
|
121
117
|
sideType = "auto",
|
|
122
118
|
sideTypeBreakpoint = 800,
|
|
123
119
|
detectSize = "container",
|
|
124
120
|
leftOptions: {
|
|
121
|
+
visible: leftVisible = true,
|
|
125
122
|
minSize: leftMinSize = 200,
|
|
126
123
|
maxSize: leftMaxSize = 500,
|
|
127
124
|
initialSize: leftInitialSize = 280,
|
|
@@ -129,8 +126,10 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
129
126
|
style: leftStyle,
|
|
130
127
|
className: leftClassName,
|
|
131
128
|
defaultCollapsed: leftDefaultCollapsed = false,
|
|
129
|
+
showTabs: leftShowTabs = true,
|
|
132
130
|
} = {},
|
|
133
131
|
rightOptions: {
|
|
132
|
+
visible: rightVisible = true,
|
|
134
133
|
minSize: rightMinSize = 200,
|
|
135
134
|
maxSize: rightMaxSize = 500,
|
|
136
135
|
initialSize: rightInitialSize = 280,
|
|
@@ -138,6 +137,7 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
138
137
|
style: rightStyle,
|
|
139
138
|
className: rightClassName,
|
|
140
139
|
defaultCollapsed: rightDefaultCollapsed = false,
|
|
140
|
+
showTabs: rightShowTabs = true,
|
|
141
141
|
} = {},
|
|
142
142
|
theme,
|
|
143
143
|
}: WorkspaceLayoutProps<LeftTab, RightTab>,
|
|
@@ -213,20 +213,6 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
213
213
|
defaultValue: getFirstTabValue(rightTabItems, "" as RightTab),
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
-
const [internalLayoutState, setInternalLayoutState] =
|
|
217
|
-
useState<PanelLayoutState | null>({
|
|
218
|
-
leftSidebarCollapsed: leftDefaultCollapsed,
|
|
219
|
-
rightSidebarCollapsed: rightDefaultCollapsed,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
const handleChangeLayoutState = useCallback(
|
|
223
|
-
(state: PanelLayoutState) => {
|
|
224
|
-
setInternalLayoutState(state);
|
|
225
|
-
onChangeLayoutState?.(state);
|
|
226
|
-
},
|
|
227
|
-
[onChangeLayoutState]
|
|
228
|
-
);
|
|
229
|
-
|
|
230
216
|
useImperativeHandle(forwardedRef, () => ({
|
|
231
217
|
setLeftExpanded: (expanded: boolean) => {
|
|
232
218
|
if (expanded) {
|
|
@@ -294,41 +280,67 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
294
280
|
(left ? leftSidebarPercentage : 0) -
|
|
295
281
|
(right ? rightSidebarPercentage : 0);
|
|
296
282
|
|
|
297
|
-
const leftPanel =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
283
|
+
const leftPanel =
|
|
284
|
+
left && leftVisible !== false ? (
|
|
285
|
+
<PanelInner
|
|
286
|
+
style={leftStyle}
|
|
287
|
+
className={cx("n-bg-sidebar-background n-flex-col", leftClassName)}
|
|
288
|
+
>
|
|
289
|
+
{leftTabValue ? renderPanelChildren(left, leftTabValue) : null}
|
|
290
|
+
</PanelInner>
|
|
291
|
+
) : null;
|
|
292
|
+
|
|
293
|
+
const rightPanel =
|
|
294
|
+
right && rightVisible !== false ? (
|
|
295
|
+
<PanelInner
|
|
296
|
+
style={rightStyle}
|
|
297
|
+
className={cx("n-bg-sidebar-background n-flex-col", rightClassName)}
|
|
298
|
+
>
|
|
299
|
+
{rightTabValue ? renderPanelChildren(right, rightTabValue) : null}
|
|
300
|
+
</PanelInner>
|
|
301
|
+
) : null;
|
|
314
302
|
|
|
315
303
|
const centerPanel = (
|
|
316
|
-
<PanelInner className="bg-canvas-background">{children}</PanelInner>
|
|
304
|
+
<PanelInner className="n-bg-canvas-background">{children}</PanelInner>
|
|
317
305
|
);
|
|
318
306
|
|
|
319
|
-
const leftSidebarOptions: PercentageSidebarOptions =
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
307
|
+
const leftSidebarOptions: PercentageSidebarOptions = useMemo(
|
|
308
|
+
() => ({
|
|
309
|
+
minSize: leftSidebarMinPercentage,
|
|
310
|
+
maxSize: leftSidebarMaxPercentage,
|
|
311
|
+
initialSize: leftSidebarPercentage,
|
|
312
|
+
resizable: leftResizable,
|
|
313
|
+
defaultCollapsed: leftDefaultCollapsed,
|
|
314
|
+
showTabs: leftShowTabs,
|
|
315
|
+
}),
|
|
316
|
+
[
|
|
317
|
+
leftSidebarMinPercentage,
|
|
318
|
+
leftSidebarMaxPercentage,
|
|
319
|
+
leftSidebarPercentage,
|
|
320
|
+
leftResizable,
|
|
321
|
+
leftDefaultCollapsed,
|
|
322
|
+
leftShowTabs,
|
|
323
|
+
]
|
|
324
|
+
);
|
|
325
325
|
|
|
326
|
-
const rightSidebarOptions: PercentageSidebarOptions =
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
326
|
+
const rightSidebarOptions: PercentageSidebarOptions = useMemo(
|
|
327
|
+
() => ({
|
|
328
|
+
minSize: rightSidebarMinPercentage,
|
|
329
|
+
maxSize: rightSidebarMaxPercentage,
|
|
330
|
+
initialSize: rightSidebarPercentage,
|
|
331
|
+
resizable: rightResizable,
|
|
332
|
+
defaultCollapsed: rightDefaultCollapsed,
|
|
333
|
+
showTabs: rightShowTabs,
|
|
334
|
+
}),
|
|
335
|
+
[
|
|
336
|
+
rightSidebarMinPercentage,
|
|
337
|
+
rightSidebarMaxPercentage,
|
|
338
|
+
rightSidebarPercentage,
|
|
339
|
+
rightResizable,
|
|
340
|
+
rightDefaultCollapsed,
|
|
341
|
+
rightShowTabs,
|
|
342
|
+
]
|
|
343
|
+
);
|
|
332
344
|
|
|
333
345
|
const LayoutComponent =
|
|
334
346
|
sideType === "panel"
|
|
@@ -353,12 +365,12 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
353
365
|
<div
|
|
354
366
|
ref={containerRef}
|
|
355
367
|
id={id}
|
|
356
|
-
className={cx("flex flex-col bg-canvas-background relative", className)}
|
|
368
|
+
className={cx("n-flex n-flex-col n-bg-canvas-background n-relative", className)}
|
|
357
369
|
style={style}
|
|
358
370
|
data-theme={theme}
|
|
359
371
|
>
|
|
360
372
|
{toolbar}
|
|
361
|
-
<div className="flex flex-row flex-1 relative">
|
|
373
|
+
<div className="n-flex n-flex-row n-flex-1 n-relative">
|
|
362
374
|
{readyToRender && (
|
|
363
375
|
<LayoutComponent
|
|
364
376
|
leftPanel={leftPanel}
|
|
@@ -374,10 +386,8 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
374
386
|
rightSidebarOptions={rightSidebarOptions}
|
|
375
387
|
centerPanelPercentage={centerPanelPercentage}
|
|
376
388
|
autoSavePrefix={autoSavePrefix}
|
|
377
|
-
internalLayoutState={internalLayoutState}
|
|
378
389
|
leftSidebarRef={leftSidebarRef}
|
|
379
390
|
rightSidebarRef={rightSidebarRef}
|
|
380
|
-
handleChangeLayoutState={handleChangeLayoutState}
|
|
381
391
|
/>
|
|
382
392
|
)}
|
|
383
393
|
</div>
|
|
@@ -395,7 +405,10 @@ const PanelInner = memo(function PanelInner({
|
|
|
395
405
|
className?: string;
|
|
396
406
|
}) {
|
|
397
407
|
return (
|
|
398
|
-
<div
|
|
408
|
+
<div
|
|
409
|
+
style={style}
|
|
410
|
+
className={cx("n-absolute n-inset-0 n-min-w-0 n-flex", className)}
|
|
411
|
+
>
|
|
399
412
|
{children}
|
|
400
413
|
</div>
|
|
401
414
|
);
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { clientStorage, IClientStorage } from "@noya-app/react-utils";
|
|
2
|
+
import { PanelGroupStorage } from "react-resizable-panels";
|
|
3
|
+
import {
|
|
4
|
+
CONTENT_AREA_ID,
|
|
5
|
+
LEFT_SIDEBAR_ID,
|
|
6
|
+
RIGHT_SIDEBAR_ID,
|
|
7
|
+
} from "./constants";
|
|
8
|
+
import {
|
|
9
|
+
PercentageSidebarOptions,
|
|
10
|
+
WorkspaceLayoutGroup,
|
|
11
|
+
WorkspaceLayoutState,
|
|
12
|
+
} from "./types";
|
|
13
|
+
|
|
14
|
+
// Workspace sizes are stored as percentages (e.g. layout: [78.7224911972, 21.2775088028])
|
|
15
|
+
// we need to convert them to pixels relative to the window width before storing
|
|
16
|
+
// and convert them back to percentages when getting the item
|
|
17
|
+
export const panelStorage: PanelGroupStorage = {
|
|
18
|
+
getItem: (name) => {
|
|
19
|
+
const item = clientStorage.getItem(name);
|
|
20
|
+
|
|
21
|
+
if (item) {
|
|
22
|
+
const parsed = JSON.parse(item);
|
|
23
|
+
const percentageSize = mapWorkspaceLayoutState(parsed, (size) =>
|
|
24
|
+
toPercentageSize(size)
|
|
25
|
+
);
|
|
26
|
+
const stringified = JSON.stringify(percentageSize);
|
|
27
|
+
// console.log("getItem", name, stringified);
|
|
28
|
+
return stringified;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return item;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
setItem: (name, value) => {
|
|
35
|
+
const parsed = JSON.parse(value);
|
|
36
|
+
const pixelSize = mapWorkspaceLayoutState(parsed, (size) =>
|
|
37
|
+
toPixelSize(size)
|
|
38
|
+
);
|
|
39
|
+
// console.log("setItem", name, pixelSize);
|
|
40
|
+
clientStorage.setItem(name, JSON.stringify(pixelSize));
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const toPixelSize = (size: number, windowWidth = window.innerWidth) =>
|
|
45
|
+
Math.round((size * windowWidth) / 100);
|
|
46
|
+
export const toPercentageSize = (
|
|
47
|
+
size: number,
|
|
48
|
+
windowWidth = window.innerWidth
|
|
49
|
+
) => (size * 100) / windowWidth;
|
|
50
|
+
|
|
51
|
+
export function mapWorkspaceLayoutState(
|
|
52
|
+
layout: WorkspaceLayoutState,
|
|
53
|
+
f: (size: number) => number
|
|
54
|
+
): WorkspaceLayoutState {
|
|
55
|
+
return Object.fromEntries(
|
|
56
|
+
Object.entries(layout).map(
|
|
57
|
+
([key, value]): [string, WorkspaceLayoutGroup] => {
|
|
58
|
+
const expandToSizes = Object.fromEntries(
|
|
59
|
+
Object.entries(value.expandToSizes).map(([key, value]) => [
|
|
60
|
+
key,
|
|
61
|
+
f(value),
|
|
62
|
+
])
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
key,
|
|
67
|
+
{
|
|
68
|
+
expandToSizes,
|
|
69
|
+
layout: value.layout.map(f),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getLayoutIds({
|
|
78
|
+
hasLeftPanel,
|
|
79
|
+
hasRightPanel,
|
|
80
|
+
hasCenterPanel,
|
|
81
|
+
}: {
|
|
82
|
+
hasLeftPanel: boolean;
|
|
83
|
+
hasRightPanel: boolean;
|
|
84
|
+
hasCenterPanel: boolean;
|
|
85
|
+
}) {
|
|
86
|
+
return [
|
|
87
|
+
hasLeftPanel && LEFT_SIDEBAR_ID,
|
|
88
|
+
hasCenterPanel && CONTENT_AREA_ID,
|
|
89
|
+
hasRightPanel && RIGHT_SIDEBAR_ID,
|
|
90
|
+
].flatMap((id) => (id ? [id] : []));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getPropertyKey(layoutIds: string[]) {
|
|
94
|
+
return layoutIds.sort().join(",");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getStorageKey(autoSaveId: string) {
|
|
98
|
+
return `react-resizable-panels:${autoSaveId}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getInitialLayout({
|
|
102
|
+
layoutIds,
|
|
103
|
+
leftSidebarOptions,
|
|
104
|
+
rightSidebarOptions,
|
|
105
|
+
centerPanelPercentage,
|
|
106
|
+
hasLeftPanel,
|
|
107
|
+
hasRightPanel,
|
|
108
|
+
hasCenterPanel,
|
|
109
|
+
windowWidth = window.innerWidth,
|
|
110
|
+
}: {
|
|
111
|
+
layoutIds: string[];
|
|
112
|
+
leftSidebarOptions: PercentageSidebarOptions;
|
|
113
|
+
rightSidebarOptions: PercentageSidebarOptions;
|
|
114
|
+
centerPanelPercentage: number;
|
|
115
|
+
hasLeftPanel: boolean;
|
|
116
|
+
hasRightPanel: boolean;
|
|
117
|
+
hasCenterPanel: boolean;
|
|
118
|
+
windowWidth?: number;
|
|
119
|
+
}) {
|
|
120
|
+
return layoutIds.map((id) => {
|
|
121
|
+
if (id === LEFT_SIDEBAR_ID && hasLeftPanel) {
|
|
122
|
+
return leftSidebarOptions.defaultCollapsed
|
|
123
|
+
? 0
|
|
124
|
+
: toPixelSize(leftSidebarOptions.initialSize ?? 0, windowWidth);
|
|
125
|
+
} else if (id === RIGHT_SIDEBAR_ID && hasRightPanel) {
|
|
126
|
+
return rightSidebarOptions.defaultCollapsed
|
|
127
|
+
? 0
|
|
128
|
+
: toPixelSize(rightSidebarOptions.initialSize ?? 0, windowWidth);
|
|
129
|
+
} else if (id === CONTENT_AREA_ID && hasCenterPanel) {
|
|
130
|
+
const shouldShowLeftSidebar =
|
|
131
|
+
hasLeftPanel && !leftSidebarOptions.defaultCollapsed;
|
|
132
|
+
const shouldShowRightSidebar =
|
|
133
|
+
hasRightPanel && !rightSidebarOptions.defaultCollapsed;
|
|
134
|
+
|
|
135
|
+
if (!shouldShowLeftSidebar && !shouldShowRightSidebar) {
|
|
136
|
+
return toPixelSize(100, windowWidth);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return toPixelSize(centerPanelPercentage, windowWidth);
|
|
140
|
+
}
|
|
141
|
+
return 0;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function setInitialLayout({
|
|
146
|
+
storageKey,
|
|
147
|
+
propertyKey,
|
|
148
|
+
calculateLayout,
|
|
149
|
+
storage = clientStorage,
|
|
150
|
+
}: {
|
|
151
|
+
storageKey: string;
|
|
152
|
+
propertyKey: string;
|
|
153
|
+
calculateLayout: () => number[];
|
|
154
|
+
storage?: IClientStorage;
|
|
155
|
+
}) {
|
|
156
|
+
const savedLayout = storage.getItem(storageKey);
|
|
157
|
+
|
|
158
|
+
if (!savedLayout) {
|
|
159
|
+
const layoutObject: WorkspaceLayoutState = {
|
|
160
|
+
[propertyKey]: {
|
|
161
|
+
layout: calculateLayout(),
|
|
162
|
+
expandToSizes: {},
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
storage.setItem(storageKey, JSON.stringify(layoutObject));
|
|
167
|
+
} else {
|
|
168
|
+
let parsedLayout: WorkspaceLayoutState;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
parsedLayout = JSON.parse(savedLayout);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
console.error(error);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!(propertyKey in parsedLayout)) {
|
|
178
|
+
const layoutObject: WorkspaceLayoutState = {
|
|
179
|
+
...parsedLayout,
|
|
180
|
+
[propertyKey]: {
|
|
181
|
+
layout: calculateLayout(),
|
|
182
|
+
expandToSizes: {},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
storage.setItem(storageKey, JSON.stringify(layoutObject));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function getLayoutCollapsedState({
|
|
192
|
+
layoutGroup,
|
|
193
|
+
layoutIds,
|
|
194
|
+
hasLeftPanel,
|
|
195
|
+
hasRightPanel,
|
|
196
|
+
}: {
|
|
197
|
+
layoutGroup: WorkspaceLayoutGroup;
|
|
198
|
+
propertyKey: string;
|
|
199
|
+
layoutIds: string[];
|
|
200
|
+
hasLeftPanel: boolean;
|
|
201
|
+
hasRightPanel: boolean;
|
|
202
|
+
}) {
|
|
203
|
+
const propertySize = Object.fromEntries(
|
|
204
|
+
layoutIds.map((id, index) => [id, layoutGroup.layout?.[index]])
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const leftSize = propertySize?.[LEFT_SIDEBAR_ID];
|
|
208
|
+
const leftSidebarCollapsed = hasLeftPanel && leftSize === 0 ? true : false;
|
|
209
|
+
const rightSize = propertySize?.[RIGHT_SIDEBAR_ID];
|
|
210
|
+
const rightSidebarCollapsed = hasRightPanel && rightSize === 0 ? true : false;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
leftSidebarCollapsed,
|
|
214
|
+
rightSidebarCollapsed,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -12,6 +12,8 @@ export type PercentageSidebarOptions = {
|
|
|
12
12
|
maxSize?: number;
|
|
13
13
|
initialSize?: number;
|
|
14
14
|
resizable?: boolean;
|
|
15
|
+
defaultCollapsed?: boolean;
|
|
16
|
+
showTabs?: boolean;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export type PanelLayoutState = {
|
|
@@ -40,8 +42,13 @@ export type LayoutProps<
|
|
|
40
42
|
rightSidebarOptions: PercentageSidebarOptions;
|
|
41
43
|
centerPanelPercentage: number;
|
|
42
44
|
autoSavePrefix?: string;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rightSidebarRef: React.RefObject<SidebarRef>;
|
|
46
|
-
handleChangeLayoutState: (state: PanelLayoutState) => void;
|
|
45
|
+
leftSidebarRef: React.RefObject<SidebarRef | null>;
|
|
46
|
+
rightSidebarRef: React.RefObject<SidebarRef | null>;
|
|
47
47
|
};
|
|
48
|
+
|
|
49
|
+
export type WorkspaceLayoutGroup = {
|
|
50
|
+
expandToSizes: Record<string, number>;
|
|
51
|
+
layout: number[];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type WorkspaceLayoutState = Record<string, WorkspaceLayoutGroup>;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { getCurrentPlatform, PlatformName } from "@noya-app/noya-keymap";
|
|
2
4
|
import * as React from "react";
|
|
3
5
|
import { ToastProvider } from "../components/Toast";
|
|
4
6
|
import { DialogProvider } from "./DialogContext";
|
|
5
7
|
import { FloatingWindowProvider } from "./FloatingWindowContext";
|
|
8
|
+
import { LinkComponent, LinkComponentProvider } from "./LinkComponentContext";
|
|
6
9
|
import { OpenPortalsProvider } from "./OpenPortalsContext";
|
|
7
10
|
|
|
8
11
|
export type DesignSystemConfigurationContextValue = {
|
|
@@ -18,9 +21,11 @@ export const DesignSystemConfigurationProvider = React.memo(
|
|
|
18
21
|
function DesignSystemConfigurationProvider({
|
|
19
22
|
children,
|
|
20
23
|
platform,
|
|
24
|
+
LinkComponent,
|
|
21
25
|
}: {
|
|
22
26
|
children: React.ReactNode;
|
|
23
27
|
platform?: PlatformName;
|
|
28
|
+
LinkComponent?: LinkComponent;
|
|
24
29
|
}) {
|
|
25
30
|
const [internalPlatform, setInternalPlatform] =
|
|
26
31
|
React.useState<PlatformName>(platform ?? "key");
|
|
@@ -41,11 +46,13 @@ export const DesignSystemConfigurationProvider = React.memo(
|
|
|
41
46
|
return (
|
|
42
47
|
<DesignSystemConfigurationContext.Provider value={contextValue}>
|
|
43
48
|
<OpenPortalsProvider>
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
<LinkComponentProvider value={LinkComponent}>
|
|
50
|
+
<DialogProvider>
|
|
51
|
+
<ToastProvider>
|
|
52
|
+
<FloatingWindowProvider>{children}</FloatingWindowProvider>
|
|
53
|
+
</ToastProvider>
|
|
54
|
+
</DialogProvider>
|
|
55
|
+
</LinkComponentProvider>
|
|
49
56
|
</OpenPortalsProvider>
|
|
50
57
|
</DesignSystemConfigurationContext.Provider>
|
|
51
58
|
);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import React, {
|
|
2
4
|
createContext,
|
|
3
5
|
ReactNode,
|
|
@@ -26,12 +28,16 @@ function createDeferredPromise<T>() {
|
|
|
26
28
|
|
|
27
29
|
type RenderableProps = { close: () => void };
|
|
28
30
|
|
|
31
|
+
type ClosablePromise<T> = Promise<T> & {
|
|
32
|
+
close: () => void;
|
|
33
|
+
};
|
|
34
|
+
|
|
29
35
|
export type DialogContextValue = {
|
|
30
36
|
openDialog(
|
|
31
37
|
options: BaseDialogContents & {
|
|
32
38
|
children: ReactNode | ((props: RenderableProps) => ReactNode);
|
|
33
39
|
}
|
|
34
|
-
):
|
|
40
|
+
): ClosablePromise<void>;
|
|
35
41
|
|
|
36
42
|
openInputDialog(
|
|
37
43
|
options:
|
|
@@ -139,7 +145,11 @@ export const DialogProvider = function DialogProvider({
|
|
|
139
145
|
},
|
|
140
146
|
});
|
|
141
147
|
|
|
142
|
-
|
|
148
|
+
const closablePromise = Object.assign(promise, {
|
|
149
|
+
close: closeRef.current,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return closablePromise;
|
|
143
153
|
}, []);
|
|
144
154
|
|
|
145
155
|
const openConfirmation: DialogContextValue["openConfirmationDialog"] =
|
|
@@ -196,7 +206,11 @@ export const DialogProvider = function DialogProvider({
|
|
|
196
206
|
},
|
|
197
207
|
});
|
|
198
208
|
|
|
199
|
-
|
|
209
|
+
const closablePromise = Object.assign(promise, {
|
|
210
|
+
close: closeRef.current,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return closablePromise;
|
|
200
214
|
},
|
|
201
215
|
[]
|
|
202
216
|
);
|
|
@@ -269,7 +283,7 @@ export const DialogProvider = function DialogProvider({
|
|
|
269
283
|
)}
|
|
270
284
|
>
|
|
271
285
|
{contents?.type === "confirmation" ? (
|
|
272
|
-
<div className="flex flex-1 flex-row items-center">
|
|
286
|
+
<div className="n-flex n-flex-1 n-flex-row n-items-center">
|
|
273
287
|
<Spacer.Horizontal />
|
|
274
288
|
<Button
|
|
275
289
|
onClick={() => {
|
|
@@ -314,7 +328,7 @@ export const DialogProvider = function DialogProvider({
|
|
|
314
328
|
/>
|
|
315
329
|
</InputField.Root>
|
|
316
330
|
<Spacer.Vertical size={20} />
|
|
317
|
-
<div className="flex flex-1 flex-row items-center">
|
|
331
|
+
<div className="n-flex n-flex-1 n-flex-row n-items-center">
|
|
318
332
|
<Spacer.Horizontal />
|
|
319
333
|
<Button onClick={close}>Cancel</Button>
|
|
320
334
|
<Spacer.Horizontal size={16} />
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext } from "react";
|
|
4
|
+
|
|
5
|
+
export type LinkComponent = React.ComponentType<React.ComponentProps<"a">>;
|
|
6
|
+
|
|
7
|
+
const LinkComponentContext = createContext<LinkComponent | undefined>(
|
|
8
|
+
undefined
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export const LinkComponentProvider = LinkComponentContext.Provider;
|
|
12
|
+
|
|
13
|
+
export const useLinkComponent = () => {
|
|
14
|
+
const Link = useContext(LinkComponentContext);
|
|
15
|
+
|
|
16
|
+
return Link ?? "a";
|
|
17
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unique } from "@noya-app/noya-utils";
|
|
2
2
|
import { composeEventHandlers } from "@radix-ui/primitive";
|
|
3
3
|
|
|
4
|
-
function composeAllEventHandlers<E>(...handlers: ((e: E) => void)[]) {
|
|
4
|
+
function composeAllEventHandlers<E extends { defaultPrevented: boolean }>(...handlers: ((e: E) => void)[]) {
|
|
5
5
|
const [first, ...rest] = handlers;
|
|
6
6
|
|
|
7
7
|
return rest.reduce(
|