@noya-app/noya-designsystem 0.1.46 → 0.1.48

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 (42) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +16 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +208 -98
  5. package/dist/index.d.ts +208 -98
  6. package/dist/index.js +2148 -1604
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +2153 -1618
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -7
  11. package/src/__tests__/validateDropIndicator.test.ts +263 -0
  12. package/src/components/ActionMenu.tsx +40 -0
  13. package/src/components/ActivityIndicator.tsx +7 -1
  14. package/src/components/Collection.tsx +12 -2
  15. package/src/components/Combobox.tsx +14 -1
  16. package/src/components/ComboboxMenu.tsx +14 -5
  17. package/src/components/Dialog.tsx +28 -31
  18. package/src/components/Drawer.tsx +98 -0
  19. package/src/components/Grid.tsx +57 -27
  20. package/src/components/GridView.tsx +39 -25
  21. package/src/components/InputField.tsx +87 -92
  22. package/src/components/Label.tsx +7 -7
  23. package/src/components/List.tsx +42 -16
  24. package/src/components/ListView.tsx +21 -17
  25. package/src/components/MediaThumbnail.tsx +117 -0
  26. package/src/components/SearchCompletionMenu.tsx +31 -37
  27. package/src/components/SelectMenu.tsx +19 -17
  28. package/src/components/Sortable.tsx +70 -44
  29. package/src/components/Switch.tsx +1 -1
  30. package/src/components/internal/Menu.tsx +38 -23
  31. package/src/components/internal/MenuViewport.tsx +7 -1
  32. package/src/components/internal/SelectItem.tsx +51 -27
  33. package/src/components/internal/__tests__/Menu.test.tsx +12 -0
  34. package/src/components/workspace/DrawerWorkspaceLayout.tsx +86 -0
  35. package/src/components/workspace/PanelWorkspaceLayout.tsx +102 -0
  36. package/src/components/{WorkspaceLayout.tsx → workspace/WorkspaceLayout.tsx} +109 -106
  37. package/src/components/workspace/types.ts +31 -0
  38. package/src/contexts/DialogContext.tsx +91 -30
  39. package/src/hooks/usePreservePanelSize.tsx +1 -5
  40. package/src/index.css +3 -1
  41. package/src/index.tsx +4 -1
  42. package/tailwind.config.ts +1 -0
@@ -24,25 +24,26 @@ function createDeferredPromise<T>() {
24
24
  return { promise, resolve, reject };
25
25
  }
26
26
 
27
+ type RenderableProps = { close: () => void };
28
+
27
29
  export type DialogContextValue = {
30
+ openDialog(
31
+ options: BaseDialogContents & {
32
+ children: ReactNode | ((props: RenderableProps) => ReactNode);
33
+ }
34
+ ): Promise<void>;
35
+
28
36
  openInputDialog(
29
37
  options:
30
38
  | string
31
- | {
32
- title: string;
33
- description?: ReactNode;
39
+ | (BaseDialogContents & {
34
40
  placeholder?: string;
35
41
  initialValue?: string;
36
- }
42
+ })
37
43
  ): Promise<string | undefined>;
38
44
 
39
45
  openConfirmationDialog(
40
- options:
41
- | string
42
- | {
43
- title: string;
44
- description?: ReactNode;
45
- }
46
+ options: string | BaseDialogContents
46
47
  ): Promise<boolean>;
47
48
 
48
49
  containsElement(element: HTMLElement): boolean;
@@ -50,23 +51,35 @@ export type DialogContextValue = {
50
51
 
51
52
  const DialogContext = createContext<DialogContextValue | undefined>(undefined);
52
53
 
53
- type InputDialogContents = {
54
- type: "input";
54
+ type BaseDialogContents = {
55
+ style?: React.CSSProperties;
56
+ className?: string;
55
57
  title: string;
56
58
  description?: ReactNode;
59
+ };
60
+
61
+ type InputDialogContents = BaseDialogContents & {
62
+ type: "input";
57
63
  placeholder?: string;
58
64
  inputValue: string;
59
65
  resolve: (value: string | undefined) => void;
60
66
  };
61
67
 
62
- type ConfirmationDialogContents = {
68
+ type ConfirmationDialogContents = BaseDialogContents & {
63
69
  type: "confirmation";
64
- title: string;
65
- description?: ReactNode;
66
70
  resolve: (value: boolean) => void;
67
71
  };
68
72
 
69
- type DialogContents = InputDialogContents | ConfirmationDialogContents;
73
+ type CustomDialogContents = BaseDialogContents & {
74
+ type: "custom";
75
+ children: ReactNode;
76
+ resolve: () => void;
77
+ };
78
+
79
+ type DialogContents =
80
+ | InputDialogContents
81
+ | ConfirmationDialogContents
82
+ | CustomDialogContents;
70
83
 
71
84
  export const DialogProvider = function DialogProvider({
72
85
  children,
@@ -78,16 +91,20 @@ export const DialogProvider = function DialogProvider({
78
91
  const isOpen = !!contents;
79
92
 
80
93
  const close = useCallback(() => {
81
- if (!contents) return;
82
-
83
- if (contents.type === "input") {
84
- contents.resolve(undefined);
85
- } else {
86
- contents.resolve(false);
94
+ if (contents) {
95
+ if (contents.type === "input") {
96
+ contents.resolve(undefined);
97
+ } else {
98
+ contents.resolve(false);
99
+ }
87
100
  }
101
+
88
102
  setContents(undefined);
89
103
  }, [contents]);
90
104
 
105
+ const closeRef = useRef(close);
106
+ closeRef.current = close;
107
+
91
108
  const submit = useCallback(() => {
92
109
  if (!contents || contents.type !== "input") return;
93
110
 
@@ -98,7 +115,7 @@ export const DialogProvider = function DialogProvider({
98
115
  const open: DialogContextValue["openInputDialog"] = useCallback((options) => {
99
116
  const { promise, resolve } = createDeferredPromise<string | undefined>();
100
117
 
101
- const { title, description, initialValue, placeholder } =
118
+ const { title, description, initialValue, placeholder, style, className } =
102
119
  typeof options === "string" ? { title: options } : options;
103
120
 
104
121
  setContents({
@@ -107,6 +124,8 @@ export const DialogProvider = function DialogProvider({
107
124
  description,
108
125
  inputValue: initialValue ?? "",
109
126
  placeholder,
127
+ style,
128
+ className,
110
129
  resolve: (value: string | undefined) => {
111
130
  resolve(value);
112
131
  setContents(undefined);
@@ -120,13 +139,15 @@ export const DialogProvider = function DialogProvider({
120
139
  useCallback((options) => {
121
140
  const { promise, resolve } = createDeferredPromise<boolean>();
122
141
 
123
- const { title, description } =
142
+ const { title, description, style, className } =
124
143
  typeof options === "string" ? { title: options } : options;
125
144
 
126
145
  setContents({
127
146
  type: "confirmation",
128
147
  title,
129
148
  description,
149
+ style,
150
+ className,
130
151
  resolve: (value: boolean) => {
131
152
  resolve(value);
132
153
  setContents(undefined);
@@ -136,6 +157,35 @@ export const DialogProvider = function DialogProvider({
136
157
  return promise;
137
158
  }, []);
138
159
 
160
+ const openCustomDialog: DialogContextValue["openDialog"] = useCallback(
161
+ (options) => {
162
+ const { promise, resolve } = createDeferredPromise<void>();
163
+
164
+ const { title, description, style, className } = options;
165
+
166
+ const children =
167
+ typeof options.children === "function"
168
+ ? options.children({ close: closeRef.current })
169
+ : options.children;
170
+
171
+ setContents({
172
+ type: "custom",
173
+ title,
174
+ description,
175
+ style,
176
+ className,
177
+ children,
178
+ resolve: () => {
179
+ resolve();
180
+ setContents(undefined);
181
+ },
182
+ });
183
+
184
+ return promise;
185
+ },
186
+ []
187
+ );
188
+
139
189
  const handleKeyDown = useCallback(
140
190
  (event: React.KeyboardEvent<HTMLInputElement>) => {
141
191
  if (event.key !== "Enter") return;
@@ -162,11 +212,12 @@ export const DialogProvider = function DialogProvider({
162
212
  <DialogContext.Provider
163
213
  value={useMemo(
164
214
  () => ({
215
+ openDialog: openCustomDialog,
165
216
  openInputDialog: open,
166
217
  openConfirmationDialog: openConfirmation,
167
218
  containsElement,
168
219
  }),
169
- [containsElement, open, openConfirmation]
220
+ [containsElement, open, openConfirmation, openCustomDialog]
170
221
  )}
171
222
  >
172
223
  {children}
@@ -176,6 +227,8 @@ export const DialogProvider = function DialogProvider({
176
227
  title={contents?.title}
177
228
  description={contents?.description}
178
229
  open={isOpen}
230
+ style={contents?.style}
231
+ className={contents?.className}
179
232
  onOpenChange={useCallback(
180
233
  (isOpen: boolean) => {
181
234
  if (!isOpen) {
@@ -221,12 +274,16 @@ export const DialogProvider = function DialogProvider({
221
274
  OK
222
275
  </Button>
223
276
  </div>
277
+ ) : contents?.type === "custom" ? (
278
+ <>{contents.children}</>
224
279
  ) : (
225
280
  <>
226
281
  <InputField.Root>
227
282
  <InputField.Input
228
283
  ref={inputRef}
229
- placeholder={contents?.placeholder}
284
+ placeholder={
285
+ contents?.type === "input" ? contents.placeholder : undefined
286
+ }
230
287
  value={contents?.type === "input" ? contents.inputValue : ""}
231
288
  onChange={(value: string) => {
232
289
  setContents((contents) =>
@@ -262,7 +319,7 @@ export const DialogProvider = function DialogProvider({
262
319
  );
263
320
  };
264
321
 
265
- function useDialog(): DialogContextValue {
322
+ export function useDialogContext(): DialogContextValue {
266
323
  const value = useContext(DialogContext);
267
324
 
268
325
  if (!value) {
@@ -273,13 +330,17 @@ function useDialog(): DialogContextValue {
273
330
  }
274
331
 
275
332
  export function useOpenInputDialog() {
276
- return useDialog().openInputDialog;
333
+ return useDialogContext().openInputDialog;
277
334
  }
278
335
 
279
336
  export function useDialogContainsElement() {
280
- return useDialog().containsElement;
337
+ return useDialogContext().containsElement;
281
338
  }
282
339
 
283
340
  export function useOpenConfirmationDialog() {
284
- return useDialog().openConfirmationDialog;
341
+ return useDialogContext().openConfirmationDialog;
342
+ }
343
+
344
+ export function useOpenDialog() {
345
+ return useDialogContext().openDialog;
285
346
  }
@@ -1,5 +1,6 @@
1
1
  import React, { useLayoutEffect, useRef } from "react";
2
2
  import { ImperativePanelGroupHandle } from "react-resizable-panels";
3
+ import { PanelLayoutState } from "../components/workspace/types";
3
4
  import { useWindowSize } from "./useWindowSize";
4
5
 
5
6
  export const EDITOR_PANEL_GROUP_ID = "editor-panel-group";
@@ -7,11 +8,6 @@ export const LEFT_SIDEBAR_ID = "editor-left-sidebar";
7
8
  export const RIGHT_SIDEBAR_ID = "editor-right-sidebar";
8
9
  export const CONTENT_AREA_ID = "editor-content-area";
9
10
 
10
- export type PanelLayoutState = {
11
- leftSidebarCollapsed: boolean;
12
- rightSidebarCollapsed: boolean;
13
- };
14
-
15
11
  export function usePreservePanelSize(
16
12
  panelGroupRef: React.RefObject<ImperativePanelGroupHandle | null>,
17
13
  setPanelLayoutState?: (state: PanelLayoutState) => void
package/src/index.css CHANGED
@@ -58,6 +58,7 @@
58
58
  --inspector-h-separator: 8px;
59
59
  --inspector-v-separator: 10px;
60
60
  --dialog-padding: 16px;
61
+ --input-height: 27px;
61
62
  --icon: rgb(129, 131, 165);
62
63
  --icon-selected: rgb(220, 220, 220);
63
64
  --warning: rgb(251, 211, 0);
@@ -104,7 +105,8 @@
104
105
  --popover-divider: rgba(255, 255, 255, 0.08);
105
106
  --listview-raised-background: rgba(181, 178, 255, 0.1);
106
107
  --listview-editing-background: #000;
107
- --slider-thumb-background: rgb(248, 248, 250);
108
+ --slider-thumb-background: var(--input-background-light);
109
+ --slider-border: var(--divider);
108
110
  --mask: rgb(102, 187, 106);
109
111
  --transparent-checker: rgba(255, 255, 255, 0.3);
110
112
  --scrollbar: rgba(199, 199, 199, 0.2);
package/src/index.tsx CHANGED
@@ -14,6 +14,7 @@ export * from "./components/ContextMenu";
14
14
  export * from "./components/Dialog";
15
15
  export * from "./components/Divider";
16
16
  export * from "./components/DraggableMenuButton";
17
+ export * from "./components/Drawer";
17
18
  export * from "./components/DropdownMenu";
18
19
  export * from "./components/EditableText";
19
20
  export * from "./components/Fade";
@@ -39,6 +40,7 @@ export * from "./components/LabeledElementView";
39
40
  export * from "./components/LabeledField";
40
41
  export * from "./components/List";
41
42
  export * from "./components/ListView";
43
+ export * from "./components/MediaThumbnail";
42
44
  export * from "./components/Message";
43
45
  export * from "./components/Popover";
44
46
  export * from "./components/Progress";
@@ -57,7 +59,8 @@ export * from "./components/Toast";
57
59
  export * from "./components/Tooltip";
58
60
  export * from "./components/TreeView";
59
61
  export * from "./components/UserPointer";
60
- export * from "./components/WorkspaceLayout";
62
+ export * from "./components/workspace/types";
63
+ export * from "./components/workspace/WorkspaceLayout";
61
64
  // Contexts
62
65
  export * from "./contexts/DesignSystemConfiguration";
63
66
  export * from "./contexts/DialogContext";
@@ -189,6 +189,7 @@ const config = {
189
189
  "inspector-h-separator": "var(--inspector-h-separator)",
190
190
  "inspector-v-separator": "var(--inspector-v-separator)",
191
191
  "dialog-padding": "var(--dialog-padding)",
192
+ "input-height": "var(--input-height)",
192
193
  },
193
194
  keyframes: {
194
195
  spin: {