@noya-app/noya-designsystem 0.1.39 → 0.1.40
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 -10
- package/CHANGELOG.md +10 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +416 -321
- package/dist/index.d.ts +416 -321
- package/dist/index.js +9558 -11324
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5694 -7465
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/ActivityIndicator.tsx +13 -4
- package/src/components/AnimatePresence.tsx +261 -0
- package/src/components/Avatar.tsx +202 -80
- package/src/components/Button.tsx +10 -6
- package/src/components/Checkbox.tsx +6 -1
- package/src/components/Chip.tsx +88 -132
- package/src/components/{InputFieldWithCompletions.tsx → Combobox.tsx} +10 -3
- package/src/components/ContextMenu.tsx +9 -5
- package/src/components/Dialog.tsx +20 -23
- package/src/components/Divider.tsx +15 -7
- package/src/components/DraggableMenuButton.tsx +9 -5
- package/src/components/DropdownMenu.tsx +8 -5
- package/src/components/FillInputField.tsx +5 -1
- package/src/components/FillPreviewBackground.tsx +1 -5
- package/src/components/GridView.tsx +71 -46
- package/src/components/InputField.tsx +140 -75
- package/src/components/InspectorPrimitives.tsx +17 -11
- package/src/components/Label.tsx +5 -1
- package/src/components/ListView.tsx +28 -15
- package/src/components/Progress.tsx +10 -7
- package/src/components/SelectMenu.tsx +20 -8
- package/src/components/Slider.tsx +70 -8
- package/src/components/Sortable.tsx +3 -3
- package/src/components/Switch.tsx +19 -2
- package/src/components/Text.tsx +5 -1
- package/src/components/TextArea.tsx +5 -1
- package/src/components/TreeView.tsx +4 -10
- package/src/components/UserPointer.tsx +170 -0
- package/src/components/WorkspaceLayout.tsx +5 -0
- package/src/components/internal/Menu.tsx +14 -5
- package/src/components/internal/TextInput.tsx +13 -0
- package/src/contexts/DialogContext.tsx +30 -18
- package/src/hooks/useTheme.ts +50 -0
- package/src/index.css +16 -13
- package/src/index.tsx +14 -26
- package/src/utils/classNames.ts +5 -0
- package/src/utils/colorFromString.ts +44 -0
- package/tailwind.config.ts +16 -13
- package/src/hooks/useDarkMode.ts +0 -14
- package/src/utils/tailwind.ts +0 -9
package/src/components/Chip.tsx
CHANGED
|
@@ -2,119 +2,68 @@ import { Cross1Icon, PlusIcon } from "@noya-app/noya-icons";
|
|
|
2
2
|
import React, { forwardRef, memo } from "react";
|
|
3
3
|
import { useHover } from "../hooks/useHover";
|
|
4
4
|
import { cssVars } from "../theme";
|
|
5
|
+
import { cx } from "../utils/classNames";
|
|
5
6
|
|
|
6
7
|
type ChipColorScheme = "primary" | "secondary" | "error";
|
|
7
8
|
type ChipSize = "small" | "medium" | "large";
|
|
8
9
|
type ChipVariant = "solid" | "outlined" | "ghost";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
text: "text-text",
|
|
67
|
-
bg: "bg-input-background",
|
|
68
|
-
subtle: "bg-[var(--chip-default-bg)]",
|
|
69
|
-
},
|
|
70
|
-
}[$colorScheme ?? "default"];
|
|
71
|
-
|
|
72
|
-
if ($variant === "solid") {
|
|
73
|
-
return `${colors.text} ${colors.bg}`;
|
|
74
|
-
}
|
|
75
|
-
if ($variant === "outlined") {
|
|
76
|
-
return `
|
|
77
|
-
${colors.text} bg-transparent
|
|
78
|
-
${shadowStyles[$colorScheme ?? "default"]}
|
|
79
|
-
hover:${colors.subtle} hover:shadow-none
|
|
80
|
-
`;
|
|
81
|
-
}
|
|
82
|
-
return "";
|
|
83
|
-
})();
|
|
84
|
-
|
|
85
|
-
// Interactive states
|
|
86
|
-
const interactiveStyles = $isInteractive
|
|
87
|
-
? "cursor-pointer hover:opacity-85"
|
|
88
|
-
: "";
|
|
89
|
-
|
|
90
|
-
return `
|
|
91
|
-
${baseStyles}
|
|
92
|
-
${sizeStyles}
|
|
93
|
-
${fontStyles}
|
|
94
|
-
${variantStyles}
|
|
95
|
-
${interactiveStyles}
|
|
96
|
-
`
|
|
97
|
-
.replace(/\s+/g, " ")
|
|
98
|
-
.trim();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function getIconStyles(size: ChipSize, isAdd: boolean) {
|
|
102
|
-
const baseStyles = "relative opacity-50 cursor-pointer hover:opacity-85";
|
|
103
|
-
|
|
104
|
-
if (size === "large") {
|
|
105
|
-
return `
|
|
106
|
-
${baseStyles}
|
|
107
|
-
${isAdd ? "ml-[-2px] mr-[2px] -top-[1px]" : "mr-[-2px] ml-[2px]"}
|
|
108
|
-
scale-75
|
|
109
|
-
`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return `
|
|
113
|
-
${baseStyles}
|
|
114
|
-
${isAdd ? "ml-[-2px] mr-[-2px]" : "mr-[-2px]"}
|
|
115
|
-
scale-60
|
|
116
|
-
`;
|
|
117
|
-
}
|
|
11
|
+
// Hoisted constants for styles
|
|
12
|
+
const BASE_STYLES =
|
|
13
|
+
"inline-flex items-center whitespace-pre rounded select-none leading-[15px]";
|
|
14
|
+
|
|
15
|
+
const SIZE_STYLES = {
|
|
16
|
+
large: "text-[11px] p-[4px_8px]",
|
|
17
|
+
medium: "text-[10px] p-[2px_6px]",
|
|
18
|
+
small: "text-[9px] p-[0px_4px]",
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
const SHADOW_STYLES = {
|
|
22
|
+
primary: "shadow-[0_0_0_1px_var(--chip-primary-shadow)_inset]",
|
|
23
|
+
secondary: "shadow-[0_0_0_1px_var(--chip-secondary-shadow)_inset]",
|
|
24
|
+
error: "shadow-[0_0_0_1px_var(--chip-error-shadow)_inset]",
|
|
25
|
+
default: "shadow-[0_0_0_1px_var(--chip-default-shadow)_inset]",
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
const COLOR_STYLES = {
|
|
29
|
+
primary: {
|
|
30
|
+
text: "text-primary",
|
|
31
|
+
bg: "bg-primary-pastel",
|
|
32
|
+
subtle: "bg-[var(--chip-primary-bg)]",
|
|
33
|
+
},
|
|
34
|
+
secondary: {
|
|
35
|
+
text: "text-secondary",
|
|
36
|
+
bg: "bg-secondary-pastel",
|
|
37
|
+
subtle: "bg-[var(--chip-secondary-bg)]",
|
|
38
|
+
},
|
|
39
|
+
error: {
|
|
40
|
+
text: "text-text",
|
|
41
|
+
bg: "bg-[rgb(255,219,219)]",
|
|
42
|
+
subtle: "bg-[var(--chip-error-bg)]",
|
|
43
|
+
},
|
|
44
|
+
default: {
|
|
45
|
+
text: "text-text",
|
|
46
|
+
bg: "bg-input-background",
|
|
47
|
+
subtle: "bg-[var(--chip-default-bg)]",
|
|
48
|
+
},
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
const ICON_BASE_STYLES = "relative opacity-50 cursor-pointer hover:opacity-85";
|
|
52
|
+
|
|
53
|
+
const ICON_SIZE_STYLES = {
|
|
54
|
+
large: {
|
|
55
|
+
add: "ml-[-2px] mr-[2px] -top-[1px] scale-75",
|
|
56
|
+
delete: "mr-[-2px] ml-[2px] scale-75",
|
|
57
|
+
},
|
|
58
|
+
medium: {
|
|
59
|
+
add: "ml-[-2px] mr-[-2px] scale-60",
|
|
60
|
+
delete: "mr-[-2px] scale-60",
|
|
61
|
+
},
|
|
62
|
+
small: {
|
|
63
|
+
add: "ml-[-2px] mr-[-2px] scale-60",
|
|
64
|
+
delete: "mr-[-2px] scale-60",
|
|
65
|
+
},
|
|
66
|
+
} as const;
|
|
118
67
|
|
|
119
68
|
export interface ChipProps {
|
|
120
69
|
id?: string;
|
|
@@ -162,6 +111,24 @@ export const Chip = memo(
|
|
|
162
111
|
});
|
|
163
112
|
|
|
164
113
|
const handleClick = !children && !deletable && addable ? onAdd : onClick;
|
|
114
|
+
const isInteractive = !!handleClick || clickable === true;
|
|
115
|
+
|
|
116
|
+
const colors = COLOR_STYLES[colorScheme ?? "default"];
|
|
117
|
+
const variantClasses =
|
|
118
|
+
variant === "solid"
|
|
119
|
+
? `${colors.text} ${colors.bg}`
|
|
120
|
+
: variant === "outlined"
|
|
121
|
+
? `${colors.text} bg-transparent ${SHADOW_STYLES[colorScheme ?? "default"]} hover:${colors.subtle} hover:shadow-none`
|
|
122
|
+
: "";
|
|
123
|
+
|
|
124
|
+
const chipClasses = cx(
|
|
125
|
+
BASE_STYLES,
|
|
126
|
+
SIZE_STYLES[size],
|
|
127
|
+
monospace && "font-mono",
|
|
128
|
+
variantClasses,
|
|
129
|
+
isInteractive && "cursor-pointer hover:opacity-85",
|
|
130
|
+
className
|
|
131
|
+
);
|
|
165
132
|
|
|
166
133
|
const color =
|
|
167
134
|
colorScheme === "primary"
|
|
@@ -173,16 +140,7 @@ export const Chip = memo(
|
|
|
173
140
|
return (
|
|
174
141
|
<span
|
|
175
142
|
ref={forwardedRef}
|
|
176
|
-
className={
|
|
177
|
-
${getChipStyles({
|
|
178
|
-
$colorScheme: colorScheme,
|
|
179
|
-
$size: size,
|
|
180
|
-
$variant: variant,
|
|
181
|
-
$monospace: monospace,
|
|
182
|
-
$isInteractive: !!handleClick || clickable === true,
|
|
183
|
-
})}
|
|
184
|
-
${className ?? ""}
|
|
185
|
-
`}
|
|
143
|
+
className={chipClasses}
|
|
186
144
|
style={style}
|
|
187
145
|
onClick={handleClick}
|
|
188
146
|
tabIndex={tabIndex}
|
|
@@ -190,14 +148,13 @@ export const Chip = memo(
|
|
|
190
148
|
>
|
|
191
149
|
{addable && (
|
|
192
150
|
<PlusIcon
|
|
193
|
-
className={
|
|
151
|
+
className={cx(ICON_BASE_STYLES, ICON_SIZE_STYLES[size].add)}
|
|
194
152
|
onClick={
|
|
195
|
-
onAdd
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
: undefined
|
|
153
|
+
onAdd &&
|
|
154
|
+
((event) => {
|
|
155
|
+
event.stopPropagation();
|
|
156
|
+
onAdd();
|
|
157
|
+
})
|
|
201
158
|
}
|
|
202
159
|
color={color}
|
|
203
160
|
/>
|
|
@@ -205,15 +162,14 @@ export const Chip = memo(
|
|
|
205
162
|
{children}
|
|
206
163
|
{deletable && (
|
|
207
164
|
<Cross1Icon
|
|
208
|
-
className={
|
|
165
|
+
className={cx(ICON_BASE_STYLES, ICON_SIZE_STYLES[size].delete)}
|
|
209
166
|
{...(hoverDeleteProps as any)}
|
|
210
167
|
onClick={
|
|
211
|
-
onDelete
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
: undefined
|
|
168
|
+
onDelete &&
|
|
169
|
+
((event) => {
|
|
170
|
+
event.stopPropagation();
|
|
171
|
+
onDelete();
|
|
172
|
+
})
|
|
217
173
|
}
|
|
218
174
|
color={color}
|
|
219
175
|
/>
|
|
@@ -140,6 +140,7 @@ export const CompletionMenu = memo(
|
|
|
140
140
|
);
|
|
141
141
|
|
|
142
142
|
export type InputFieldWithCompletionsProps = {
|
|
143
|
+
id?: string;
|
|
143
144
|
loading?: boolean;
|
|
144
145
|
initialValue?: string;
|
|
145
146
|
placeholder?: string;
|
|
@@ -153,6 +154,7 @@ export type InputFieldWithCompletionsProps = {
|
|
|
153
154
|
size?: InputFieldSize;
|
|
154
155
|
style?: React.CSSProperties;
|
|
155
156
|
className?: string;
|
|
157
|
+
label?: React.ReactNode;
|
|
156
158
|
children?: React.ReactNode;
|
|
157
159
|
hideChildrenWhenFocused?: boolean;
|
|
158
160
|
hideMenuWhenEmptyValue?: boolean;
|
|
@@ -164,9 +166,10 @@ export interface InputFieldWithCompletionsRef {
|
|
|
164
166
|
selectAllInputText(): void;
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
export const
|
|
168
|
-
forwardRef(function
|
|
169
|
+
export const Combobox = memo(
|
|
170
|
+
forwardRef(function Combobox(
|
|
169
171
|
{
|
|
172
|
+
id,
|
|
170
173
|
loading,
|
|
171
174
|
initialValue = "",
|
|
172
175
|
placeholder,
|
|
@@ -180,6 +183,7 @@ export const InputFieldWithCompletions = memo(
|
|
|
180
183
|
onDeleteWhenEmpty,
|
|
181
184
|
style,
|
|
182
185
|
className,
|
|
186
|
+
label,
|
|
183
187
|
children,
|
|
184
188
|
hideChildrenWhenFocused = false,
|
|
185
189
|
hideMenuWhenEmptyValue = false,
|
|
@@ -409,7 +413,9 @@ export const InputFieldWithCompletions = memo(
|
|
|
409
413
|
|
|
410
414
|
return (
|
|
411
415
|
<InputField.Root
|
|
416
|
+
id={id}
|
|
412
417
|
size={size}
|
|
418
|
+
labelPosition="end"
|
|
413
419
|
renderPopoverContent={({ width }) => {
|
|
414
420
|
const listSize = { width, height };
|
|
415
421
|
|
|
@@ -417,7 +423,7 @@ export const InputFieldWithCompletions = memo(
|
|
|
417
423
|
<div
|
|
418
424
|
className={`flex flex-col ${!filter && hideMenuWhenEmptyValue ? "none" : "flex"}`}
|
|
419
425
|
style={{
|
|
420
|
-
flex: `0 0 ${height}px
|
|
426
|
+
flex: `0 0 ${height}px`,
|
|
421
427
|
}}
|
|
422
428
|
>
|
|
423
429
|
{filteredItems.length > 0 ? (
|
|
@@ -472,6 +478,7 @@ export const InputFieldWithCompletions = memo(
|
|
|
472
478
|
<ActivityIndicator />
|
|
473
479
|
</InputField.Label>
|
|
474
480
|
)}
|
|
481
|
+
{label && <InputField.Label>{label}</InputField.Label>}
|
|
475
482
|
</InputField.Root>
|
|
476
483
|
);
|
|
477
484
|
})
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CheckIcon, ChevronRightIcon } from "@noya-app/noya-icons";
|
|
2
2
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
3
|
+
import { memoGeneric } from "@noya-app/react-utils";
|
|
3
4
|
import * as RadixContextMenu from "@radix-ui/react-context-menu";
|
|
4
|
-
import React, { ReactNode,
|
|
5
|
+
import React, { ReactNode, useCallback, useMemo } from "react";
|
|
5
6
|
import { renderIcon } from "./Icons";
|
|
6
7
|
import { Spacer } from "./Spacer";
|
|
7
8
|
import {
|
|
@@ -26,7 +27,7 @@ export interface MenuItemProps<T extends string> {
|
|
|
26
27
|
items?: MenuItem<T>[];
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
const ContextMenuItem =
|
|
30
|
+
const ContextMenuItem = memoGeneric(function ContextMenuItem<T extends string>({
|
|
30
31
|
value,
|
|
31
32
|
children,
|
|
32
33
|
onSelect,
|
|
@@ -68,7 +69,7 @@ const ContextMenuItem = memo(function ContextMenuItem<T extends string>({
|
|
|
68
69
|
|
|
69
70
|
const element = (
|
|
70
71
|
<RadixContextMenu.Item
|
|
71
|
-
|
|
72
|
+
className={styles.itemStyle({ disabled })}
|
|
72
73
|
disabled={disabled}
|
|
73
74
|
onSelect={handleSelectItem}
|
|
74
75
|
onPointerDown={handlePointerDown}
|
|
@@ -171,7 +172,10 @@ function ContextMenuRoot<T extends string>({
|
|
|
171
172
|
<ContentComponent className={styles.contentStyle}>
|
|
172
173
|
{items.map((item, index) =>
|
|
173
174
|
item === SEPARATOR_ITEM ? (
|
|
174
|
-
<RadixContextMenu.Separator
|
|
175
|
+
<RadixContextMenu.Separator
|
|
176
|
+
key={index}
|
|
177
|
+
className={styles.separatorStyle}
|
|
178
|
+
/>
|
|
175
179
|
) : (
|
|
176
180
|
<ContextMenuItem
|
|
177
181
|
key={item.value ?? index}
|
|
@@ -194,4 +198,4 @@ function ContextMenuRoot<T extends string>({
|
|
|
194
198
|
);
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
export const ContextMenu =
|
|
201
|
+
export const ContextMenu = memoGeneric(ContextMenuRoot);
|
|
@@ -9,7 +9,7 @@ import React, {
|
|
|
9
9
|
} from "react";
|
|
10
10
|
import { IconButton } from "./IconButton";
|
|
11
11
|
import { Spacer } from "./Spacer";
|
|
12
|
-
import {
|
|
12
|
+
import { cx } from "../utils/classNames";
|
|
13
13
|
|
|
14
14
|
const StyledOverlay = forwardRef<
|
|
15
15
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
@@ -17,7 +17,7 @@ const StyledOverlay = forwardRef<
|
|
|
17
17
|
>(({ className, ...props }, ref) => (
|
|
18
18
|
<DialogPrimitive.Overlay
|
|
19
19
|
ref={ref}
|
|
20
|
-
className={
|
|
20
|
+
className={cx(`fixed inset-0 bg-[rgba(0,0,0,0.5)] `, className)}
|
|
21
21
|
{...props}
|
|
22
22
|
/>
|
|
23
23
|
));
|
|
@@ -28,14 +28,16 @@ const StyledContent = forwardRef<
|
|
|
28
28
|
>(({ className, ...props }, ref) => (
|
|
29
29
|
<DialogPrimitive.Content
|
|
30
30
|
ref={ref}
|
|
31
|
-
className={
|
|
31
|
+
className={cx(
|
|
32
|
+
`
|
|
32
33
|
fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2
|
|
33
34
|
w-[90vw] max-w-[450px] max-h-[85vh] p-dialog-padding rounded-[2px]
|
|
34
35
|
font-sans text-heading5 font-normal leading-[19px] text-text-muted
|
|
35
36
|
bg-popover-background overflow-y-auto pointer-events-all z-[1000] focus:outline-none
|
|
36
37
|
shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2)]
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
`,
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
39
41
|
{...props}
|
|
40
42
|
/>
|
|
41
43
|
));
|
|
@@ -46,8 +48,8 @@ const StyledTitle = forwardRef<
|
|
|
46
48
|
>(({ className, ...props }, ref) => (
|
|
47
49
|
<DialogPrimitive.Title
|
|
48
50
|
ref={ref}
|
|
49
|
-
className={
|
|
50
|
-
|
|
51
|
+
className={cx(
|
|
52
|
+
`m-0 font-sans text-base font-normal leading-[1.4] text-text `,
|
|
51
53
|
className
|
|
52
54
|
)}
|
|
53
55
|
{...props}
|
|
@@ -60,8 +62,8 @@ const StyledDescription = forwardRef<
|
|
|
60
62
|
>(({ className, ...props }, ref) => (
|
|
61
63
|
<DialogPrimitive.Description
|
|
62
64
|
ref={ref}
|
|
63
|
-
className={
|
|
64
|
-
|
|
65
|
+
className={cx(
|
|
66
|
+
`m-0 font-sans text-heading5 font-normal leading-[19px] text-text-muted `,
|
|
65
67
|
className
|
|
66
68
|
)}
|
|
67
69
|
{...props}
|
|
@@ -74,7 +76,10 @@ const CloseButtonContainer = forwardRef<
|
|
|
74
76
|
>(({ className, ...props }, ref) => (
|
|
75
77
|
<div
|
|
76
78
|
ref={ref}
|
|
77
|
-
className={
|
|
79
|
+
className={cx(
|
|
80
|
+
`absolute top-dialog-padding right-dialog-padding z-[1] bg-popover-background p-[4px_6px] rounded-[2px] border border-[rgba(128,128,128,0.2)] `,
|
|
81
|
+
className
|
|
82
|
+
)}
|
|
78
83
|
{...props}
|
|
79
84
|
/>
|
|
80
85
|
));
|
|
@@ -94,6 +99,7 @@ interface Props {
|
|
|
94
99
|
typeof DialogPrimitive.Content
|
|
95
100
|
>["onOpenAutoFocus"];
|
|
96
101
|
closeOnInteractOutside?: boolean;
|
|
102
|
+
className?: string;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
export const Dialog = forwardRef(function Dialog(
|
|
@@ -106,6 +112,7 @@ export const Dialog = forwardRef(function Dialog(
|
|
|
106
112
|
onOpenChange,
|
|
107
113
|
onOpenAutoFocus,
|
|
108
114
|
closeOnInteractOutside = true,
|
|
115
|
+
className,
|
|
109
116
|
}: Props,
|
|
110
117
|
forwardedRef: ForwardedRef<IDialog>
|
|
111
118
|
) {
|
|
@@ -125,6 +132,7 @@ export const Dialog = forwardRef(function Dialog(
|
|
|
125
132
|
ref={contentRef}
|
|
126
133
|
onOpenAutoFocus={onOpenAutoFocus}
|
|
127
134
|
style={style}
|
|
135
|
+
className={className}
|
|
128
136
|
{...(closeOnInteractOutside === false && {
|
|
129
137
|
onPointerDownOutside: (event) => event.preventDefault(),
|
|
130
138
|
onInteractOutside: (event) => event.preventDefault(),
|
|
@@ -161,19 +169,8 @@ export const FullscreenDialog = forwardRef(function FullscreenDialog(
|
|
|
161
169
|
return (
|
|
162
170
|
<Dialog
|
|
163
171
|
ref={forwardedRef}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
height: "100%",
|
|
167
|
-
maxWidth: "100%",
|
|
168
|
-
maxHeight: "100%",
|
|
169
|
-
top: "0",
|
|
170
|
-
left: "0",
|
|
171
|
-
transform: "none",
|
|
172
|
-
display: "flex",
|
|
173
|
-
flexDirection: "column",
|
|
174
|
-
padding: 0,
|
|
175
|
-
...style,
|
|
176
|
-
}}
|
|
172
|
+
className="w-full h-full max-w-full max-h-full top-0 left-0 translate-none flex flex-col p-0"
|
|
173
|
+
style={style}
|
|
177
174
|
{...rest}
|
|
178
175
|
/>
|
|
179
176
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { memo } from "react";
|
|
2
|
+
import { cx } from "../utils/classNames";
|
|
2
3
|
|
|
3
4
|
type DividerVariant = "normal" | "subtle" | "strong";
|
|
4
5
|
|
|
@@ -18,12 +19,14 @@ export const Divider = memo(function Divider({
|
|
|
18
19
|
}: DividerProps) {
|
|
19
20
|
return (
|
|
20
21
|
<div
|
|
21
|
-
className={
|
|
22
|
+
className={cx(
|
|
23
|
+
`
|
|
22
24
|
h-px min-h-px
|
|
23
25
|
${variant === "strong" ? "bg-divider-strong" : variant === "subtle" ? "bg-divider-subtle" : "bg-divider"}
|
|
24
26
|
self-stretch
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
`,
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
27
30
|
style={{
|
|
28
31
|
marginLeft: `-${overflow}px`,
|
|
29
32
|
marginRight: `-${overflow}px`,
|
|
@@ -38,17 +41,22 @@ export const DividerVertical = memo(function DividerVertical({
|
|
|
38
41
|
variant = "normal",
|
|
39
42
|
overflow = 0,
|
|
40
43
|
className,
|
|
44
|
+
style,
|
|
41
45
|
...props
|
|
42
46
|
}: DividerProps) {
|
|
43
47
|
return (
|
|
44
48
|
<div
|
|
45
|
-
className={`
|
|
49
|
+
className={cx(`
|
|
46
50
|
w-px min-w-px
|
|
47
|
-
my-[-${overflow}px]
|
|
48
51
|
${variant === "strong" ? "bg-divider-strong" : variant === "subtle" ? "bg-divider-subtle" : "bg-divider"}
|
|
49
52
|
self-stretch
|
|
50
|
-
${className
|
|
51
|
-
`}
|
|
53
|
+
${className}
|
|
54
|
+
`)}
|
|
55
|
+
style={{
|
|
56
|
+
marginTop: `-${overflow}px`,
|
|
57
|
+
marginBottom: `-${overflow}px`,
|
|
58
|
+
...style,
|
|
59
|
+
}}
|
|
52
60
|
{...props}
|
|
53
61
|
/>
|
|
54
62
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DragHandleDots2Icon } from "@noya-app/noya-icons";
|
|
2
|
-
import
|
|
2
|
+
import { memoGeneric } from "@noya-app/react-utils";
|
|
3
|
+
import React, { forwardRef, useCallback, useState } from "react";
|
|
3
4
|
import { cssVars } from "../theme";
|
|
4
|
-
import {
|
|
5
|
+
import { cx } from "../utils/classNames";
|
|
5
6
|
import { DropdownMenu } from "./DropdownMenu";
|
|
6
7
|
import { MenuItem } from "./internal/Menu";
|
|
7
8
|
|
|
@@ -11,7 +12,10 @@ const DotButton = forwardRef<
|
|
|
11
12
|
>(({ className, ...props }, ref) => (
|
|
12
13
|
<div
|
|
13
14
|
ref={ref}
|
|
14
|
-
className={
|
|
15
|
+
className={cx(
|
|
16
|
+
`cursor-pointer rounded flex items-center justify-center py-[2px] hover:bg-input-background-light active:bg-active-background `,
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
15
19
|
{...props}
|
|
16
20
|
/>
|
|
17
21
|
));
|
|
@@ -22,7 +26,7 @@ const Trigger = forwardRef<
|
|
|
22
26
|
>(({ className, ...props }, ref) => (
|
|
23
27
|
<div
|
|
24
28
|
ref={ref}
|
|
25
|
-
className={
|
|
29
|
+
className={cx(`pointer-events-none h-[15px] `, className)}
|
|
26
30
|
{...props}
|
|
27
31
|
/>
|
|
28
32
|
));
|
|
@@ -30,7 +34,7 @@ const Trigger = forwardRef<
|
|
|
30
34
|
/**
|
|
31
35
|
* A button that opens a menu when clicked, but also allows dragging the
|
|
32
36
|
*/
|
|
33
|
-
export const DraggableMenuButton =
|
|
37
|
+
export const DraggableMenuButton = memoGeneric(function DraggableMenuButton<
|
|
34
38
|
T extends string,
|
|
35
39
|
>({
|
|
36
40
|
items,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { CheckIcon, ChevronRightIcon } from "@noya-app/noya-icons";
|
|
2
2
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
3
|
+
import { forwardRefGeneric, memoGeneric } from "@noya-app/react-utils";
|
|
3
4
|
import * as RadixDropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
4
5
|
import React, {
|
|
5
6
|
ComponentProps,
|
|
6
7
|
ForwardedRef,
|
|
7
8
|
SyntheticEvent,
|
|
8
|
-
forwardRef,
|
|
9
|
-
memo,
|
|
10
9
|
useCallback,
|
|
11
10
|
useMemo,
|
|
12
11
|
} from "react";
|
|
@@ -22,7 +21,9 @@ import {
|
|
|
22
21
|
styles,
|
|
23
22
|
} from "./internal/Menu";
|
|
24
23
|
|
|
25
|
-
const DropdownMenuItem =
|
|
24
|
+
const DropdownMenuItem = memoGeneric(function ContextMenuItem<
|
|
25
|
+
T extends string,
|
|
26
|
+
>({
|
|
26
27
|
value,
|
|
27
28
|
children,
|
|
28
29
|
onSelect,
|
|
@@ -123,7 +124,9 @@ type DropdownRootProps<T extends string> = MenuProps<T> & {
|
|
|
123
124
|
"side" | "sideOffset" | "align" | "alignOffset" | "collisionPadding"
|
|
124
125
|
>;
|
|
125
126
|
|
|
126
|
-
const DropdownMenuRoot =
|
|
127
|
+
const DropdownMenuRoot = forwardRefGeneric(function DropdownMenuRoot<
|
|
128
|
+
T extends string,
|
|
129
|
+
>(
|
|
127
130
|
{
|
|
128
131
|
items,
|
|
129
132
|
children,
|
|
@@ -213,4 +216,4 @@ const DropdownMenuRoot = forwardRef(function DropdownMenuRoot<T extends string>(
|
|
|
213
216
|
);
|
|
214
217
|
});
|
|
215
218
|
|
|
216
|
-
export const DropdownMenu =
|
|
219
|
+
export const DropdownMenu = memoGeneric(DropdownMenuRoot);
|
|
@@ -2,6 +2,7 @@ import { Sketch } from "@noya-app/noya-file-format";
|
|
|
2
2
|
import React, { forwardRef, memo } from "react";
|
|
3
3
|
import { SketchPattern } from "../utils/sketchPattern";
|
|
4
4
|
import { FillPreviewBackground } from "./FillPreviewBackground";
|
|
5
|
+
import { cx } from "../utils/classNames";
|
|
5
6
|
|
|
6
7
|
const FillButton = forwardRef<
|
|
7
8
|
HTMLButtonElement,
|
|
@@ -9,7 +10,10 @@ const FillButton = forwardRef<
|
|
|
9
10
|
>(({ className, ...props }, ref) => (
|
|
10
11
|
<button
|
|
11
12
|
ref={ref}
|
|
12
|
-
className={
|
|
13
|
+
className={cx(
|
|
14
|
+
`outline-none p-0 w-[50px] h-[27px] rounded overflow-hidden border-none shadow-[0_0_0_1px_var(--divider)_inset] bg-transparent relative focus:shadow-[0_0_0_1px_var(--sidebar-background),0_0_0_3px_var(--primary)] `,
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
13
17
|
{...props}
|
|
14
18
|
/>
|
|
15
19
|
));
|
|
@@ -7,7 +7,6 @@ import { cssVars } from "../theme";
|
|
|
7
7
|
import { getGradientBackground } from "../utils/getGradientBackground";
|
|
8
8
|
import { sketchColorToRgbaString } from "../utils/sketchColor";
|
|
9
9
|
import { SketchPattern } from "../utils/sketchPattern";
|
|
10
|
-
import { cn } from "../utils/tailwind";
|
|
11
10
|
|
|
12
11
|
const dotsHorizontalSvg = (fillColor: string) => `
|
|
13
12
|
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 15 15' fill='${fillColor}'>
|
|
@@ -22,10 +21,7 @@ const Background = memo(function Background({
|
|
|
22
21
|
}) {
|
|
23
22
|
return (
|
|
24
23
|
<span
|
|
25
|
-
className={
|
|
26
|
-
"absolute inset-0",
|
|
27
|
-
background ? `bg-[${background}]` : "bg-input-background"
|
|
28
|
-
)}
|
|
24
|
+
className={`${background ? `bg-[${background}]` : "bg-input-background"} absolute inset-0`}
|
|
29
25
|
/>
|
|
30
26
|
);
|
|
31
27
|
});
|