@noya-app/noya-designsystem 0.1.48 → 0.1.50

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 (55) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +347 -173
  5. package/dist/index.d.ts +347 -173
  6. package/dist/index.js +3602 -2811
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +4761 -3993
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -5
  11. package/src/__tests__/validateDropIndicator.test.ts +4 -4
  12. package/src/components/ActionMenu.tsx +15 -4
  13. package/src/components/Avatar.tsx +2 -2
  14. package/src/components/Banner.tsx +29 -0
  15. package/src/components/BaseToolbar.tsx +2 -2
  16. package/src/components/Button.tsx +2 -2
  17. package/src/components/Checkbox.tsx +2 -2
  18. package/src/components/Chip.tsx +15 -14
  19. package/src/components/Collection.tsx +25 -2
  20. package/src/components/Combobox.tsx +22 -23
  21. package/src/components/ComboboxMenu.tsx +1 -1
  22. package/src/components/Dialog.tsx +2 -2
  23. package/src/components/DimensionInput.tsx +14 -12
  24. package/src/components/EditableText.tsx +3 -1
  25. package/src/components/FillInputField.tsx +2 -2
  26. package/src/components/Grid.tsx +131 -113
  27. package/src/components/GridView.tsx +36 -18
  28. package/src/components/InputField.tsx +116 -171
  29. package/src/components/Label.tsx +14 -73
  30. package/src/components/LabeledField.tsx +13 -2
  31. package/src/components/List.tsx +106 -47
  32. package/src/components/ListView.tsx +52 -31
  33. package/src/components/MediaThumbnail.tsx +14 -6
  34. package/src/components/Message.tsx +8 -8
  35. package/src/components/NoyaLogo.tsx +41 -0
  36. package/src/components/Popover.tsx +9 -6
  37. package/src/components/Section.tsx +172 -0
  38. package/src/components/SegmentedControl.tsx +1 -1
  39. package/src/components/SelectMenu.tsx +9 -4
  40. package/src/components/Slider.tsx +16 -7
  41. package/src/components/Sortable.tsx +186 -47
  42. package/src/components/UserPointer.tsx +1 -1
  43. package/src/components/ai-assistant/AIAssistantLayout.tsx +102 -0
  44. package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +71 -0
  45. package/src/components/file-explorer/FileExplorerLayout.tsx +71 -0
  46. package/src/components/internal/Menu.tsx +20 -10
  47. package/src/components/internal/SelectItem.tsx +3 -2
  48. package/src/components/pipeline/PipelineResultLayout.tsx +32 -0
  49. package/src/index.css +118 -112
  50. package/src/index.tsx +9 -0
  51. package/src/theme/index.ts +2 -0
  52. package/src/utils/classNames.ts +76 -3
  53. package/src/utils/inputs.ts +21 -0
  54. package/src/utils/moveTreeItem.ts +99 -0
  55. package/tailwind.config.ts +82 -75
@@ -65,8 +65,9 @@ export const SelectItem = React.forwardRef(
65
65
  testSelected && styles.testSelectedItemStyle
66
66
  )}
67
67
  >
68
+ <Spacer.Horizontal size={CHECKBOX_INDENT_WIDTH} />
68
69
  {Components.ItemIndicator && (
69
- <Components.ItemIndicator className={styles.itemIndicatorStyle}>
70
+ <Components.ItemIndicator {...styles.itemIndicator}>
70
71
  <CheckIcon />
71
72
  </Components.ItemIndicator>
72
73
  )}
@@ -107,7 +108,7 @@ export const SelectItem = React.forwardRef(
107
108
  <div className="flex flex-1 items-center">
108
109
  {indented && <Spacer.Horizontal size={CHECKBOX_INDENT_WIDTH} />}
109
110
  {checked ? (
110
- <div className={styles.itemIndicatorStyle}>
111
+ <div {...styles.itemIndicator}>
111
112
  <CheckIcon />
112
113
  </div>
113
114
  ) : indented ? (
@@ -0,0 +1,32 @@
1
+ import { Link1Icon } from "@noya-app/noya-icons";
2
+ import React from "react";
3
+ import { DividerVertical } from "../Divider";
4
+ import { Small } from "../Text";
5
+
6
+ export const PipelineResultLink = ({ url }: { url: string }) => {
7
+ return (
8
+ <div className="flex flex-col gap-0.5">
9
+ {/* <Label position="start">{name}</Label> */}
10
+ <a
11
+ href={url}
12
+ target="_blank"
13
+ rel="noopener noreferrer"
14
+ className="flex text-primary hover:opacity-80 border border-divider rounded-md"
15
+ >
16
+ <div className="flex gap-1 items-center p-2">
17
+ <Link1Icon className="w-[15px] h-[15px] flex-shrink-0" />
18
+ </div>
19
+ <DividerVertical />
20
+ <Small className="truncate p-2 flex-1">{url}</Small>
21
+ </a>
22
+ </div>
23
+ );
24
+ };
25
+
26
+ export const PipelineResultLayout = ({
27
+ children,
28
+ }: {
29
+ children: React.ReactNode;
30
+ }) => {
31
+ return <div className="flex flex-col gap-2">{children}</div>;
32
+ };
package/src/index.css CHANGED
@@ -3,119 +3,125 @@
3
3
  @tailwind utilities;
4
4
 
5
5
  :root {
6
- --logo-fill: rgb(150, 152, 172);
7
- --logo-highlight: rgb(150, 152, 172);
8
- --background: rgb(255, 255, 255);
9
- --text: rgb(38, 48, 83);
10
- --text-muted: rgb(107, 113, 136);
11
- --text-subtle: rgb(117, 121, 129);
12
- --text-disabled: rgb(150, 152, 172);
13
- --text-decorative-light: rgb(168, 185, 212);
14
- --divider-subtle: rgba(30, 50, 100, 0.04);
15
- --divider: rgba(30, 50, 100, 0.07);
16
- --divider-strong: rgba(30, 50, 100, 0.09);
17
- --primary: rgb(103, 70, 255);
18
- --primary-light: rgb(147, 86, 255);
19
- --primary-pastel: rgba(234, 230, 255);
20
- --secondary: rgb(0, 151, 117);
21
- --secondary-light: rgb(0, 160, 129);
22
- --secondary-pastel: rgb(205, 238, 231);
23
- --secondary-bright: #0ab557;
24
- --input-background: rgb(240, 242, 246);
25
- --input-background-light: rgb(243, 245, 249);
26
- --code-background: rgb(250, 250, 250);
27
- --code-background-dark: #435080;
28
- --selected-background: rgb(242, 245, 250);
29
- --breadcrumb-text: rgb(107, 113, 136);
30
- --breadcrumb-text-hover: rgb(117, 121, 129);
31
- --breadcrumb-icon: rgb(129, 131, 165);
32
- --canvas-background: rgb(249, 249, 249);
33
- --canvas-grid: rgba(0, 0, 0, 0.05);
34
- --sidebar-background: rgb(255, 255, 255);
35
- --sidebar-background-transparent: rgba(255, 255, 255, 0.85);
36
- --popover-background: rgb(252, 252, 252);
37
- --popover-divider: transparent;
38
- --listview-raised-background: rgba(0, 0, 0, 0.03);
39
- --listview-editing-background: #fff;
40
- --slider-thumb-background: white;
41
- --slider-border: #9698ac;
42
- --mask: rgb(12, 193, 67);
43
- --transparent-checker: rgba(255, 255, 255, 0.8);
44
- --scrollbar: rgba(199, 199, 199, 0.8);
45
- --placeholder-dots: rgba(0, 0, 0, 0.3);
46
- --drag-outline: rgb(103, 70, 255);
47
- --active-background: rgba(0, 0, 0, 0.1);
48
- --thumbnail-background: #f0efff;
49
- --thumbnail-shadow: #d3ceed66;
50
- --inline-code-text: rgb(103, 70, 255);
51
- --inline-code-background: rgb(240, 242, 246);
52
- --text-link: rgb(103, 70, 255);
53
- --text-link-focused: rgb(147, 86, 255);
54
- --inset-top: 46px;
55
- --sidebar-width: 260px;
56
- --toolbar-height: 46px;
57
- --toolbar-separator: 8px;
58
- --inspector-h-separator: 8px;
59
- --inspector-v-separator: 10px;
60
- --dialog-padding: 16px;
61
- --input-height: 27px;
62
- --icon: rgb(129, 131, 165);
63
- --icon-selected: rgb(220, 220, 220);
64
- --warning: rgb(251, 211, 0);
65
- --segmented-control-item: rgb(139, 139, 139);
66
- --dot: rgba(0, 0, 0, 0.25);
67
- --row-highlight: #3390ff10;
68
- --table-row-background: var(--background);
69
- --interactable-z-index: 2;
70
- --label-z-index: 3;
71
- --menu-z-index: 5000;
72
- --chip-primary-bg: rgba(238, 229, 255, 0.2);
73
- --chip-secondary-bg: rgba(205, 238, 231, 0.2);
74
- --chip-error-bg: rgba(255, 219, 219, 0.2);
75
- --chip-default-bg: rgba(0, 0, 0, 0.1);
76
- --chip-primary-shadow: rgb(238, 229, 255);
77
- --chip-secondary-shadow: rgb(205, 238, 231);
78
- --chip-error-shadow: rgb(255, 219, 219);
79
- --chip-default-shadow: rgb(0, 0, 0);
80
- --floating-button: rgb(248, 248, 250);
6
+ --n-logo-fill: rgb(150, 152, 172);
7
+ --n-logo-highlight: rgb(150, 152, 172);
8
+ --n-background: rgb(255, 255, 255);
9
+ --n-text: rgb(38, 48, 83);
10
+ --n-text-muted: rgb(107, 113, 136);
11
+ --n-text-subtle: rgb(117, 121, 129);
12
+ --n-text-disabled: rgb(150, 152, 172);
13
+ --n-text-decorative-light: rgb(168, 185, 212);
14
+ --n-divider-subtle: rgba(30, 50, 100, 0.04);
15
+ --n-divider: rgba(30, 50, 100, 0.07);
16
+ --n-divider-strong: rgba(30, 50, 100, 0.09);
17
+ --n-primary: rgb(103, 70, 255);
18
+ --n-primary-light: rgb(147, 86, 255);
19
+ --n-primary-pastel: rgba(234, 230, 255);
20
+ --n-secondary: rgb(0, 151, 117);
21
+ --n-secondary-light: rgb(0, 160, 129);
22
+ --n-secondary-pastel: rgb(205, 238, 231);
23
+ --n-secondary-bright: #0ab557;
24
+ --n-input-background-light: rgb(243, 245, 249);
25
+ --n-code-background: rgb(250, 250, 250);
26
+ --n-code-background-dark: #435080;
27
+ --n-selected-background: rgb(242, 245, 250);
28
+ --n-breadcrumb-text: rgb(107, 113, 136);
29
+ --n-breadcrumb-text-hover: rgb(117, 121, 129);
30
+ --n-breadcrumb-icon: rgb(129, 131, 165);
31
+ --n-canvas-background: rgb(249, 249, 249);
32
+ --n-canvas-grid: rgba(0, 0, 0, 0.05);
33
+ --n-sidebar-background: rgb(255, 255, 255);
34
+ --n-sidebar-background-transparent: rgba(255, 255, 255, 0.85);
35
+ --n-popover-background: rgb(252, 252, 252);
36
+ --n-popover-divider: transparent;
37
+ --n-listview-raised-background: rgba(0, 0, 0, 0.03);
38
+ --n-listview-editing-background: #fff;
39
+ --n-input-background: rgb(240, 242, 246);
40
+ --n-list-view-hover-background: rgb(244, 246, 250);
41
+ --n-list-view-thumbnail-background: var(--n-input-background);
42
+ --n-slider-thumb-background: white;
43
+ --n-slider-border: #9698ac;
44
+ --n-mask: rgb(12, 193, 67);
45
+ --n-transparent-checker: rgba(255, 255, 255, 0.8);
46
+ --n-scrollbar: rgba(199, 199, 199, 0.8);
47
+ --n-placeholder-dots: rgba(0, 0, 0, 0.3);
48
+ --n-drag-outline: rgb(103, 70, 255);
49
+ --n-active-background: rgba(0, 0, 0, 0.1);
50
+ --n-thumbnail-background: #f0efff;
51
+ --n-thumbnail-shadow: #d3ceed66;
52
+ --n-inline-code-text: rgb(103, 70, 255);
53
+ --n-inline-code-background: rgb(240, 242, 246);
54
+ --n-text-link: rgb(103, 70, 255);
55
+ --n-text-link-focused: rgb(147, 86, 255);
56
+ --n-inset-top: 46px;
57
+ --n-sidebar-width: 260px;
58
+ --n-toolbar-height: 46px;
59
+ --n-toolbar-separator: 8px;
60
+ --n-inspector-h-separator: 8px;
61
+ --n-inspector-v-separator: 10px;
62
+ --n-dialog-padding: 16px;
63
+ --n-input-height: 27px;
64
+ --n-icon: rgb(129, 131, 165);
65
+ --n-icon-selected: rgb(220, 220, 220);
66
+ --n-warning: rgb(251, 211, 0);
67
+ --n-segmented-control-item: rgb(139, 139, 139);
68
+ --n-dot: rgba(0, 0, 0, 0.25);
69
+ --n-row-highlight: #3390ff10;
70
+ --n-table-row-background: var(--n-background);
71
+ --n-interactable-z-index: 2;
72
+ --n-label-z-index: 3;
73
+ --n-menu-z-index: 5000;
74
+ --n-chip-primary-bg: rgba(238, 229, 255, 0.2);
75
+ --n-chip-secondary-bg: rgba(205, 238, 231, 0.2);
76
+ --n-chip-error-bg: rgba(255, 219, 219, 0.2);
77
+ --n-chip-default-bg: rgba(0, 0, 0, 0.1);
78
+ --n-chip-primary-shadow: rgb(238, 229, 255);
79
+ --n-chip-secondary-shadow: rgb(205, 238, 231);
80
+ --n-chip-error-shadow: rgb(255, 219, 219);
81
+ --n-chip-default-shadow: rgb(0, 0, 0);
82
+ --n-floating-button: rgb(248, 248, 250);
83
+ --n-block-border: rgb(184, 201, 218);
84
+ --n-block-highlight: rgb(255, 165, 0);
81
85
  }
82
86
 
83
87
  [data-theme="dark"] {
84
- --background: #111111;
85
- --logo-fill: rgb(248, 248, 250);
86
- --logo-highlight: rgb(248, 248, 250);
87
- --text: rgb(248, 248, 250);
88
- --text-muted: rgb(180, 179, 182);
89
- --text-subtle: rgb(180, 179, 182);
90
- --text-disabled: rgb(115, 114, 126);
91
- --divider-subtle: rgba(255, 255, 255, 0.04);
92
- --divider: rgba(255, 255, 255, 0.08);
93
- --divider-strong: rgba(0, 0, 0, 1);
94
- --primary: rgb(119, 66, 255);
95
- --primary-light: rgb(134, 86, 255);
96
- --secondary-bright: #36fe91;
97
- --input-background: rgba(181, 178, 255, 0.08);
98
- --input-background-light: rgba(181, 178, 255, 0.1);
99
- --code-background: rgb(20, 19, 23);
100
- --canvas-background: rgb(20, 19, 23);
101
- --canvas-grid: rgba(0, 0, 0, 0.1);
102
- --sidebar-background: rgb(34, 33, 39);
103
- --sidebar-background-transparent: rgba(34, 33, 39, 0.95);
104
- --popover-background: rgb(34, 33, 39);
105
- --popover-divider: rgba(255, 255, 255, 0.08);
106
- --listview-raised-background: rgba(181, 178, 255, 0.1);
107
- --listview-editing-background: #000;
108
- --slider-thumb-background: var(--input-background-light);
109
- --slider-border: var(--divider);
110
- --mask: rgb(102, 187, 106);
111
- --transparent-checker: rgba(255, 255, 255, 0.3);
112
- --scrollbar: rgba(199, 199, 199, 0.2);
113
- --placeholder-dots: rgba(255, 255, 255, 0.3);
114
- --drag-outline: white;
115
- --active-background: rgba(181, 178, 255, 0.08);
116
- --thumbnail-background: #1f1d33;
117
- --thumbnail-shadow: #1f1d3366;
118
- --dot: rgba(255, 255, 255, 0.15);
119
- --table-row-background: var(--sidebar-background);
120
- --floating-button: #333333;
88
+ --n-background: #111111;
89
+ --n-logo-fill: rgb(248, 248, 250);
90
+ --n-logo-highlight: rgb(248, 248, 250);
91
+ --n-text: rgb(248, 248, 250);
92
+ --n-text-muted: rgb(180, 179, 182);
93
+ --n-text-subtle: rgb(180, 179, 182);
94
+ --n-text-disabled: rgb(115, 114, 126);
95
+ --n-divider-subtle: rgba(255, 255, 255, 0.04);
96
+ --n-divider: rgba(255, 255, 255, 0.08);
97
+ --n-divider-strong: rgba(0, 0, 0, 1);
98
+ --n-primary: rgb(119, 66, 255);
99
+ --n-primary-light: rgb(134, 86, 255);
100
+ --n-secondary-bright: #36fe91;
101
+ --n-input-background: rgba(181, 178, 255, 0.08);
102
+ --n-input-background-light: rgba(181, 178, 255, 0.1);
103
+ --n-code-background: rgb(20, 19, 23);
104
+ --n-canvas-background: rgb(20, 19, 23);
105
+ --n-canvas-grid: rgba(0, 0, 0, 0.1);
106
+ --n-sidebar-background: rgb(34, 33, 39);
107
+ --n-sidebar-background-transparent: rgba(34, 33, 39, 0.95);
108
+ --n-popover-background: rgb(34, 33, 39);
109
+ --n-popover-divider: rgba(255, 255, 255, 0.08);
110
+ --n-listview-raised-background: rgba(181, 178, 255, 0.1);
111
+ --n-listview-editing-background: #000;
112
+ --n-list-view-hover-background: var(--n-input-background-light);
113
+ --n-list-view-thumbnail-background: var(--n-input-background);
114
+ --n-slider-thumb-background: var(--n-input-background-light);
115
+ --n-slider-border: var(--n-divider);
116
+ --n-mask: rgb(102, 187, 106);
117
+ --n-transparent-checker: rgba(255, 255, 255, 0.3);
118
+ --n-scrollbar: rgba(199, 199, 199, 0.2);
119
+ --n-placeholder-dots: rgba(255, 255, 255, 0.3);
120
+ --n-drag-outline: white;
121
+ --n-active-background: rgba(181, 178, 255, 0.08);
122
+ --n-thumbnail-background: #1f1d33;
123
+ --n-thumbnail-shadow: #1f1d3366;
124
+ --n-dot: rgba(255, 255, 255, 0.15);
125
+ --n-table-row-background: var(--n-sidebar-background);
126
+ --n-floating-button: #333333;
121
127
  }
package/src/index.tsx CHANGED
@@ -1,7 +1,10 @@
1
1
  // Components
2
+ export * from "./components/ActionMenu";
2
3
  export * from "./components/ActivityIndicator";
4
+ export * from "./components/ai-assistant/AIAssistantLayout";
3
5
  export * from "./components/AnimatePresence";
4
6
  export * from "./components/Avatar";
7
+ export * from "./components/Banner";
5
8
  export * from "./components/Breadcrumbs";
6
9
  export * from "./components/Button";
7
10
  export * from "./components/Checkbox";
@@ -10,6 +13,7 @@ export * from "./components/Collection";
10
13
  export * from "./components/Combobox";
11
14
  export * from "./components/ComboboxMenu";
12
15
  export * from "./components/CommandPalette";
16
+ export * from "./components/connected-users-menu/ConnectedUsersMenuLayout";
13
17
  export * from "./components/ContextMenu";
14
18
  export * from "./components/Dialog";
15
19
  export * from "./components/Divider";
@@ -18,6 +22,7 @@ export * from "./components/Drawer";
18
22
  export * from "./components/DropdownMenu";
19
23
  export * from "./components/EditableText";
20
24
  export * from "./components/Fade";
25
+ export * from "./components/file-explorer/FileExplorerLayout";
21
26
  export * from "./components/FillInputField";
22
27
  export * from "./components/FillPreviewBackground";
23
28
  export * from "./components/FloatingWindow";
@@ -42,10 +47,13 @@ export * from "./components/List";
42
47
  export * from "./components/ListView";
43
48
  export * from "./components/MediaThumbnail";
44
49
  export * from "./components/Message";
50
+ export * from "./components/NoyaLogo";
51
+ export * from "./components/pipeline/PipelineResultLayout";
45
52
  export * from "./components/Popover";
46
53
  export * from "./components/Progress";
47
54
  export * from "./components/ScrollArea";
48
55
  export * from "./components/SearchCompletionMenu";
56
+ export * from "./components/Section";
49
57
  export * from "./components/SegmentedControl";
50
58
  export * from "./components/SelectMenu";
51
59
  export * from "./components/Slider";
@@ -83,6 +91,7 @@ export * from "./utils/getGradientBackground";
83
91
  export * from "./utils/colorFromString";
84
92
  export * from "./utils/combobox";
85
93
  export * from "./utils/fuzzyScorer";
94
+ export * from "./utils/moveTreeItem";
86
95
  export * from "./utils/selection";
87
96
  export * from "./utils/sketchColor";
88
97
  export * from "./utils/sketchPattern";
@@ -6,3 +6,5 @@ export type Theme = (typeof tailwindConfig.theme)["extend"];
6
6
  export type ThemeColor = keyof Theme["colors"];
7
7
 
8
8
  export const cssVars = convertKebabToCamelCase(tailwindConfig.theme.extend);
9
+
10
+ export const INPUT_HEIGHT = 27;
@@ -1,5 +1,78 @@
1
- export function cx(
2
- ...args: Array<string | number | boolean | null | undefined>
3
- ): string {
1
+ import tailwindConfig from "../../tailwind.config";
2
+
3
+ type ClassNameItem = string | number | BigInt | boolean | null | undefined;
4
+ type Category = "text" | "color" | "font" | "flex";
5
+ type Options = {
6
+ categories?: Category[];
7
+ };
8
+
9
+ const colorKeys = Object.keys(tailwindConfig.theme.extend.colors).map(
10
+ (key) => `text-${key}`
11
+ );
12
+ const colorKeysSet = new Set(colorKeys);
13
+ const textKeys = Object.keys(tailwindConfig.theme.extend.fontSize).map(
14
+ (key) => `text-${key}`
15
+ );
16
+ const textKeysSet = new Set(textKeys);
17
+ const fontKeys = [
18
+ "thin",
19
+ "extralight",
20
+ "light",
21
+ "normal",
22
+ "medium",
23
+ "semibold",
24
+ "bold",
25
+ "extra-bold",
26
+ "black",
27
+ ].map((key) => `font-${key}`);
28
+ const fontKeysSet = new Set(fontKeys);
29
+ const flexKeysSet = new Set([
30
+ "flex-auto",
31
+ "flex-none",
32
+ "flex-[0_0_auto]",
33
+ "flex-1",
34
+ ]);
35
+
36
+ const keyMap: Record<Category, Set<string>> = {
37
+ text: textKeysSet,
38
+ flex: flexKeysSet,
39
+ color: colorKeysSet,
40
+ font: fontKeysSet,
41
+ };
42
+
43
+ export function cx(...args: ClassNameItem[]): string {
4
44
  return args.filter(Boolean).join(" ").trim();
5
45
  }
46
+
47
+ const filterLastClassNameInCategory = ({
48
+ classNames,
49
+ categoryKeys,
50
+ }: {
51
+ classNames: string[];
52
+ categoryKeys: Set<string>;
53
+ }) => {
54
+ const lastClassInGroup = classNames.findLast((key) => categoryKeys.has(key));
55
+ return classNames.flatMap((className) => {
56
+ if (categoryKeys.has(className)) {
57
+ return lastClassInGroup === className ? [className] : [];
58
+ }
59
+ return [className];
60
+ });
61
+ };
62
+
63
+ export function mergeConflictingClassNames(
64
+ classNames: ClassNameItem | ClassNameItem[],
65
+ options?: Options
66
+ ): string {
67
+ const classes = Array.isArray(classNames)
68
+ ? cx(...classNames)
69
+ : cx(classNames);
70
+ let classNamesList = classes.split(/\s+/);
71
+ options?.categories?.forEach((category) => {
72
+ classNamesList = filterLastClassNameInCategory({
73
+ classNames: classNamesList,
74
+ categoryKeys: keyMap[category],
75
+ });
76
+ });
77
+ return classNamesList.join(" ");
78
+ }
@@ -0,0 +1,21 @@
1
+ import { cx } from "./classNames";
2
+
3
+ export type InputSize = "small" | "medium" | "large";
4
+
5
+ const insetEndBaseStyles = "absolute inset-y-0 flex items-center z-label";
6
+
7
+ export const getInsetEndStyles = (size: InputSize = "medium") => {
8
+ return cx(
9
+ insetEndBaseStyles,
10
+ size === "large"
11
+ ? "right-2"
12
+ : size === "medium"
13
+ ? "right-1.5"
14
+ : size === "small"
15
+ ? "right-0.5"
16
+ : "",
17
+ size === "small" ? "min-h-[19px]" : "min-h-input-height"
18
+ );
19
+ };
20
+
21
+ export const startBaseStyles = "absolute left-1.5 inset-y-0 flex items-center";
@@ -0,0 +1,99 @@
1
+ import { isDeepEqual } from "@noya-app/noya-utils";
2
+ import {
3
+ defaultAcceptsDrop,
4
+ RelativeDropPosition,
5
+ } from "../components/Sortable";
6
+
7
+ type MoveOptions = {
8
+ indexPaths: number[][];
9
+ to: number[];
10
+ };
11
+
12
+ export type MoveTreeItemOptions<T> = {
13
+ root: T;
14
+ move: (root: T, options: MoveOptions) => T;
15
+ position: RelativeDropPosition;
16
+ sourceIndexPath: number[];
17
+ targetIndexPath: number[];
18
+ };
19
+
20
+ export function moveTreeItem<T>({
21
+ root,
22
+ move,
23
+ position,
24
+ sourceIndexPath,
25
+ targetIndexPath,
26
+ }: MoveTreeItemOptions<T>): T {
27
+ switch (position) {
28
+ case "above": {
29
+ return move(root, {
30
+ indexPaths: [sourceIndexPath],
31
+ to: targetIndexPath,
32
+ });
33
+ }
34
+ case "below": {
35
+ return move(root, {
36
+ indexPaths: [sourceIndexPath],
37
+ to: [...targetIndexPath.slice(0, -1), targetIndexPath.at(-1)! + 1],
38
+ });
39
+ }
40
+ case "inside": {
41
+ return move(root, {
42
+ indexPaths: [sourceIndexPath],
43
+ to: [...targetIndexPath, 1000],
44
+ });
45
+ }
46
+ }
47
+ }
48
+
49
+ export type AcceptsDropOptions = {
50
+ sourceIndexPath: number[];
51
+ targetIndexPath: number[];
52
+ position: RelativeDropPosition;
53
+
54
+ /**
55
+ * Whether to allow dropping the source item within the same parent as the target item.
56
+ */
57
+ allowSiblings: boolean;
58
+
59
+ /**
60
+ * Whether to allow dropping the source item within itself or one of its descendants.
61
+ */
62
+ allowRecursion: boolean;
63
+ };
64
+
65
+ export function acceptsDrop({
66
+ sourceIndexPath,
67
+ targetIndexPath,
68
+ position,
69
+ allowSiblings,
70
+ allowRecursion,
71
+ }: AcceptsDropOptions): boolean {
72
+ if (!allowRecursion) {
73
+ const targetIsDescendantOfSource = isDeepEqual(
74
+ sourceIndexPath,
75
+ targetIndexPath.slice(0, sourceIndexPath.length)
76
+ );
77
+
78
+ if (targetIsDescendantOfSource) return false;
79
+ }
80
+
81
+ const areSiblings = isDeepEqual(
82
+ sourceIndexPath.slice(0, -1),
83
+ targetIndexPath.slice(0, -1)
84
+ );
85
+
86
+ if (areSiblings && position !== "inside") {
87
+ if (!allowSiblings) {
88
+ return false;
89
+ }
90
+
91
+ return defaultAcceptsDrop(
92
+ sourceIndexPath.at(-1)!,
93
+ targetIndexPath.at(-1)!,
94
+ position
95
+ );
96
+ }
97
+
98
+ return true;
99
+ }