@noya-app/noya-designsystem 0.1.49 → 0.1.51
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 +19 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +169 -205
- package/dist/index.d.ts +169 -205
- package/dist/index.js +5092 -13463
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3501 -11912
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/components/ActionMenu.tsx +4 -2
- package/src/components/Avatar.tsx +2 -2
- package/src/components/Banner.tsx +29 -0
- package/src/components/Button.tsx +2 -2
- package/src/components/Chip.tsx +8 -8
- package/src/components/Collection.tsx +18 -4
- package/src/components/ComboboxMenu.tsx +10 -1
- package/src/components/Dialog.tsx +2 -2
- package/src/components/FillInputField.tsx +1 -1
- package/src/components/Grid.tsx +12 -11
- package/src/components/Label.tsx +11 -6
- package/src/components/LabeledField.tsx +6 -1
- package/src/components/List.tsx +30 -24
- package/src/components/ListView.tsx +10 -5
- package/src/components/MediaThumbnail.tsx +31 -9
- package/src/components/Popover.tsx +9 -6
- package/src/components/SearchCompletionMenu.tsx +12 -12
- package/src/components/Section.tsx +172 -0
- package/src/components/SegmentedControl.tsx +1 -1
- package/src/components/SelectMenu.tsx +1 -1
- package/src/components/Slider.tsx +1 -1
- package/src/components/Sortable.tsx +124 -22
- package/src/components/Toolbar.tsx +22 -10
- package/src/components/UserPointer.tsx +1 -1
- package/src/components/ai-assistant/AIAssistantLayout.tsx +102 -0
- package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +71 -0
- package/src/components/file-explorer/FileExplorerLayout.tsx +81 -0
- package/src/components/internal/Menu.tsx +12 -7
- package/src/components/internal/TextInput.tsx +7 -2
- package/src/components/pipeline/PipelineResultLayout.tsx +32 -0
- package/src/index.css +125 -118
- package/src/index.tsx +7 -0
- package/src/theme/index.ts +1 -1
- package/src/utils/classNames.ts +28 -3
- package/src/utils/combobox.ts +18 -13
- package/src/utils/moveTreeItem.ts +99 -0
- package/tailwind.config.ts +2 -239
- package/tailwind.d.ts +1 -1
- package/tsup.config.ts +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noya-app/noya-designsystem",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.51",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@dnd-kit/core": "6.3.1",
|
|
24
24
|
"@dnd-kit/sortable": "10.0.0",
|
|
25
|
-
"@noya-app/noya-colorpicker": "0.1.
|
|
26
|
-
"@noya-app/noya-utils": "0.1.
|
|
27
|
-
"@noya-app/noya-geometry": "0.1.
|
|
28
|
-
"@noya-app/noya-icons": "0.1.
|
|
25
|
+
"@noya-app/noya-colorpicker": "0.1.19",
|
|
26
|
+
"@noya-app/noya-utils": "0.1.5",
|
|
27
|
+
"@noya-app/noya-geometry": "0.1.10",
|
|
28
|
+
"@noya-app/noya-icons": "0.1.7",
|
|
29
29
|
"@noya-app/noya-keymap": "0.1.3",
|
|
30
|
+
"@noya-app/noya-tailwind-config": "0.1.2",
|
|
30
31
|
"@radix-ui/primitive": "^1.0.0",
|
|
31
32
|
"@radix-ui/react-avatar": "^1.0.1",
|
|
32
33
|
"@radix-ui/react-compose-refs": "^1.0.0",
|
|
@@ -47,17 +48,16 @@
|
|
|
47
48
|
"kiwi.js": "^1.1.3",
|
|
48
49
|
"react-resizable-panels": "2.0.22",
|
|
49
50
|
"react-window": "^1.8.8",
|
|
50
|
-
"vscode-fuzzy-scorer": "^0.0.4"
|
|
51
|
+
"vscode-fuzzy-scorer": "^0.0.4",
|
|
52
|
+
"react-virtualized": "9.22.6"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
55
|
"@tailwindcss/container-queries": "^0.1.1",
|
|
54
56
|
"@types/react": "*",
|
|
55
57
|
"@types/react-dom": "*",
|
|
56
|
-
"@types/react-virtualized": "^9.21.
|
|
58
|
+
"@types/react-virtualized": "^9.21.30",
|
|
57
59
|
"@types/react-window": "^1.8.5",
|
|
58
|
-
"esbuild-plugin-react-virtualized": "1.0.4",
|
|
59
60
|
"esbuild-plugin-tailwindcss": "^1.2.1",
|
|
60
|
-
"react-virtualized": "9.22.5",
|
|
61
61
|
"tailwind-merge": "^2.5.4",
|
|
62
62
|
"tailwindcss": "^3.4.14"
|
|
63
63
|
},
|
|
@@ -12,6 +12,7 @@ type ActionMenuProps<TMenu extends string> = {
|
|
|
12
12
|
onOpenChange: (open: boolean) => void;
|
|
13
13
|
className?: string;
|
|
14
14
|
style?: React.CSSProperties;
|
|
15
|
+
variant?: "normal" | "bare";
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export const ActionMenu = memoGeneric(function ActionMenu<
|
|
@@ -23,16 +24,17 @@ export const ActionMenu = memoGeneric(function ActionMenu<
|
|
|
23
24
|
onOpenChange,
|
|
24
25
|
className,
|
|
25
26
|
style,
|
|
27
|
+
variant = "normal",
|
|
26
28
|
}: ActionMenuProps<TMenu>) {
|
|
27
29
|
const internalStyle = useMemo(() => {
|
|
28
30
|
return {
|
|
29
31
|
backgroundColor: selected
|
|
30
32
|
? cssVars.colors.primaryPastel
|
|
31
33
|
: cssVars.colors.inputBackground,
|
|
32
|
-
padding: "
|
|
34
|
+
padding: variant === "bare" ? 0 : 4,
|
|
33
35
|
...style,
|
|
34
36
|
};
|
|
35
|
-
}, [selected, style]);
|
|
37
|
+
}, [selected, style, variant]);
|
|
36
38
|
|
|
37
39
|
return (
|
|
38
40
|
<DropdownMenu
|
|
@@ -181,8 +181,8 @@ const OverflowAvatar = React.memo(function OverflowAvatar({
|
|
|
181
181
|
count: number;
|
|
182
182
|
}) {
|
|
183
183
|
return (
|
|
184
|
-
<AvatarRoot size={size} backgroundColor="var(--text-disabled)" disabled>
|
|
185
|
-
<AvatarFallback backgroundColor="var(--text-disabled)" size={size}>
|
|
184
|
+
<AvatarRoot size={size} backgroundColor="var(--n-text-disabled)" disabled>
|
|
185
|
+
<AvatarFallback backgroundColor="var(--n-text-disabled)" size={size}>
|
|
186
186
|
+{count}
|
|
187
187
|
</AvatarFallback>
|
|
188
188
|
</AvatarRoot>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { CSSProperties } from "react";
|
|
2
|
+
import { cssVars } from "../theme";
|
|
3
|
+
import { cx } from "../utils/classNames";
|
|
4
|
+
import { Small } from "./Text";
|
|
5
|
+
|
|
6
|
+
const bannerStyles = {
|
|
7
|
+
backgroundColor: cssVars.colors.inputBackground,
|
|
8
|
+
color: cssVars.colors.textDisabled,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type BannerProps = {
|
|
12
|
+
label?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
style?: CSSProperties;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function Banner({ label = "No items", className, style }: BannerProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className={cx(
|
|
21
|
+
"flex p-1 items-center justify-center select-none rounded",
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
style={{ ...bannerStyles, ...style }}
|
|
25
|
+
>
|
|
26
|
+
<Small color="textDisabled">{label}</Small>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -5,8 +5,8 @@ import React, {
|
|
|
5
5
|
ReactNode,
|
|
6
6
|
useCallback,
|
|
7
7
|
} from "react";
|
|
8
|
-
import { Tooltip } from "./Tooltip";
|
|
9
8
|
import { cx } from "../utils/classNames";
|
|
9
|
+
import { Tooltip } from "./Tooltip";
|
|
10
10
|
|
|
11
11
|
type ButtonVariant =
|
|
12
12
|
| "normal"
|
|
@@ -87,7 +87,7 @@ export const Button = forwardRef(function Button(
|
|
|
87
87
|
ref={forwardedRef}
|
|
88
88
|
id={id}
|
|
89
89
|
className={cx(
|
|
90
|
-
"no-underline leading-[1] relative border-0 outline-none select-none text-left rounded flex items-center justify-center [&>*]:pointer-events-none [-webkit-app-region:no-drag] focus:ring-2 focus:ring-primary focus:shadow-[0_0_0_1px_var(--popover-background)_inset] transition-all",
|
|
90
|
+
"no-underline leading-[1] relative border-0 outline-none select-none text-left rounded flex items-center justify-center [&>*]:pointer-events-none [-webkit-app-region:no-drag] focus:ring-2 focus:ring-primary focus:shadow-[0_0_0_1px_var(--n-popover-background)_inset] transition-all",
|
|
91
91
|
disabled ? "opacity-25" : "",
|
|
92
92
|
!className?.includes("flex") ? "flex-none" : "",
|
|
93
93
|
active
|
package/src/components/Chip.tsx
CHANGED
|
@@ -19,32 +19,32 @@ const SIZE_STYLES = {
|
|
|
19
19
|
} as const;
|
|
20
20
|
|
|
21
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]",
|
|
22
|
+
primary: "shadow-[0_0_0_1px_var(--n-chip-primary-shadow)_inset]",
|
|
23
|
+
secondary: "shadow-[0_0_0_1px_var(--n-chip-secondary-shadow)_inset]",
|
|
24
|
+
error: "shadow-[0_0_0_1px_var(--n-chip-error-shadow)_inset]",
|
|
25
|
+
default: "shadow-[0_0_0_1px_var(--n-chip-default-shadow)_inset]",
|
|
26
26
|
} as const;
|
|
27
27
|
|
|
28
28
|
const COLOR_STYLES = {
|
|
29
29
|
primary: {
|
|
30
30
|
text: "text-primary",
|
|
31
31
|
bg: "bg-primary-pastel",
|
|
32
|
-
subtle: "bg-[var(--chip-primary-bg)]",
|
|
32
|
+
subtle: "bg-[var(--n-chip-primary-bg)]",
|
|
33
33
|
},
|
|
34
34
|
secondary: {
|
|
35
35
|
text: "text-secondary",
|
|
36
36
|
bg: "bg-secondary-pastel",
|
|
37
|
-
subtle: "bg-[var(--chip-secondary-bg)]",
|
|
37
|
+
subtle: "bg-[var(--n-chip-secondary-bg)]",
|
|
38
38
|
},
|
|
39
39
|
error: {
|
|
40
40
|
text: "text-text",
|
|
41
41
|
bg: "bg-[rgb(255,219,219)]",
|
|
42
|
-
subtle: "bg-[var(--chip-error-bg)]",
|
|
42
|
+
subtle: "bg-[var(--n-chip-error-bg)]",
|
|
43
43
|
},
|
|
44
44
|
default: {
|
|
45
45
|
text: "text-text",
|
|
46
46
|
bg: "bg-input-background",
|
|
47
|
-
subtle: "bg-[var(--chip-default-bg)]",
|
|
47
|
+
subtle: "bg-[var(--n-chip-default-bg)]",
|
|
48
48
|
},
|
|
49
49
|
} as const;
|
|
50
50
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { forwardRefGeneric } from "@noya-app/react-utils";
|
|
1
2
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { Grid, GridViewSize } from "../components/Grid";
|
|
3
|
+
import { Grid } from "../components/Grid";
|
|
4
4
|
import { MenuItem } from "../components/internal/Menu";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ListView,
|
|
7
|
+
ListViewRootProps,
|
|
8
|
+
ListViewRowProps,
|
|
9
|
+
} from "../components/ListView";
|
|
6
10
|
import { List } from "./List";
|
|
7
11
|
|
|
8
12
|
export type CollectionViewType = "grid" | "list";
|
|
@@ -16,6 +20,7 @@ export type CollectionRef = {
|
|
|
16
20
|
export type CollectionThumbnailProps<T> = {
|
|
17
21
|
item: T;
|
|
18
22
|
selected: boolean;
|
|
23
|
+
size?: CollectionItemSize;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
26
|
export type CollectionRenderActionProps<T> = {
|
|
@@ -47,6 +52,7 @@ export interface CollectionProps<T, M extends string = string> {
|
|
|
47
52
|
renderThumbnail?: ({
|
|
48
53
|
item,
|
|
49
54
|
selected,
|
|
55
|
+
size,
|
|
50
56
|
}: CollectionThumbnailProps<T>) => React.ReactNode;
|
|
51
57
|
renderAction?:
|
|
52
58
|
| "menu"
|
|
@@ -62,7 +68,7 @@ export interface CollectionProps<T, M extends string = string> {
|
|
|
62
68
|
/** Position of the detail content. Defaults to 'end'. */
|
|
63
69
|
detailPosition?: "end" | "below";
|
|
64
70
|
/** Size of the list items. Defaults to 'medium'. */
|
|
65
|
-
size?:
|
|
71
|
+
size?: CollectionItemSize;
|
|
66
72
|
/** Size of the thumbnail. Defaults to 'auto', which will be based on the size prop. */
|
|
67
73
|
thumbnailSize?: CollectionThumbnailSize;
|
|
68
74
|
/** For testing: Override the hover state with a specific item ID */
|
|
@@ -86,6 +92,7 @@ export interface CollectionProps<T, M extends string = string> {
|
|
|
86
92
|
renderEmptyState?: () => React.ReactElement;
|
|
87
93
|
/** @default false */
|
|
88
94
|
sortable?: boolean;
|
|
95
|
+
dragIndicatorStyle?: ListViewRowProps<M>["dragIndicatorStyle"];
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
export const Collection = forwardRefGeneric(function Collection<
|
|
@@ -100,3 +107,10 @@ export const Collection = forwardRefGeneric(function Collection<
|
|
|
100
107
|
<List ref={ref} {...rest} />
|
|
101
108
|
);
|
|
102
109
|
});
|
|
110
|
+
export type CollectionItemSize =
|
|
111
|
+
| "xxs"
|
|
112
|
+
| "xs"
|
|
113
|
+
| "small"
|
|
114
|
+
| "medium"
|
|
115
|
+
| "large"
|
|
116
|
+
| "xl";
|
|
@@ -25,6 +25,8 @@ interface ComboboxMenuProps<T extends string> {
|
|
|
25
25
|
listSize: Size;
|
|
26
26
|
style?: React.CSSProperties;
|
|
27
27
|
indented?: boolean;
|
|
28
|
+
/** @default right */
|
|
29
|
+
iconPosition?: "left" | "right";
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export const ComboboxMenu = memoGeneric(
|
|
@@ -37,6 +39,7 @@ export const ComboboxMenu = memoGeneric(
|
|
|
37
39
|
listSize,
|
|
38
40
|
style,
|
|
39
41
|
indented,
|
|
42
|
+
iconPosition = "right",
|
|
40
43
|
}: ComboboxMenuProps<T>,
|
|
41
44
|
forwardedRef: ForwardedRef<IVirtualizedList>
|
|
42
45
|
) {
|
|
@@ -100,6 +103,12 @@ export const ComboboxMenu = memoGeneric(
|
|
|
100
103
|
size={CHECKBOX_WIDTH - CHECKBOX_RIGHT_INSET}
|
|
101
104
|
/>
|
|
102
105
|
) : null}
|
|
106
|
+
{iconPosition === "left" && item.icon && (
|
|
107
|
+
<>
|
|
108
|
+
{renderIcon(item.icon)}
|
|
109
|
+
<Spacer.Horizontal size={8} />
|
|
110
|
+
</>
|
|
111
|
+
)}
|
|
103
112
|
{tokens.map((token, j) => (
|
|
104
113
|
<span
|
|
105
114
|
key={`${item.value}-token-${j}`}
|
|
@@ -112,7 +121,7 @@ export const ComboboxMenu = memoGeneric(
|
|
|
112
121
|
</span>
|
|
113
122
|
))}
|
|
114
123
|
</div>
|
|
115
|
-
{(item.shortcut || item.icon) && (
|
|
124
|
+
{(item.shortcut || (item.icon && iconPosition === "right")) && (
|
|
116
125
|
<>
|
|
117
126
|
{item.shortcut ? (
|
|
118
127
|
<KeyboardShortcut shortcut={item.shortcut} />
|
|
@@ -138,8 +138,8 @@ export const Dialog = forwardRef(function Dialog(
|
|
|
138
138
|
className="z-[1]"
|
|
139
139
|
style={{
|
|
140
140
|
position: "absolute",
|
|
141
|
-
top: "var(--dialog-padding)",
|
|
142
|
-
right: "var(--dialog-padding)",
|
|
141
|
+
top: "var(--n-dialog-padding)",
|
|
142
|
+
right: "var(--n-dialog-padding)",
|
|
143
143
|
}}
|
|
144
144
|
/>
|
|
145
145
|
</DialogPrimitive.Close>
|
|
@@ -11,7 +11,7 @@ const FillButton = forwardRef<
|
|
|
11
11
|
<button
|
|
12
12
|
ref={ref}
|
|
13
13
|
className={cx(
|
|
14
|
-
`outline-none p-0 w-[50px] h-input-height 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)] `,
|
|
14
|
+
`outline-none p-0 w-[50px] h-input-height rounded overflow-hidden border-none shadow-[0_0_0_1px_var(--n-divider)_inset] bg-transparent relative focus:shadow-[0_0_0_1px_var(--n-sidebar-background),0_0_0_3px_var(--n-primary)] `,
|
|
15
15
|
className
|
|
16
16
|
)}
|
|
17
17
|
{...props}
|
package/src/components/Grid.tsx
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { useFileDropTarget } from "@noya-app/react-utils";
|
|
2
|
-
import React, { useImperativeHandle, useRef, useState } from "react";
|
|
3
1
|
import {
|
|
4
2
|
forwardRefGeneric,
|
|
5
3
|
memoGeneric,
|
|
6
|
-
|
|
4
|
+
useFileDropTarget,
|
|
5
|
+
} from "@noya-app/react-utils";
|
|
6
|
+
import React, { useImperativeHandle, useRef, useState } from "react";
|
|
7
7
|
import { cx } from "../utils/classNames";
|
|
8
8
|
import { updateSelection } from "../utils/selection";
|
|
9
9
|
import { ActionMenu } from "./ActionMenu";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
CollectionItemSize,
|
|
12
|
+
CollectionProps,
|
|
13
|
+
CollectionRef,
|
|
14
|
+
} from "./Collection";
|
|
11
15
|
import { EditableText } from "./EditableText";
|
|
12
16
|
import { GridView } from "./GridView";
|
|
13
17
|
import { ListView } from "./ListView";
|
|
14
18
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
export const getGridSize = (size: GridViewSize) => {
|
|
19
|
+
export const getGridSize = (size: CollectionItemSize) => {
|
|
18
20
|
// Define size ranges that allow items to grow/shrink within bounds
|
|
19
21
|
const sizes: Record<
|
|
20
|
-
Exclude<
|
|
22
|
+
Exclude<CollectionItemSize, number>,
|
|
21
23
|
{
|
|
22
24
|
minColumnWidth: string;
|
|
23
25
|
gap: number;
|
|
@@ -173,6 +175,7 @@ export const Grid = memoGeneric(
|
|
|
173
175
|
const thumbnail = renderThumbnail?.({
|
|
174
176
|
item,
|
|
175
177
|
selected: isSelected,
|
|
178
|
+
size,
|
|
176
179
|
});
|
|
177
180
|
const onOpenChange = (open: boolean) => {
|
|
178
181
|
setDropdownOpenId(open ? id : undefined);
|
|
@@ -216,9 +219,7 @@ export const Grid = memoGeneric(
|
|
|
216
219
|
testFocused={isTestingRenaming}
|
|
217
220
|
readOnly={!itemIsRenamable || !onRename}
|
|
218
221
|
onSubmit={(value) => {
|
|
219
|
-
|
|
220
|
-
onRename?.(item, value);
|
|
221
|
-
}
|
|
222
|
+
onRename?.(item, value);
|
|
222
223
|
setRenamingId(undefined);
|
|
223
224
|
}}
|
|
224
225
|
onBlur={() => {
|
package/src/components/Label.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { LabelHTMLAttributes, forwardRef, memo } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { mergeConflictingClassNames } from "../utils/classNames";
|
|
3
3
|
|
|
4
4
|
export type LabelPosition = "inset" | "start" | "end" | "above";
|
|
5
5
|
|
|
@@ -17,11 +17,16 @@ export const Label = memo(
|
|
|
17
17
|
return (
|
|
18
18
|
<label
|
|
19
19
|
ref={ref}
|
|
20
|
-
className={
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
className={mergeConflictingClassNames(
|
|
21
|
+
[
|
|
22
|
+
labelStyles,
|
|
23
|
+
labelTextStyles,
|
|
24
|
+
"text-left min-h-input-height",
|
|
25
|
+
className,
|
|
26
|
+
],
|
|
27
|
+
{
|
|
28
|
+
categories: ["color", "font"],
|
|
29
|
+
}
|
|
25
30
|
)}
|
|
26
31
|
{...props}
|
|
27
32
|
>
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
LabelContext,
|
|
5
5
|
LabelPositionContext,
|
|
6
6
|
LabelPositionContextValue,
|
|
7
|
+
useLabelPosition,
|
|
7
8
|
useLabelWidth,
|
|
8
9
|
} from "../hooks/useLabel";
|
|
9
10
|
import { cx } from "../utils/classNames";
|
|
@@ -23,7 +24,7 @@ const labelPositionInset: LabelPositionContextValue = {
|
|
|
23
24
|
export const LabeledField = memo(function LabeledField({
|
|
24
25
|
children,
|
|
25
26
|
label,
|
|
26
|
-
labelPosition
|
|
27
|
+
labelPosition: labelPositionProp,
|
|
27
28
|
fieldId,
|
|
28
29
|
minWidth = 100,
|
|
29
30
|
className,
|
|
@@ -44,6 +45,10 @@ export const LabeledField = memo(function LabeledField({
|
|
|
44
45
|
const labelWidthFromContext = useLabelWidth();
|
|
45
46
|
const labelWidth = labelWidthFromContext ?? minWidth;
|
|
46
47
|
|
|
48
|
+
const labelPositionFromContext = useLabelPosition();
|
|
49
|
+
const labelPosition =
|
|
50
|
+
labelPositionProp ?? labelPositionFromContext ?? "start";
|
|
51
|
+
|
|
47
52
|
const labeledFieldClasses = useMemo(
|
|
48
53
|
() => labeledFieldStyles(labelPosition),
|
|
49
54
|
[labelPosition]
|
package/src/components/List.tsx
CHANGED
|
@@ -8,13 +8,16 @@ import { cssVars } from "../theme";
|
|
|
8
8
|
import { cx } from "../utils/classNames";
|
|
9
9
|
import { updateSelection } from "../utils/selection";
|
|
10
10
|
import { ActionMenu } from "./ActionMenu";
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
CollectionItemSize,
|
|
13
|
+
CollectionProps,
|
|
14
|
+
CollectionRef,
|
|
15
|
+
} from "./Collection";
|
|
13
16
|
import { ListView, ListViewItemInfo } from "./ListView";
|
|
14
17
|
import { TreeView } from "./TreeView";
|
|
15
18
|
|
|
16
19
|
const cssVarOverrides = {
|
|
17
|
-
"--icon-selected": cssVars.colors.primary,
|
|
20
|
+
"--n-icon-selected": cssVars.colors.primary,
|
|
18
21
|
};
|
|
19
22
|
|
|
20
23
|
const emptyArray: string[] = [];
|
|
@@ -60,6 +63,7 @@ export const List = memoGeneric(
|
|
|
60
63
|
getDropTargetParentIndex,
|
|
61
64
|
getPlaceholder,
|
|
62
65
|
onClickItem,
|
|
66
|
+
dragIndicatorStyle,
|
|
63
67
|
} = props;
|
|
64
68
|
|
|
65
69
|
const [internalHoveredId, setHoveredId] = useState<string>();
|
|
@@ -148,6 +152,7 @@ export const List = memoGeneric(
|
|
|
148
152
|
const thumbnail = renderThumbnail?.({
|
|
149
153
|
item,
|
|
150
154
|
selected: isSelected,
|
|
155
|
+
size,
|
|
151
156
|
});
|
|
152
157
|
const onOpenChange = (open: boolean) => {
|
|
153
158
|
setDropdownOpenId(open ? id : undefined);
|
|
@@ -168,6 +173,7 @@ export const List = memoGeneric(
|
|
|
168
173
|
onSelect={(action) => handleMenuAction(action, item)}
|
|
169
174
|
selected={isSelected}
|
|
170
175
|
onOpenChange={onOpenChange}
|
|
176
|
+
variant="bare"
|
|
171
177
|
/>
|
|
172
178
|
));
|
|
173
179
|
|
|
@@ -229,6 +235,7 @@ export const List = memoGeneric(
|
|
|
229
235
|
if (!expandable) return;
|
|
230
236
|
setExpanded?.(item, !expanded);
|
|
231
237
|
}}
|
|
238
|
+
dragIndicatorStyle={dragIndicatorStyle}
|
|
232
239
|
>
|
|
233
240
|
<div
|
|
234
241
|
className={cx("flex flex-1 items-center px-2", rowGapMap[size])}
|
|
@@ -236,9 +243,10 @@ export const List = memoGeneric(
|
|
|
236
243
|
{thumbnail && (
|
|
237
244
|
<div
|
|
238
245
|
className={cx(
|
|
239
|
-
"
|
|
246
|
+
"overflow-hidden flex-none flex items-center justify-center",
|
|
240
247
|
thumbnailSize === "auto" && thumbnailSizeMap[size],
|
|
241
|
-
isSelected && "text-primary"
|
|
248
|
+
isSelected && "text-primary",
|
|
249
|
+
size === "small" ? "rounded-sm" : "rounded"
|
|
242
250
|
)}
|
|
243
251
|
tabIndex={-1}
|
|
244
252
|
>
|
|
@@ -255,9 +263,7 @@ export const List = memoGeneric(
|
|
|
255
263
|
className={fontStyleMap[size]}
|
|
256
264
|
autoFocus={!isTestingRenaming}
|
|
257
265
|
onSubmitEditing={(value: string) => {
|
|
258
|
-
|
|
259
|
-
onRename?.(item, value);
|
|
260
|
-
}
|
|
266
|
+
onRename?.(item, value);
|
|
261
267
|
setRenamingId(undefined);
|
|
262
268
|
}}
|
|
263
269
|
onKeyDown={(e: React.KeyboardEvent) => {
|
|
@@ -316,37 +322,37 @@ const DetailContainer = memo(function DetailContainer({
|
|
|
316
322
|
);
|
|
317
323
|
});
|
|
318
324
|
|
|
319
|
-
const pyMap: Record<
|
|
320
|
-
xxs: "py-
|
|
321
|
-
xs: "py-
|
|
322
|
-
small: "py-
|
|
325
|
+
const pyMap: Record<CollectionItemSize, string> = {
|
|
326
|
+
xxs: "py-0.5",
|
|
327
|
+
xs: "py-0.5",
|
|
328
|
+
small: "py-0.5",
|
|
323
329
|
medium: "py-1",
|
|
324
330
|
large: "py-2",
|
|
325
331
|
xl: "py-3",
|
|
326
332
|
};
|
|
327
333
|
|
|
328
|
-
const thumbnailSizeMap: Record<
|
|
329
|
-
xxs: "w-
|
|
330
|
-
xs: "w-
|
|
331
|
-
small: "w-
|
|
334
|
+
const thumbnailSizeMap: Record<CollectionItemSize, string> = {
|
|
335
|
+
xxs: "w-5 h-5",
|
|
336
|
+
xs: "w-5 h-5",
|
|
337
|
+
small: "w-5 h-5",
|
|
332
338
|
medium: "w-8 h-8",
|
|
333
339
|
large: "w-16 h-16",
|
|
334
340
|
xl: "w-24 h-24",
|
|
335
341
|
};
|
|
336
342
|
|
|
337
|
-
const rowGapMap: Record<
|
|
338
|
-
xxs: "gap-
|
|
339
|
-
xs: "gap-
|
|
340
|
-
small: "gap-
|
|
343
|
+
const rowGapMap: Record<CollectionItemSize, string> = {
|
|
344
|
+
xxs: "gap-2",
|
|
345
|
+
xs: "gap-2",
|
|
346
|
+
small: "gap-2",
|
|
341
347
|
medium: "gap-3",
|
|
342
348
|
large: "gap-3",
|
|
343
349
|
xl: "gap-4",
|
|
344
350
|
};
|
|
345
351
|
|
|
346
|
-
const fontStyleMap: Record<
|
|
347
|
-
xxs: "font-medium",
|
|
348
|
-
xs: "font-medium",
|
|
349
|
-
small: "font-medium",
|
|
352
|
+
const fontStyleMap: Record<CollectionItemSize, string> = {
|
|
353
|
+
xxs: "font-medium text-list-small",
|
|
354
|
+
xs: "font-medium text-list-small",
|
|
355
|
+
small: "font-medium text-list-small",
|
|
350
356
|
medium: "font-medium",
|
|
351
357
|
large: "font-medium",
|
|
352
358
|
xl: "font-medium text-heading4 text-text",
|
|
@@ -26,7 +26,7 @@ import { ListChildComponentProps, VariableSizeList } from "react-window";
|
|
|
26
26
|
import { mergeEventHandlers } from "../hooks/mergeEventHandlers";
|
|
27
27
|
import { useHover } from "../hooks/useHover";
|
|
28
28
|
import { cssVars, INPUT_HEIGHT } from "../theme";
|
|
29
|
-
import { cx } from "../utils/classNames";
|
|
29
|
+
import { cx, mergeConflictingClassNames } from "../utils/classNames";
|
|
30
30
|
import { ContextMenu } from "./ContextMenu";
|
|
31
31
|
import { InputField } from "./InputField";
|
|
32
32
|
import { MenuItem } from "./internal/Menu";
|
|
@@ -376,7 +376,7 @@ interface ListViewClickInfo {
|
|
|
376
376
|
ctrlKey: boolean;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
interface ListViewRowProps<MenuItemType extends string = string> {
|
|
379
|
+
export interface ListViewRowProps<MenuItemType extends string = string> {
|
|
380
380
|
id?: string;
|
|
381
381
|
tabIndex?: number;
|
|
382
382
|
role?: string;
|
|
@@ -1044,9 +1044,14 @@ const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
|
|
|
1044
1044
|
aria-labelledby={ariaLabelledby}
|
|
1045
1045
|
aria-orientation={ariaOrientation}
|
|
1046
1046
|
aria-multiselectable={ariaMultiselectable}
|
|
1047
|
-
className={
|
|
1048
|
-
|
|
1049
|
-
|
|
1047
|
+
className={mergeConflictingClassNames(
|
|
1048
|
+
[
|
|
1049
|
+
`flex flex-col text-text-muted ${scrollable ? "flex-1" : "flex-none"} `,
|
|
1050
|
+
className,
|
|
1051
|
+
],
|
|
1052
|
+
{
|
|
1053
|
+
categories: ["flex"],
|
|
1054
|
+
}
|
|
1050
1055
|
)}
|
|
1051
1056
|
style={{ ...gapStyle, ...style }}
|
|
1052
1057
|
{...{
|
|
@@ -2,9 +2,10 @@ import { ImageIcon, SpeakerLoudIcon, VideoIcon } from "@noya-app/noya-icons";
|
|
|
2
2
|
import React, { memo, useMemo } from "react";
|
|
3
3
|
import { cssVars } from "../theme";
|
|
4
4
|
import { cx } from "../utils/classNames";
|
|
5
|
+
import { CollectionItemSize } from "./Collection";
|
|
5
6
|
import { IconName, Icons } from "./Icons";
|
|
6
7
|
|
|
7
|
-
type ColorScheme = "primary" | "icon" | "warning";
|
|
8
|
+
type ColorScheme = "primary" | "secondary" | "icon" | "warning";
|
|
8
9
|
|
|
9
10
|
type AssetType = "image" | "video" | "audio";
|
|
10
11
|
|
|
@@ -29,9 +30,13 @@ type MediaThumbnailProps = {
|
|
|
29
30
|
* If provided, use this icon instead of the default one for the asset type
|
|
30
31
|
*/
|
|
31
32
|
iconName?: IconName;
|
|
33
|
+
size?: CollectionItemSize;
|
|
32
34
|
};
|
|
33
35
|
|
|
34
|
-
const
|
|
36
|
+
export const getThumbnailColors = (
|
|
37
|
+
colorScheme: ColorScheme,
|
|
38
|
+
selected: boolean
|
|
39
|
+
) => {
|
|
35
40
|
if (selected) {
|
|
36
41
|
return {
|
|
37
42
|
icon: cssVars.colors.primary,
|
|
@@ -45,6 +50,11 @@ const getColors = (colorScheme: ColorScheme, selected: boolean) => {
|
|
|
45
50
|
icon: cssVars.colors.primary,
|
|
46
51
|
background: cssVars.colors.listViewThumbnailBackground,
|
|
47
52
|
};
|
|
53
|
+
case "secondary":
|
|
54
|
+
return {
|
|
55
|
+
icon: cssVars.colors.secondary,
|
|
56
|
+
background: cssVars.colors.secondaryPastel,
|
|
57
|
+
};
|
|
48
58
|
case "warning":
|
|
49
59
|
return {
|
|
50
60
|
icon: cssVars.colors.warning,
|
|
@@ -59,11 +69,6 @@ const getColors = (colorScheme: ColorScheme, selected: boolean) => {
|
|
|
59
69
|
}
|
|
60
70
|
};
|
|
61
71
|
|
|
62
|
-
const iconStyles = {
|
|
63
|
-
width: "max(15px, 20%)",
|
|
64
|
-
height: "max(15px, 20%)",
|
|
65
|
-
};
|
|
66
|
-
|
|
67
72
|
export const MediaThumbnail = memo(function MediaThumbnail({
|
|
68
73
|
contentType: contentTypeProp,
|
|
69
74
|
selected = false,
|
|
@@ -71,12 +76,20 @@ export const MediaThumbnail = memo(function MediaThumbnail({
|
|
|
71
76
|
colorScheme = "icon",
|
|
72
77
|
url,
|
|
73
78
|
iconName = "FileIcon",
|
|
79
|
+
size = "medium",
|
|
74
80
|
}: MediaThumbnailProps) {
|
|
75
|
-
const { icon: iconColor, background: backgroundColor } =
|
|
81
|
+
const { icon: iconColor, background: backgroundColor } = getThumbnailColors(
|
|
76
82
|
colorScheme,
|
|
77
83
|
selected
|
|
78
84
|
);
|
|
79
85
|
const contentType = getAssetType(contentTypeProp);
|
|
86
|
+
const iconStyles = useMemo(
|
|
87
|
+
() => ({
|
|
88
|
+
width: iconSizeMap[size],
|
|
89
|
+
height: iconSizeMap[size],
|
|
90
|
+
}),
|
|
91
|
+
[size]
|
|
92
|
+
);
|
|
80
93
|
|
|
81
94
|
const content = useMemo(() => {
|
|
82
95
|
switch (contentType) {
|
|
@@ -101,7 +114,7 @@ export const MediaThumbnail = memo(function MediaThumbnail({
|
|
|
101
114
|
const Icon = Icons[iconName];
|
|
102
115
|
return <Icon color={iconColor} style={iconStyles} />;
|
|
103
116
|
}
|
|
104
|
-
}, [contentType, url, iconColor, iconName]);
|
|
117
|
+
}, [contentType, url, iconColor, iconStyles, iconName]);
|
|
105
118
|
|
|
106
119
|
return (
|
|
107
120
|
<div
|
|
@@ -115,3 +128,12 @@ export const MediaThumbnail = memo(function MediaThumbnail({
|
|
|
115
128
|
</div>
|
|
116
129
|
);
|
|
117
130
|
});
|
|
131
|
+
|
|
132
|
+
const iconSizeMap: Record<CollectionItemSize, number | string> = {
|
|
133
|
+
xxs: 12,
|
|
134
|
+
xs: 12,
|
|
135
|
+
small: 12,
|
|
136
|
+
medium: "max(15px, 20%)",
|
|
137
|
+
large: "max(15px, 20%)",
|
|
138
|
+
xl: "max(15px, 20%)",
|
|
139
|
+
};
|