@noya-app/noya-designsystem 0.1.51 → 0.1.53
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 +10 -13
- package/CHANGELOG.md +17 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +307 -12
- package/dist/index.d.ts +307 -12
- package/dist/index.js +3408 -647
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3660 -908
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -9
- package/postcss.config.js +7 -0
- package/src/components/ActionMenu.tsx +8 -3
- package/src/components/Banner.tsx +2 -2
- package/src/components/BaseToolbar.tsx +6 -2
- package/src/components/Breadcrumbs.tsx +32 -2
- package/src/components/Button.tsx +30 -19
- package/src/components/Chip.tsx +3 -0
- package/src/components/ColorSwatch.tsx +42 -0
- package/src/components/ColorSwatchControl.tsx +90 -0
- package/src/components/ContextMenu.tsx +10 -2
- package/src/components/Dialog.tsx +1 -1
- package/src/components/DraggableMenuButton.tsx +17 -30
- package/src/components/DropdownMenu.tsx +7 -0
- package/src/components/FillInputField.tsx +1 -1
- package/src/components/Grid.tsx +11 -4
- package/src/components/GridView.tsx +1 -1
- package/src/components/LabeledField.tsx +4 -1
- package/src/components/List.tsx +12 -7
- package/src/components/ListView.tsx +7 -4
- package/src/components/MediaThumbnail.tsx +44 -10
- package/src/components/Popover.tsx +8 -1
- package/src/components/SegmentedControl.tsx +1 -1
- package/src/components/SelectMenu.tsx +7 -0
- package/src/components/SelectionToolbar.tsx +76 -0
- package/src/components/Switch.tsx +1 -1
- package/src/components/Text.tsx +2 -2
- package/src/components/Toast.tsx +13 -7
- package/src/components/Toolbar.tsx +78 -37
- package/src/components/Tooltip.tsx +11 -2
- package/src/components/catppuccin/fileIcons.ts +2430 -0
- package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +3 -1
- package/src/components/internal/Menu.tsx +6 -5
- package/src/components/internal/MenuViewport.tsx +11 -1
- package/src/components/pipeline/PipelineResultLayout.tsx +18 -0
- package/src/contexts/DialogContext.tsx +20 -5
- package/src/contexts/PortalScopeContext.tsx +48 -0
- package/src/index.css +101 -39
- package/src/index.tsx +4 -0
- package/src/theme/index.ts +6 -1
- package/src/theme/themeUtils.ts +10 -3
- package/src/utils/classNames.ts +3 -2
- package/src/utils/moveTreeItem.ts +4 -4
- package/tsup.config.ts +1 -1
|
@@ -38,7 +38,9 @@ export const ConnectedUsersMenuLayout = ({
|
|
|
38
38
|
}: ConnectedUsersMenuLayoutProps) => {
|
|
39
39
|
return (
|
|
40
40
|
<div className="flex gap-1.5">
|
|
41
|
-
<AvatarStack size={INPUT_HEIGHT}>
|
|
41
|
+
<AvatarStack size={INPUT_HEIGHT} className="mr-1">
|
|
42
|
+
{renderUsers()}
|
|
43
|
+
</AvatarStack>
|
|
42
44
|
|
|
43
45
|
{/* AI Assistant Avatar */}
|
|
44
46
|
{launchAIAssistant && (
|
|
@@ -92,9 +92,10 @@ export type SelectableMenuItem<T extends string> = BaseMenuItem & {
|
|
|
92
92
|
shortcut?: string;
|
|
93
93
|
value: T;
|
|
94
94
|
testSelected?: boolean;
|
|
95
|
+
tooltip?: ReactNode;
|
|
95
96
|
};
|
|
96
97
|
|
|
97
|
-
type SubMenuItem<T extends string> = BaseMenuItem & {
|
|
98
|
+
export type SubMenuItem<T extends string> = BaseMenuItem & {
|
|
98
99
|
type: "submenu";
|
|
99
100
|
items: MenuItem<T>[];
|
|
100
101
|
id: string;
|
|
@@ -164,12 +165,12 @@ export const CHECKBOX_INDENT_WIDTH = 6;
|
|
|
164
165
|
export const styles = {
|
|
165
166
|
separatorStyle: "h-px bg-divider mx-3 my-1",
|
|
166
167
|
selectedItemStyle:
|
|
167
|
-
"focus:outline-none focus:text-
|
|
168
|
-
testSelectedItemStyle:
|
|
168
|
+
"focus:outline-none focus:text-selected-list-item-text focus:bg-selected-list-item-background focus:kbd:text-selected-list-item-text",
|
|
169
|
+
testSelectedItemStyle:
|
|
170
|
+
"outline-none text-selected-list-item-text bg-selected-list-item-background kbd:text-selected-list-item-text",
|
|
169
171
|
itemStyle: ({ disabled }: { disabled?: boolean }) => `
|
|
170
172
|
flex-none select-none cursor-pointer rounded
|
|
171
173
|
py-1.5 px-2
|
|
172
|
-
active:bg-primary-light
|
|
173
174
|
transition-colors
|
|
174
175
|
flex items-center
|
|
175
176
|
font-sans text-button font-medium
|
|
@@ -182,7 +183,7 @@ export const styles = {
|
|
|
182
183
|
},
|
|
183
184
|
},
|
|
184
185
|
contentStyle:
|
|
185
|
-
"rounded bg-popover-background text-text shadow-
|
|
186
|
+
"rounded bg-popover-background text-text shadow-popover z-menu py-1",
|
|
186
187
|
};
|
|
187
188
|
|
|
188
189
|
function getKeyboardShortcuts<T extends string>(
|
|
@@ -2,7 +2,11 @@ import { ChevronRightIcon } from "@noya-app/noya-icons";
|
|
|
2
2
|
import * as RadixContextMenu from "@radix-ui/react-context-menu";
|
|
3
3
|
import * as RadixDropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
4
4
|
import React from "react";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
portalScopeProps,
|
|
7
|
+
usePortalScopeId,
|
|
8
|
+
} from "../../contexts/PortalScopeContext";
|
|
9
|
+
import { cx } from "../../utils/classNames";
|
|
6
10
|
import { MenuItem, SectionHeader, styles } from "./Menu";
|
|
7
11
|
import { SelectItem } from "./SelectItem";
|
|
8
12
|
|
|
@@ -59,6 +63,8 @@ export const MenuViewport = <T extends string>({
|
|
|
59
63
|
Components,
|
|
60
64
|
onSelect,
|
|
61
65
|
}: MenuViewportProps<T>) => {
|
|
66
|
+
const portalScopeId = usePortalScopeId();
|
|
67
|
+
|
|
62
68
|
const hasCheckedItem = items.some(
|
|
63
69
|
(item) =>
|
|
64
70
|
item.type !== "separator" && item.type !== "sectionHeader" && item.checked
|
|
@@ -105,6 +111,7 @@ export const MenuViewport = <T extends string>({
|
|
|
105
111
|
e.stopPropagation();
|
|
106
112
|
e.preventDefault();
|
|
107
113
|
}}
|
|
114
|
+
disabled={item.disabled}
|
|
108
115
|
>
|
|
109
116
|
<SelectItem
|
|
110
117
|
value={item.id}
|
|
@@ -113,6 +120,7 @@ export const MenuViewport = <T extends string>({
|
|
|
113
120
|
onSelect={onSelect}
|
|
114
121
|
Components={Components}
|
|
115
122
|
indented={hasCheckedItem}
|
|
123
|
+
disabled={item.disabled}
|
|
116
124
|
>
|
|
117
125
|
<div className="flex items-center flex-1">
|
|
118
126
|
{item.title}
|
|
@@ -122,6 +130,7 @@ export const MenuViewport = <T extends string>({
|
|
|
122
130
|
</Components.SubTrigger>
|
|
123
131
|
<Components.Portal>
|
|
124
132
|
<Components.SubContent
|
|
133
|
+
{...portalScopeProps(portalScopeId)}
|
|
125
134
|
alignOffset={-5}
|
|
126
135
|
className={styles.contentStyle}
|
|
127
136
|
>
|
|
@@ -147,6 +156,7 @@ export const MenuViewport = <T extends string>({
|
|
|
147
156
|
Components={Components}
|
|
148
157
|
indented={hasCheckedItem}
|
|
149
158
|
testSelected={item.testSelected}
|
|
159
|
+
disabled={item.disabled}
|
|
150
160
|
>
|
|
151
161
|
{item.title ?? item.value}
|
|
152
162
|
</SelectItem>
|
|
@@ -30,3 +30,21 @@ export const PipelineResultLayout = ({
|
|
|
30
30
|
}) => {
|
|
31
31
|
return <div className="flex flex-col gap-2">{children}</div>;
|
|
32
32
|
};
|
|
33
|
+
|
|
34
|
+
export function getPipelineResultLink(
|
|
35
|
+
value: unknown
|
|
36
|
+
): { url: string } | undefined {
|
|
37
|
+
if (typeof value !== "object" || value === null) return undefined;
|
|
38
|
+
|
|
39
|
+
// Check for htmlUrl first
|
|
40
|
+
if ("html_url" in value && typeof value.html_url === "string") {
|
|
41
|
+
return { url: value.html_url };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Fall back to regular url
|
|
45
|
+
if ("url" in value && typeof value.url === "string") {
|
|
46
|
+
return { url: value.url };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
@@ -43,7 +43,12 @@ export type DialogContextValue = {
|
|
|
43
43
|
): Promise<string | undefined>;
|
|
44
44
|
|
|
45
45
|
openConfirmationDialog(
|
|
46
|
-
options:
|
|
46
|
+
options:
|
|
47
|
+
| string
|
|
48
|
+
| (BaseDialogContents & {
|
|
49
|
+
confirmButtonLabel?: string;
|
|
50
|
+
cancelButtonLabel?: string;
|
|
51
|
+
})
|
|
47
52
|
): Promise<boolean>;
|
|
48
53
|
|
|
49
54
|
containsElement(element: HTMLElement): boolean;
|
|
@@ -67,6 +72,8 @@ type InputDialogContents = BaseDialogContents & {
|
|
|
67
72
|
|
|
68
73
|
type ConfirmationDialogContents = BaseDialogContents & {
|
|
69
74
|
type: "confirmation";
|
|
75
|
+
confirmButtonLabel?: string;
|
|
76
|
+
cancelButtonLabel?: string;
|
|
70
77
|
resolve: (value: boolean) => void;
|
|
71
78
|
};
|
|
72
79
|
|
|
@@ -139,13 +146,21 @@ export const DialogProvider = function DialogProvider({
|
|
|
139
146
|
useCallback((options) => {
|
|
140
147
|
const { promise, resolve } = createDeferredPromise<boolean>();
|
|
141
148
|
|
|
142
|
-
const {
|
|
143
|
-
|
|
149
|
+
const {
|
|
150
|
+
title,
|
|
151
|
+
description,
|
|
152
|
+
confirmButtonLabel,
|
|
153
|
+
cancelButtonLabel,
|
|
154
|
+
style,
|
|
155
|
+
className,
|
|
156
|
+
} = typeof options === "string" ? { title: options } : options;
|
|
144
157
|
|
|
145
158
|
setContents({
|
|
146
159
|
type: "confirmation",
|
|
147
160
|
title,
|
|
148
161
|
description,
|
|
162
|
+
confirmButtonLabel,
|
|
163
|
+
cancelButtonLabel,
|
|
149
164
|
style,
|
|
150
165
|
className,
|
|
151
166
|
resolve: (value: boolean) => {
|
|
@@ -262,7 +277,7 @@ export const DialogProvider = function DialogProvider({
|
|
|
262
277
|
setContents(undefined);
|
|
263
278
|
}}
|
|
264
279
|
>
|
|
265
|
-
Cancel
|
|
280
|
+
{contents.cancelButtonLabel ?? "Cancel"}
|
|
266
281
|
</Button>
|
|
267
282
|
<Spacer.Horizontal size={16} />
|
|
268
283
|
<Button
|
|
@@ -271,7 +286,7 @@ export const DialogProvider = function DialogProvider({
|
|
|
271
286
|
setContents(undefined);
|
|
272
287
|
}}
|
|
273
288
|
>
|
|
274
|
-
OK
|
|
289
|
+
{contents.confirmButtonLabel ?? "OK"}
|
|
275
290
|
</Button>
|
|
276
291
|
</div>
|
|
277
292
|
) : contents?.type === "custom" ? (
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export type PortalScopeContextValue = string;
|
|
4
|
+
|
|
5
|
+
const PortalScopeContext = React.createContext<
|
|
6
|
+
PortalScopeContextValue | undefined
|
|
7
|
+
>(undefined);
|
|
8
|
+
|
|
9
|
+
export const PortalScopeProvider = React.memo(function PortalScopeProvider({
|
|
10
|
+
children,
|
|
11
|
+
portalScopeId,
|
|
12
|
+
}: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
portalScopeId: string;
|
|
15
|
+
}) {
|
|
16
|
+
return (
|
|
17
|
+
<PortalScopeContext.Provider value={portalScopeId}>
|
|
18
|
+
{children}
|
|
19
|
+
</PortalScopeContext.Provider>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export function usePortalScopeId(): string {
|
|
24
|
+
return React.useContext(PortalScopeContext) ?? "";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const portalScopeDataSetName = "noyaPortalScope";
|
|
28
|
+
export const portalScopePropName = `data-noya-portal-scope`;
|
|
29
|
+
|
|
30
|
+
export function portalScopeProps(id?: string) {
|
|
31
|
+
return {
|
|
32
|
+
[portalScopePropName]: id,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getClosestPortalScope(element: EventTarget) {
|
|
37
|
+
if (!(element instanceof HTMLElement)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const closest = element.closest(`[${portalScopePropName}]`);
|
|
42
|
+
|
|
43
|
+
if (!closest || !(closest instanceof HTMLElement)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return closest.dataset[portalScopeDataSetName];
|
|
48
|
+
}
|
package/src/index.css
CHANGED
|
@@ -1,42 +1,61 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
1
|
:root {
|
|
6
|
-
--n-
|
|
7
|
-
--n-
|
|
8
|
-
--n-
|
|
9
|
-
--n-
|
|
10
|
-
--n-
|
|
11
|
-
--n-
|
|
12
|
-
--n-
|
|
13
|
-
--n-
|
|
14
|
-
--n-
|
|
15
|
-
|
|
16
|
-
--n-
|
|
17
|
-
--n-
|
|
18
|
-
--n-
|
|
19
|
-
--n-
|
|
2
|
+
--n-primary-900: rgb(45, 25, 95); /* dark: --n-primary-pastel */
|
|
3
|
+
--n-primary-600: rgb(103, 70, 255); /* --n-primary */
|
|
4
|
+
--n-primary-500: rgb(119, 66, 255); /* dark: --n-primary */
|
|
5
|
+
--n-primary-400: rgb(147, 86, 255); /* --n-primary-light */
|
|
6
|
+
--n-primary-300: rgb(134, 86, 255); /* dark: --n-primary-light */
|
|
7
|
+
--n-primary-250: rgb(171, 137, 251);
|
|
8
|
+
--n-primary-200: rgb(188, 160, 255);
|
|
9
|
+
--n-primary-150: rgb(225, 219, 255);
|
|
10
|
+
--n-primary-100: rgb(234, 230, 255); /* --n-primary-pastel */
|
|
11
|
+
|
|
12
|
+
--n-indigo-950: rgb(18, 26, 37);
|
|
13
|
+
--n-indigo-900: rgb(30, 40, 60);
|
|
14
|
+
--n-indigo-800: rgb(38, 48, 83);
|
|
15
|
+
--n-indigo-700: rgb(55, 65, 99);
|
|
16
|
+
--n-indigo-600: rgb(76, 86, 122);
|
|
17
|
+
--n-indigo-500: rgb(107, 113, 136);
|
|
18
|
+
--n-indigo-400: rgb(117, 121, 129);
|
|
19
|
+
--n-indigo-300: rgb(129, 131, 165);
|
|
20
|
+
--n-indigo-200: rgb(150, 152, 172);
|
|
21
|
+
--n-indigo-150: rgb(226, 230, 238);
|
|
22
|
+
--n-indigo-100: rgb(240, 242, 246);
|
|
23
|
+
--n-indigo-50: rgb(243, 245, 249);
|
|
24
|
+
--n-indigo-25: rgb(251, 252, 254);
|
|
25
|
+
|
|
26
|
+
--n-logo-fill: var(--n-indigo-200);
|
|
27
|
+
--n-logo-highlight: var(--n-indigo-200);
|
|
28
|
+
--n-background: white;
|
|
29
|
+
--n-text: var(--n-indigo-800);
|
|
30
|
+
--n-text-muted: var(--n-indigo-500);
|
|
31
|
+
--n-text-subtle: var(--n-indigo-400);
|
|
32
|
+
--n-text-disabled: var(--n-indigo-200);
|
|
33
|
+
--n-text-decorative-light: var(--n-indigo-100);
|
|
34
|
+
--n-divider-subtle: color-mix(in srgb, var(--n-indigo-900) 4%, transparent);
|
|
35
|
+
--n-divider: color-mix(in srgb, var(--n-indigo-900) 7%, transparent);
|
|
36
|
+
--n-divider-strong: color-mix(in srgb, var(--n-indigo-900) 9%, transparent);
|
|
37
|
+
--n-primary: var(--n-primary-600);
|
|
38
|
+
--n-primary-light: var(--n-primary-400);
|
|
39
|
+
--n-primary-pastel: var(--n-primary-100);
|
|
20
40
|
--n-secondary: rgb(0, 151, 117);
|
|
21
41
|
--n-secondary-light: rgb(0, 160, 129);
|
|
22
42
|
--n-secondary-pastel: rgb(205, 238, 231);
|
|
23
43
|
--n-secondary-bright: #0ab557;
|
|
24
44
|
--n-input-background-light: rgb(243, 245, 249);
|
|
25
45
|
--n-code-background: rgb(250, 250, 250);
|
|
26
|
-
--n-code-background-dark:
|
|
46
|
+
--n-code-background-dark: var(--n-indigo-950);
|
|
27
47
|
--n-selected-background: rgb(242, 245, 250);
|
|
28
|
-
--n-breadcrumb-text:
|
|
29
|
-
--n-breadcrumb-text-hover:
|
|
30
|
-
--n-breadcrumb-icon:
|
|
31
|
-
--n-canvas-background:
|
|
48
|
+
--n-breadcrumb-text: var(--n-indigo-500);
|
|
49
|
+
--n-breadcrumb-text-hover: var(--n-indigo-400);
|
|
50
|
+
--n-breadcrumb-icon: var(--n-indigo-300);
|
|
51
|
+
--n-canvas-background: var(--n-indigo-25);
|
|
32
52
|
--n-canvas-grid: rgba(0, 0, 0, 0.05);
|
|
33
53
|
--n-sidebar-background: rgb(255, 255, 255);
|
|
34
|
-
--n-sidebar-background-transparent: rgba(255, 255, 255, 0.85);
|
|
35
54
|
--n-popover-background: rgb(252, 252, 252);
|
|
36
55
|
--n-popover-divider: transparent;
|
|
37
56
|
--n-listview-raised-background: rgba(0, 0, 0, 0.03);
|
|
38
57
|
--n-listview-editing-background: #fff;
|
|
39
|
-
--n-input-background:
|
|
58
|
+
--n-input-background: var(--n-indigo-100);
|
|
40
59
|
--n-list-view-hover-background: rgb(244, 246, 250);
|
|
41
60
|
--n-list-view-thumbnail-background: var(--n-input-background);
|
|
42
61
|
--n-slider-thumb-background: white;
|
|
@@ -45,14 +64,14 @@
|
|
|
45
64
|
--n-transparent-checker: rgba(255, 255, 255, 0.8);
|
|
46
65
|
--n-scrollbar: rgba(199, 199, 199, 0.8);
|
|
47
66
|
--n-placeholder-dots: rgba(0, 0, 0, 0.3);
|
|
48
|
-
--n-drag-outline:
|
|
49
|
-
--n-active-background:
|
|
67
|
+
--n-drag-outline: var(--n-primary-600);
|
|
68
|
+
--n-active-background: var(--n-indigo-150);
|
|
50
69
|
--n-thumbnail-background: #f0efff;
|
|
51
70
|
--n-thumbnail-shadow: #d3ceed66;
|
|
52
|
-
--n-inline-code-text:
|
|
71
|
+
--n-inline-code-text: var(--n-primary-600);
|
|
53
72
|
--n-inline-code-background: rgb(240, 242, 246);
|
|
54
|
-
--n-text-link:
|
|
55
|
-
--n-text-link-focused:
|
|
73
|
+
--n-text-link: var(--n-primary-600);
|
|
74
|
+
--n-text-link-focused: var(--n-primary-400);
|
|
56
75
|
--n-inset-top: 46px;
|
|
57
76
|
--n-sidebar-width: 260px;
|
|
58
77
|
--n-toolbar-height: 46px;
|
|
@@ -61,7 +80,7 @@
|
|
|
61
80
|
--n-inspector-v-separator: 10px;
|
|
62
81
|
--n-dialog-padding: 16px;
|
|
63
82
|
--n-input-height: 27px;
|
|
64
|
-
--n-icon:
|
|
83
|
+
--n-icon: var(--n-indigo-300);
|
|
65
84
|
--n-icon-selected: rgb(220, 220, 220);
|
|
66
85
|
--n-warning: rgb(251, 211, 0);
|
|
67
86
|
--n-segmented-control-item: rgb(139, 139, 139);
|
|
@@ -82,7 +101,26 @@
|
|
|
82
101
|
--n-floating-button: rgb(248, 248, 250);
|
|
83
102
|
--n-block-border: rgb(184, 201, 218);
|
|
84
103
|
--n-block-highlight: rgb(255, 165, 0);
|
|
85
|
-
--n-
|
|
104
|
+
--n-markdown-editor-line-placeholder-content: "Write or press / for commands";
|
|
105
|
+
--n-selected-list-item-background: var(--n-primary-100);
|
|
106
|
+
--n-selected-list-item-text: var(--n-primary);
|
|
107
|
+
--n-selected-list-item-icon-background: var(--n-primary-150);
|
|
108
|
+
/* based on vs code light theme: https://github.com/fsegurai/codemirror-themes/blob/main/packages/vscode-light/src/index.ts */
|
|
109
|
+
--n-cm-keyword: var(--n-primary-600);
|
|
110
|
+
--n-cm-function: #1b4db8;
|
|
111
|
+
--n-cm-control-keyword: var(--n-primary-600);
|
|
112
|
+
--n-cm-class-type: #1b4db8;
|
|
113
|
+
--n-cm-regexp: #1097af;
|
|
114
|
+
--n-cm-link: #1097af;
|
|
115
|
+
--n-cm-string: #1097af;
|
|
116
|
+
--n-cm-number: #1097af;
|
|
117
|
+
--n-cm-comment: var(--n-indigo-300);
|
|
118
|
+
--n-cm-operator: var(--n-indigo-800);
|
|
119
|
+
--n-cm-variable: var(--n-indigo-800);
|
|
120
|
+
--n-cm-type: #f59e0b;
|
|
121
|
+
--n-cm-error: #e45649;
|
|
122
|
+
--n-cm-warning: #fb9d00;
|
|
123
|
+
--n-cm-info: #3390ff;
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
[data-theme="dark"] {
|
|
@@ -96,8 +134,11 @@
|
|
|
96
134
|
--n-divider-subtle: rgba(255, 255, 255, 0.04);
|
|
97
135
|
--n-divider: rgba(255, 255, 255, 0.08);
|
|
98
136
|
--n-divider-strong: rgba(0, 0, 0, 1);
|
|
99
|
-
--n-primary:
|
|
100
|
-
--n-primary-light:
|
|
137
|
+
--n-primary: var(--n-primary-500);
|
|
138
|
+
--n-primary-light: var(--n-primary-300);
|
|
139
|
+
--n-selected-list-item-background: var(--n-primary-900);
|
|
140
|
+
--n-selected-list-item-text: var(--n-primary-200);
|
|
141
|
+
--n-selected-list-item-icon-background: var(--n-primary-900);
|
|
101
142
|
--n-secondary-bright: #36fe91;
|
|
102
143
|
--n-input-background: rgba(181, 178, 255, 0.08);
|
|
103
144
|
--n-input-background-light: rgba(181, 178, 255, 0.1);
|
|
@@ -105,7 +146,6 @@
|
|
|
105
146
|
--n-canvas-background: rgb(20, 19, 23);
|
|
106
147
|
--n-canvas-grid: rgba(0, 0, 0, 0.1);
|
|
107
148
|
--n-sidebar-background: rgb(34, 33, 39);
|
|
108
|
-
--n-sidebar-background-transparent: rgba(34, 33, 39, 0.95);
|
|
109
149
|
--n-popover-background: rgb(34, 33, 39);
|
|
110
150
|
--n-popover-divider: rgba(255, 255, 255, 0.08);
|
|
111
151
|
--n-listview-raised-background: rgba(181, 178, 255, 0.1);
|
|
@@ -125,10 +165,32 @@
|
|
|
125
165
|
--n-dot: rgba(255, 255, 255, 0.15);
|
|
126
166
|
--n-table-row-background: var(--n-sidebar-background);
|
|
127
167
|
--n-floating-button: #333333;
|
|
168
|
+
/* based on vs code dark theme: https://github.com/fsegurai/codemirror-themes/blob/main/packages/vscode-dark/src/index.ts */
|
|
169
|
+
--n-cm-keyword: #569cd6;
|
|
170
|
+
--n-cm-function: #dcdcaa;
|
|
171
|
+
--n-cm-control-keyword: #c586c0;
|
|
172
|
+
--n-cm-class-type: #4ec9b0;
|
|
173
|
+
--n-cm-regexp: #d16969;
|
|
174
|
+
--n-cm-link: #4078f2;
|
|
175
|
+
--n-cm-string: #ce9178;
|
|
176
|
+
--n-cm-number: #b5cea8;
|
|
177
|
+
--n-cm-comment: #6a9955;
|
|
178
|
+
--n-cm-operator: #d4d4d4;
|
|
179
|
+
--n-cm-variable: #9cdcfe;
|
|
180
|
+
--n-cm-type: #f59e0b;
|
|
181
|
+
--n-cm-error: #ff0000;
|
|
182
|
+
--n-cm-warning: #fb9d00;
|
|
183
|
+
--n-cm-info: #3390ff;
|
|
128
184
|
}
|
|
129
185
|
|
|
130
|
-
.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
186
|
+
.noya-styles {
|
|
187
|
+
@tailwind base;
|
|
188
|
+
@tailwind components;
|
|
189
|
+
@tailwind utilities;
|
|
190
|
+
|
|
191
|
+
.markdown-editor-line-placeholder::after {
|
|
192
|
+
content: var(--n-markdown-editor-line-placeholder-content);
|
|
193
|
+
color: var(--n-text-disabled);
|
|
194
|
+
pointer-events: none;
|
|
195
|
+
}
|
|
134
196
|
}
|
package/src/index.tsx
CHANGED
|
@@ -10,6 +10,8 @@ export * from "./components/Button";
|
|
|
10
10
|
export * from "./components/Checkbox";
|
|
11
11
|
export * from "./components/Chip";
|
|
12
12
|
export * from "./components/Collection";
|
|
13
|
+
export * from "./components/ColorSwatch";
|
|
14
|
+
export * from "./components/ColorSwatchControl";
|
|
13
15
|
export * from "./components/Combobox";
|
|
14
16
|
export * from "./components/ComboboxMenu";
|
|
15
17
|
export * from "./components/CommandPalette";
|
|
@@ -55,6 +57,7 @@ export * from "./components/ScrollArea";
|
|
|
55
57
|
export * from "./components/SearchCompletionMenu";
|
|
56
58
|
export * from "./components/Section";
|
|
57
59
|
export * from "./components/SegmentedControl";
|
|
60
|
+
export * from "./components/SelectionToolbar";
|
|
58
61
|
export * from "./components/SelectMenu";
|
|
59
62
|
export * from "./components/Slider";
|
|
60
63
|
export * from "./components/Sortable";
|
|
@@ -75,6 +78,7 @@ export * from "./contexts/DialogContext";
|
|
|
75
78
|
export * from "./contexts/FloatingWindowContext";
|
|
76
79
|
export * from "./contexts/GlobalInputBlurContext";
|
|
77
80
|
export * from "./contexts/ImageDataContext";
|
|
81
|
+
export * from "./contexts/PortalScopeContext";
|
|
78
82
|
// Hooks
|
|
79
83
|
export * from "./hooks/useHover";
|
|
80
84
|
export * from "./hooks/useIndent";
|
package/src/theme/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import tailwindConfig from "@noya-app/noya-tailwind-config";
|
|
2
|
-
import { convertKebabToCamelCase } from "./themeUtils";
|
|
2
|
+
import { convertKebabToCamelCase, parseCssVarName } from "./themeUtils";
|
|
3
3
|
|
|
4
4
|
export type Theme = (typeof tailwindConfig.theme)["extend"];
|
|
5
5
|
|
|
@@ -7,4 +7,9 @@ export type ThemeColor = keyof Theme["colors"];
|
|
|
7
7
|
|
|
8
8
|
export const cssVars = convertKebabToCamelCase(tailwindConfig.theme.extend);
|
|
9
9
|
|
|
10
|
+
export const cssVarNames = convertKebabToCamelCase(
|
|
11
|
+
tailwindConfig.theme.extend,
|
|
12
|
+
parseCssVarName
|
|
13
|
+
);
|
|
14
|
+
|
|
10
15
|
export const INPUT_HEIGHT = 27;
|
package/src/theme/themeUtils.ts
CHANGED
|
@@ -48,7 +48,8 @@ export function kebabToCamelCase<S extends string>(
|
|
|
48
48
|
|
|
49
49
|
// Runtime function to convert all keys in an object from kebab-case to camelCase
|
|
50
50
|
export function convertKebabToCamelCase<T extends object>(
|
|
51
|
-
obj: T
|
|
51
|
+
obj: T,
|
|
52
|
+
mapValue?: (value: string) => string
|
|
52
53
|
): KebabToCamelCaseKeys<T> {
|
|
53
54
|
if (Array.isArray(obj) || obj instanceof Set || obj instanceof Map) {
|
|
54
55
|
return obj as KebabToCamelCaseKeys<T>;
|
|
@@ -64,9 +65,15 @@ export function convertKebabToCamelCase<T extends object>(
|
|
|
64
65
|
!Array.isArray(value) &&
|
|
65
66
|
!(value instanceof Set) &&
|
|
66
67
|
!(value instanceof Map)
|
|
67
|
-
? convertKebabToCamelCase(value)
|
|
68
|
-
: value
|
|
68
|
+
? convertKebabToCamelCase(value, mapValue)
|
|
69
|
+
: mapValue && typeof value === "string"
|
|
70
|
+
? mapValue(value)
|
|
71
|
+
: value;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
return result as KebabToCamelCaseKeys<T>;
|
|
72
75
|
}
|
|
76
|
+
|
|
77
|
+
export function parseCssVarName(key: string) {
|
|
78
|
+
return key.match(/var\((--.*?)\)/)?.[1] ?? "";
|
|
79
|
+
}
|
package/src/utils/classNames.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import tailwindConfig from "@noya-app/noya-tailwind-config";
|
|
2
2
|
|
|
3
3
|
type ClassNameItem = string | number | BigInt | boolean | null | undefined;
|
|
4
|
-
type Category = "text" | "color" | "font" | "flex";
|
|
4
|
+
type Category = "text" | "color" | "font" | "flex" | "position";
|
|
5
5
|
type Options = {
|
|
6
6
|
categories?: Category[];
|
|
7
7
|
};
|
|
@@ -32,12 +32,13 @@ const flexKeysSet = new Set([
|
|
|
32
32
|
"flex-[0_0_auto]",
|
|
33
33
|
"flex-1",
|
|
34
34
|
]);
|
|
35
|
-
|
|
35
|
+
const positionKeysSet = new Set(["absolute", "relative", "fixed", "sticky"]);
|
|
36
36
|
const keyMap: Record<Category, Set<string>> = {
|
|
37
37
|
text: textKeysSet,
|
|
38
38
|
flex: flexKeysSet,
|
|
39
39
|
color: colorKeysSet,
|
|
40
40
|
font: fontKeysSet,
|
|
41
|
+
position: positionKeysSet,
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
export function cx(...args: ClassNameItem[]): string {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "../components/Sortable";
|
|
6
6
|
|
|
7
7
|
type MoveOptions = {
|
|
8
|
-
|
|
8
|
+
paths: number[][];
|
|
9
9
|
to: number[];
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -27,19 +27,19 @@ export function moveTreeItem<T>({
|
|
|
27
27
|
switch (position) {
|
|
28
28
|
case "above": {
|
|
29
29
|
return move(root, {
|
|
30
|
-
|
|
30
|
+
paths: [sourceIndexPath],
|
|
31
31
|
to: targetIndexPath,
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
case "below": {
|
|
35
35
|
return move(root, {
|
|
36
|
-
|
|
36
|
+
paths: [sourceIndexPath],
|
|
37
37
|
to: [...targetIndexPath.slice(0, -1), targetIndexPath.at(-1)! + 1],
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
case "inside": {
|
|
41
41
|
return move(root, {
|
|
42
|
-
|
|
42
|
+
paths: [sourceIndexPath],
|
|
43
43
|
to: [...targetIndexPath, 1000],
|
|
44
44
|
});
|
|
45
45
|
}
|
package/tsup.config.ts
CHANGED
|
@@ -14,7 +14,7 @@ export default defineConfig({
|
|
|
14
14
|
// Build Tailwind CSS after successful tsup build
|
|
15
15
|
try {
|
|
16
16
|
const { stdout, stderr } = await execAsync(
|
|
17
|
-
"tailwindcss -i ./src/index.css -o ./dist/index.css --minify"
|
|
17
|
+
"tailwindcss -i ./src/index.css -o ./dist/index.css --minify --postcss"
|
|
18
18
|
);
|
|
19
19
|
if (stdout) console.info(stdout);
|
|
20
20
|
if (stderr) console.error(stderr);
|