@noya-app/noya-designsystem 0.1.77 → 0.1.79
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 +20 -12
- package/CHANGELOG.md +15 -0
- package/dist/chunk-D57E6H3M.mjs +36 -0
- package/dist/chunk-D57E6H3M.mjs.map +1 -0
- package/dist/chunk-FJ6ZGZIA.mjs +43 -0
- package/dist/chunk-FJ6ZGZIA.mjs.map +1 -0
- package/dist/emojis.d.mts +1 -0
- package/dist/emojis.d.ts +1 -0
- package/dist/emojis.js +31 -0
- package/dist/emojis.js.map +1 -0
- package/dist/emojis.mjs +8 -0
- package/dist/emojis.mjs.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +142 -90
- package/dist/index.d.ts +142 -90
- package/dist/index.js +30559 -6412
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35081 -10928
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -17
- package/src/__tests__/__snapshots__/fuzzyScorer.test.ts.snap +1 -1
- package/src/components/Avatar.tsx +10 -10
- package/src/components/Banner.tsx +1 -1
- package/src/components/BaseToolbar.tsx +1 -1
- package/src/components/Button.tsx +2 -1
- package/src/components/Chip.tsx +1 -1
- package/src/components/ColorSwatchControl.tsx +22 -14
- package/src/components/CommandPalette.tsx +10 -6
- package/src/components/ContextMenu.tsx +249 -38
- package/src/components/Dialog.tsx +70 -67
- package/src/components/Drawer.tsx +56 -17
- package/src/components/DropdownMenu.tsx +305 -46
- package/src/components/EditableText.tsx +1 -1
- package/src/components/EmojiPicker.tsx +645 -0
- package/src/components/GridView.tsx +5 -1
- package/src/components/IVirtualizedList.tsx +21 -1
- package/src/components/InputField.tsx +2 -10
- package/src/components/InspectorContainer.tsx +4 -2
- package/src/components/Message.tsx +5 -16
- package/src/components/Popover.tsx +73 -107
- package/src/components/Progress.tsx +18 -18
- package/src/components/ScrollArea.tsx +66 -31
- package/src/components/ScrollableSidebar.tsx +1 -1
- package/src/components/SegmentedControl.tsx +166 -38
- package/src/components/SelectMenu.tsx +193 -101
- package/src/components/Slider.tsx +40 -38
- package/src/components/Switch.tsx +4 -4
- package/src/components/TextArea.tsx +1 -1
- package/src/components/Toast.tsx +99 -26
- package/src/components/Toolbar.tsx +114 -16
- package/src/components/Tooltip.tsx +18 -8
- package/src/components/Virtualized.tsx +193 -14
- package/src/components/VisuallyHidden.tsx +20 -0
- package/src/components/__tests__/Virtualized.math.test.ts +426 -1
- package/src/components/__tests__/Virtualized.test.tsx +129 -1
- package/src/components/ai-assistant/AIAssistantLayout.tsx +11 -6
- package/src/components/internal/Menu.tsx +4 -0
- package/src/components/listView/ListViewEditableRowTitle.tsx +1 -1
- package/src/components/listView/ListViewRoot.tsx +5 -1
- package/src/components/resizablePanels/Panel.tsx +94 -0
- package/src/components/resizablePanels/PanelGroup.tsx +498 -0
- package/src/components/resizablePanels/PanelGroupContext.tsx +14 -0
- package/src/components/resizablePanels/PanelResizeHandle.tsx +61 -0
- package/src/components/resizablePanels/index.ts +7 -0
- package/src/components/resizablePanels/types.ts +65 -0
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +22 -7
- package/src/components/workspace/PanelWorkspaceLayout.tsx +30 -84
- package/src/components/workspace/WorkspaceLayout.tsx +28 -58
- package/src/components/workspace/types.ts +6 -4
- package/src/contexts/DialogContext.tsx +15 -24
- package/src/emojis.ts +1 -0
- package/src/hooks/useTriggerToggle.ts +95 -0
- package/src/index.css +2 -0
- package/src/index.tsx +1 -2
- package/src/theme/proseTheme.ts +2 -0
- package/src/utils/mergeProps.ts +57 -0
- package/src/utils/skinTone.ts +90 -0
- package/tsup.config.ts +3 -1
- package/src/__tests__/workspaceLayout.test.ts +0 -281
- package/src/components/ScrollArea2.tsx +0 -76
- package/src/components/internal/MenuViewport.tsx +0 -178
- package/src/components/internal/SelectItem.tsx +0 -138
- 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 ??
|
|
141
|
+
allSelectableTabItems[0].tooltip ??
|
|
142
|
+
allSelectableTabItems[0].title
|
|
142
143
|
}
|
|
143
144
|
active={(() => {
|
|
144
|
-
const value = allSelectableTabItems[0].value as
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
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
|
-
|
|
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 "
|
|
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}--
|
|
46
|
+
? `${autoSavePrefix}--v3--${EDITOR_PANEL_GROUP_ID}`
|
|
66
47
|
: Math.random().toString(36).substring(2, 15);
|
|
67
48
|
}, [autoSavePrefix]);
|
|
68
49
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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>
|
|
@@ -22,8 +22,8 @@ import { PanelWorkspaceLayout } from "./PanelWorkspaceLayout";
|
|
|
22
22
|
import { renderPanelChildren } from "./renderPanelChildren";
|
|
23
23
|
import {
|
|
24
24
|
LayoutProps,
|
|
25
|
-
PercentageSidebarOptions,
|
|
26
25
|
RenderPanel,
|
|
26
|
+
SidebarOptions,
|
|
27
27
|
SidebarRef,
|
|
28
28
|
} from "./types";
|
|
29
29
|
import { WorkspaceSideProvider } from "./WorkspaceSideContext";
|
|
@@ -194,46 +194,22 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
194
194
|
? containerSize
|
|
195
195
|
: windowSize;
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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);
|
|
201
204
|
}
|
|
202
205
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
max: number | undefined
|
|
207
|
-
) {
|
|
208
|
-
let result = value;
|
|
209
|
-
if (min !== undefined) {
|
|
210
|
-
result = Math.max(result, min);
|
|
211
|
-
}
|
|
212
|
-
if (max !== undefined) {
|
|
213
|
-
result = Math.min(result, max);
|
|
214
|
-
}
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
206
|
+
const leftSidebarMinPixels = toPixels(leftMinSize);
|
|
207
|
+
const leftSidebarMaxPixels = toPixels(leftMaxSize);
|
|
208
|
+
const leftSidebarInitialPixels = toPixels(leftInitialSize) ?? 280;
|
|
217
209
|
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
rightMinSize !== undefined ? getPercentage(rightMinSize) : undefined;
|
|
222
|
-
const leftSidebarMaxPercentage =
|
|
223
|
-
leftMaxSize !== undefined ? getPercentage(leftMaxSize) : undefined;
|
|
224
|
-
const rightSidebarMaxPercentage =
|
|
225
|
-
rightMaxSize !== undefined ? getPercentage(rightMaxSize) : undefined;
|
|
226
|
-
|
|
227
|
-
const leftSidebarPercentage = clampPercentage(
|
|
228
|
-
getPercentage(leftInitialSize),
|
|
229
|
-
leftSidebarMinPercentage,
|
|
230
|
-
leftSidebarMaxPercentage
|
|
231
|
-
);
|
|
232
|
-
const rightSidebarPercentage = clampPercentage(
|
|
233
|
-
getPercentage(rightInitialSize),
|
|
234
|
-
rightSidebarMinPercentage,
|
|
235
|
-
rightSidebarMaxPercentage
|
|
236
|
-
);
|
|
210
|
+
const rightSidebarMinPixels = toPixels(rightMinSize);
|
|
211
|
+
const rightSidebarMaxPixels = toPixels(rightMaxSize);
|
|
212
|
+
const rightSidebarInitialPixels = toPixels(rightInitialSize) ?? 280;
|
|
237
213
|
|
|
238
214
|
const leftSidebarRef = useRef<SidebarRef>(null);
|
|
239
215
|
const rightSidebarRef = useRef<SidebarRef>(null);
|
|
@@ -313,11 +289,6 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
313
289
|
},
|
|
314
290
|
});
|
|
315
291
|
|
|
316
|
-
const centerPanelPercentage =
|
|
317
|
-
100 -
|
|
318
|
-
(left ? leftSidebarPercentage : 0) -
|
|
319
|
-
(right ? rightSidebarPercentage : 0);
|
|
320
|
-
|
|
321
292
|
const isDrawerActive =
|
|
322
293
|
sideType === "drawer" ||
|
|
323
294
|
(sideType === "auto" && parentSize.width <= sideTypeBreakpoint);
|
|
@@ -390,38 +361,38 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
390
361
|
<PanelInner className="n-bg-canvas-background">{children}</PanelInner>
|
|
391
362
|
);
|
|
392
363
|
|
|
393
|
-
const leftSidebarOptions:
|
|
364
|
+
const leftSidebarOptions: SidebarOptions = useMemo(
|
|
394
365
|
() => ({
|
|
395
|
-
minSize:
|
|
396
|
-
maxSize:
|
|
397
|
-
initialSize:
|
|
366
|
+
minSize: leftSidebarMinPixels,
|
|
367
|
+
maxSize: leftSidebarMaxPixels,
|
|
368
|
+
initialSize: leftSidebarInitialPixels,
|
|
398
369
|
resizable: leftResizable,
|
|
399
370
|
defaultCollapsed: leftDefaultCollapsed,
|
|
400
371
|
showTabs: leftShowTabs,
|
|
401
372
|
}),
|
|
402
373
|
[
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
374
|
+
leftSidebarMinPixels,
|
|
375
|
+
leftSidebarMaxPixels,
|
|
376
|
+
leftSidebarInitialPixels,
|
|
406
377
|
leftResizable,
|
|
407
378
|
leftDefaultCollapsed,
|
|
408
379
|
leftShowTabs,
|
|
409
380
|
]
|
|
410
381
|
);
|
|
411
382
|
|
|
412
|
-
const rightSidebarOptions:
|
|
383
|
+
const rightSidebarOptions: SidebarOptions = useMemo(
|
|
413
384
|
() => ({
|
|
414
|
-
minSize:
|
|
415
|
-
maxSize:
|
|
416
|
-
initialSize:
|
|
385
|
+
minSize: rightSidebarMinPixels,
|
|
386
|
+
maxSize: rightSidebarMaxPixels,
|
|
387
|
+
initialSize: rightSidebarInitialPixels,
|
|
417
388
|
resizable: rightResizable,
|
|
418
389
|
defaultCollapsed: rightDefaultCollapsed,
|
|
419
390
|
showTabs: rightShowTabs,
|
|
420
391
|
}),
|
|
421
392
|
[
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
393
|
+
rightSidebarMinPixels,
|
|
394
|
+
rightSidebarMaxPixels,
|
|
395
|
+
rightSidebarInitialPixels,
|
|
425
396
|
rightResizable,
|
|
426
397
|
rightDefaultCollapsed,
|
|
427
398
|
rightShowTabs,
|
|
@@ -476,7 +447,6 @@ export const WorkspaceLayout = forwardRefGeneric(function WorkspaceLayout<
|
|
|
476
447
|
onChangeRightTab={setRightTabValue}
|
|
477
448
|
leftSidebarOptions={leftSidebarOptions}
|
|
478
449
|
rightSidebarOptions={rightSidebarOptions}
|
|
479
|
-
centerPanelPercentage={centerPanelPercentage}
|
|
480
450
|
autoSavePrefix={autoSavePrefix}
|
|
481
451
|
leftSidebarRef={leftSidebarRef}
|
|
482
452
|
rightSidebarRef={rightSidebarRef}
|
|
@@ -7,7 +7,10 @@ export type SidebarRef = {
|
|
|
7
7
|
isExpanded: () => boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
|
|
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:
|
|
49
|
-
rightSidebarOptions:
|
|
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";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
interface UseTriggerToggleOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Called when an interaction outside the popup occurs.
|
|
6
|
+
* Return false to prevent the component from closing.
|
|
7
|
+
*/
|
|
8
|
+
shouldCloseOnInteractOutside?: (event: PointerEvent) => boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook that provides toggle behavior for trigger-based components (Popover, Drawer, etc.)
|
|
13
|
+
*
|
|
14
|
+
* When a component is open and the user clicks the trigger, this hook ensures:
|
|
15
|
+
* 1. The component closes (normal behavior)
|
|
16
|
+
* 2. The immediate reopen attempt from the same click is blocked
|
|
17
|
+
* 3. Subsequent clicks work normally
|
|
18
|
+
*
|
|
19
|
+
* @param isOpen - Whether the component is currently open
|
|
20
|
+
* @param setIsOpen - Function to update the open state
|
|
21
|
+
* @param options - Optional configuration
|
|
22
|
+
* @returns Object with anchorElement state, popupRef, and handleOpenChange
|
|
23
|
+
*/
|
|
24
|
+
export function useTriggerToggle(
|
|
25
|
+
isOpen: boolean,
|
|
26
|
+
setIsOpen: (open: boolean) => void,
|
|
27
|
+
options: UseTriggerToggleOptions = {}
|
|
28
|
+
) {
|
|
29
|
+
const { shouldCloseOnInteractOutside } = options;
|
|
30
|
+
|
|
31
|
+
const [anchorElement, setAnchorElement] = useState<Element | null>(null);
|
|
32
|
+
const popupRef = useRef<HTMLDivElement>(null);
|
|
33
|
+
// Track whether a close was just initiated (to prevent immediate reopen from same click)
|
|
34
|
+
const closeInitiatedRef = useRef(false);
|
|
35
|
+
// Track whether the next close should be prevented based on shouldCloseOnInteractOutside
|
|
36
|
+
const shouldPreventCloseRef = useRef(false);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!isOpen) return;
|
|
40
|
+
|
|
41
|
+
const handlePointerDown = (event: PointerEvent) => {
|
|
42
|
+
// Check if click is outside the popup content for shouldCloseOnInteractOutside
|
|
43
|
+
if (
|
|
44
|
+
popupRef.current &&
|
|
45
|
+
!popupRef.current.contains(event.target as Node)
|
|
46
|
+
) {
|
|
47
|
+
if (shouldCloseOnInteractOutside) {
|
|
48
|
+
const shouldClose = shouldCloseOnInteractOutside(event);
|
|
49
|
+
shouldPreventCloseRef.current = !shouldClose;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Use capture phase to intercept before Base UI's handler
|
|
55
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
56
|
+
|
|
57
|
+
return () => {
|
|
58
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
59
|
+
};
|
|
60
|
+
}, [isOpen, anchorElement, shouldCloseOnInteractOutside]);
|
|
61
|
+
|
|
62
|
+
const handleOpenChange = useCallback(
|
|
63
|
+
(newOpen: boolean) => {
|
|
64
|
+
// If closing and we should prevent it, skip
|
|
65
|
+
if (!newOpen && shouldPreventCloseRef.current) {
|
|
66
|
+
shouldPreventCloseRef.current = false;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// When closing, set flag and clear it on next macrotask
|
|
71
|
+
// This detects if open is called within the same event loop cycle (same click)
|
|
72
|
+
if (!newOpen) {
|
|
73
|
+
closeInitiatedRef.current = true;
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
closeInitiatedRef.current = false;
|
|
76
|
+
}, 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Block immediate reopen from the same click that closed the component
|
|
80
|
+
if (newOpen && closeInitiatedRef.current) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setIsOpen(newOpen);
|
|
85
|
+
},
|
|
86
|
+
[setIsOpen]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
anchorElement,
|
|
91
|
+
setAnchorElement,
|
|
92
|
+
popupRef,
|
|
93
|
+
handleOpenChange,
|
|
94
|
+
};
|
|
95
|
+
}
|
package/src/index.css
CHANGED
|
@@ -109,6 +109,8 @@
|
|
|
109
109
|
--n-inspector-v-separator: 10px;
|
|
110
110
|
--n-dialog-padding: 32px;
|
|
111
111
|
--n-input-height: 27px;
|
|
112
|
+
--n-input-padding-x: 8px;
|
|
113
|
+
--n-input-padding-y: 4px;
|
|
112
114
|
--n-icon: var(--n-indigo-300);
|
|
113
115
|
--n-icon-selected: rgb(220, 220, 220);
|
|
114
116
|
--n-warning: rgb(251, 211, 0);
|
package/src/index.tsx
CHANGED
|
@@ -26,6 +26,7 @@ export * from "./components/DraggableMenuButton";
|
|
|
26
26
|
export * from "./components/Drawer";
|
|
27
27
|
export * from "./components/DropdownMenu";
|
|
28
28
|
export * from "./components/EditableText";
|
|
29
|
+
export * from "./components/EmojiPicker";
|
|
29
30
|
export * from "./components/Fade";
|
|
30
31
|
export * from "./components/file-explorer/FileExplorerLayout";
|
|
31
32
|
export * from "./components/FileUploadIndicator";
|
|
@@ -43,7 +44,6 @@ export type {
|
|
|
43
44
|
MenuItem,
|
|
44
45
|
SelectableMenuItem,
|
|
45
46
|
} from "./components/internal/Menu";
|
|
46
|
-
export * from "./components/internal/MenuViewport";
|
|
47
47
|
export * from "./components/IVirtualizedList";
|
|
48
48
|
export * from "./components/Label";
|
|
49
49
|
export * from "./components/LabeledElementView";
|
|
@@ -63,7 +63,6 @@ export * from "./components/ResizableContainer";
|
|
|
63
63
|
export * from "./components/RingProgress";
|
|
64
64
|
export * from "./components/ScrollableSidebar";
|
|
65
65
|
export * from "./components/ScrollArea";
|
|
66
|
-
export * from "./components/ScrollArea2";
|
|
67
66
|
export * from "./components/SearchCompletionMenu";
|
|
68
67
|
export * from "./components/Section";
|
|
69
68
|
export * from "./components/SegmentedControl";
|
package/src/theme/proseTheme.ts
CHANGED
|
@@ -13,6 +13,8 @@ export const whiteboardProseTheme = (isDark: boolean) =>
|
|
|
13
13
|
"prose-li:n-m-0",
|
|
14
14
|
"prose-li:n-p-0",
|
|
15
15
|
"prose-a:n-text-inherit",
|
|
16
|
+
"prose-pre:n-my-1",
|
|
17
|
+
"prose-pre:n-text-inherit",
|
|
16
18
|
"prose-strong:n-text-inherit",
|
|
17
19
|
"prose-em:n-italic",
|
|
18
20
|
"prose-ol:n-list-inside",
|