@noya-app/noya-designsystem 0.1.64 → 0.1.65
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 +13 -10
- package/CHANGELOG.md +12 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +501 -228
- package/dist/index.d.ts +501 -228
- package/dist/index.js +6738 -2571
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6697 -2499
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/components/ActivityIndicator.tsx +9 -4
- package/src/components/ActivityLog.tsx +197 -0
- package/src/components/AnimatePresence.tsx +37 -22
- package/src/components/Avatar.tsx +42 -25
- package/src/components/Banner.tsx +57 -11
- package/src/components/BaseToolbar.tsx +29 -7
- package/src/components/Breadcrumbs.tsx +2 -2
- package/src/components/Button.tsx +23 -24
- package/src/components/Checkbox.tsx +6 -35
- package/src/components/Chip.tsx +45 -33
- package/src/components/Collection.tsx +16 -11
- package/src/components/ColorSwatch.tsx +3 -3
- package/src/components/ColorSwatchControl.tsx +2 -2
- package/src/components/Combobox.tsx +6 -6
- package/src/components/ComboboxMenu.tsx +6 -5
- package/src/components/CommandPalette.tsx +1 -1
- package/src/components/Dialog.tsx +6 -12
- package/src/components/Divider.tsx +8 -8
- package/src/components/DraggableMenuButton.tsx +9 -5
- package/src/components/Drawer.tsx +5 -5
- package/src/components/DropdownMenu.tsx +1 -1
- package/src/components/EditableText.tsx +2 -2
- package/src/components/Fade.tsx +13 -13
- package/src/components/FileUploadIndicator.tsx +11 -11
- package/src/components/FloatingWindow.tsx +2 -2
- package/src/components/Grid.tsx +18 -11
- package/src/components/GridView.tsx +32 -25
- package/src/components/IVirtualizedList.tsx +5 -0
- package/src/components/Icons.tsx +24 -4
- package/src/components/InputField.tsx +19 -19
- package/src/components/InspectorContainer.tsx +2 -2
- package/src/components/InspectorPrimitives.tsx +15 -9
- package/src/components/Label.tsx +4 -3
- package/src/components/LabeledElementView.tsx +3 -3
- package/src/components/LabeledField.tsx +6 -6
- package/src/components/List.tsx +103 -45
- package/src/components/ListMenu.tsx +91 -0
- package/src/components/ListNavigator.tsx +106 -0
- package/src/components/ListView.tsx +20 -1158
- package/src/components/MediaThumbnail.tsx +56 -15
- package/src/components/Message.tsx +5 -5
- package/src/components/Navigator.tsx +461 -0
- package/src/components/NoyaLogo.tsx +1 -1
- package/src/components/Popover.tsx +9 -5
- package/src/components/Progress.tsx +19 -9
- package/src/components/ResizableContainer.tsx +187 -0
- package/src/components/RingProgress.tsx +128 -0
- package/src/components/ScrollArea.tsx +4 -4
- package/src/components/ScrollableSidebar.tsx +10 -0
- package/src/components/SearchCompletionMenu.tsx +3 -3
- package/src/components/Section.tsx +107 -57
- package/src/components/SegmentedControl.tsx +29 -29
- package/src/components/SelectMenu.tsx +13 -20
- package/src/components/SelectionToolbar.tsx +4 -3
- package/src/components/Slider.tsx +9 -9
- package/src/components/Spacer.tsx +2 -2
- package/src/components/StackNavigator.tsx +378 -0
- package/src/components/Stepper.tsx +88 -0
- package/src/components/Switch.tsx +4 -4
- package/src/components/Tabs.tsx +3 -3
- package/src/components/Text.tsx +23 -13
- package/src/components/TextArea.tsx +3 -3
- package/src/components/Toast.tsx +4 -4
- package/src/components/Toolbar.tsx +50 -9
- package/src/components/ToolbarDrawer.tsx +2 -2
- package/src/components/Tooltip.tsx +1 -1
- package/src/components/TreeView.tsx +11 -4
- package/src/components/UserPointer.tsx +4 -4
- package/src/components/ai-assistant/AIAssistantLayout.tsx +8 -8
- package/src/components/blocks/ImageBlockComponent.tsx +13 -7
- package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +4 -4
- package/src/components/file-explorer/FileExplorerLayout.tsx +20 -8
- package/src/components/internal/Checkmark.tsx +1 -1
- package/src/components/internal/Menu.tsx +22 -18
- package/src/components/internal/MenuViewport.tsx +13 -6
- package/src/components/internal/SelectItem.tsx +3 -3
- package/src/components/internal/TextInput.tsx +5 -1
- package/src/components/listView/ListViewContexts.tsx +68 -0
- package/src/components/listView/ListViewEditableRowTitle.tsx +55 -0
- package/src/components/listView/ListViewRoot.tsx +521 -0
- package/src/components/listView/ListViewRow.tsx +475 -0
- package/src/components/listView/ListViewRowTitle.tsx +21 -0
- package/src/components/listView/types.ts +11 -0
- package/src/components/pipeline/PipelineResultLayout.tsx +6 -6
- package/src/components/sorting/DragRegistration.tsx +2 -1
- package/src/components/sorting/SharedDragProvider.tsx +91 -9
- package/src/components/sorting/Sortable.tsx +71 -17
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +5 -5
- package/src/components/workspace/PanelWorkspaceLayout.tsx +65 -49
- package/src/components/workspace/VerticalTabMenu.tsx +25 -15
- package/src/components/workspace/WorkspaceLayout.tsx +30 -21
- package/src/contexts/DialogContext.tsx +17 -5
- package/src/hooks/useIndent.ts +3 -8
- package/src/index.css +24 -10
- package/src/index.tsx +10 -5
- package/src/utils/classNames.ts +52 -6
- package/src/utils/editableBlockStyles.ts +2 -2
- package/src/utils/formatByteSize.ts +1 -0
- package/src/utils/inputs.ts +8 -6
- package/src/utils/sketchColor.ts +0 -34
- package/tailwind.config.ts +1 -0
- package/src/components/FillInputField.tsx +0 -37
- package/src/components/FillPreviewBackground.tsx +0 -134
- package/src/components/GradientPicker.tsx +0 -90
- package/src/utils/getGradientBackground.tsx +0 -31
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clamp } from "@noya-app/noya-utils";
|
|
4
|
+
import React, { FocusEventHandler, memo, useCallback, useMemo } from "react";
|
|
5
|
+
import { useLabel } from "../hooks/useLabel";
|
|
6
|
+
import { cx } from "../utils/classNames";
|
|
7
|
+
import { Button } from "./Button";
|
|
8
|
+
import { InputField } from "./InputField";
|
|
9
|
+
|
|
10
|
+
type ColorScheme = "primary" | "secondary";
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
id?: string;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
className?: string;
|
|
16
|
+
value: number;
|
|
17
|
+
onValueChange: (value: number) => void;
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
step?: number;
|
|
21
|
+
colorScheme?: ColorScheme;
|
|
22
|
+
onFocus?: FocusEventHandler;
|
|
23
|
+
onBlur?: FocusEventHandler;
|
|
24
|
+
readOnly?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const Stepper = memo(function Stepper({
|
|
28
|
+
style,
|
|
29
|
+
className,
|
|
30
|
+
value: valueProp,
|
|
31
|
+
onValueChange,
|
|
32
|
+
min,
|
|
33
|
+
max,
|
|
34
|
+
step = 1,
|
|
35
|
+
colorScheme,
|
|
36
|
+
onFocus,
|
|
37
|
+
onBlur,
|
|
38
|
+
readOnly = false,
|
|
39
|
+
...props
|
|
40
|
+
}: Props) {
|
|
41
|
+
const { fieldId: id } = useLabel({
|
|
42
|
+
fieldId: props.id,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const value = useMemo(() => {
|
|
46
|
+
return clamp(valueProp, min, max);
|
|
47
|
+
}, [valueProp, min, max]);
|
|
48
|
+
|
|
49
|
+
const handleValueChange = useCallback(
|
|
50
|
+
(value: number) => {
|
|
51
|
+
const newValue = clamp(value, min, max);
|
|
52
|
+
onValueChange(newValue);
|
|
53
|
+
},
|
|
54
|
+
[onValueChange, min, max]
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
id={id}
|
|
60
|
+
className={cx(
|
|
61
|
+
"n-flex n-relative n-items-center n-select-none n-touch-none n-h-input-height n-rounded n-flex-grow n-max-h-input-height n-gap-1.5",
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
style={style}
|
|
65
|
+
onFocus={onFocus}
|
|
66
|
+
onBlur={onBlur}
|
|
67
|
+
>
|
|
68
|
+
<Button
|
|
69
|
+
icon="MinusIcon"
|
|
70
|
+
disabled={readOnly}
|
|
71
|
+
onClick={() => handleValueChange(value - step)}
|
|
72
|
+
/>
|
|
73
|
+
<InputField.Root className="n-flex-1">
|
|
74
|
+
<InputField.NumberInput
|
|
75
|
+
value={value}
|
|
76
|
+
onChange={handleValueChange}
|
|
77
|
+
onNudge={(amount) => handleValueChange(value + amount)}
|
|
78
|
+
readOnly={readOnly}
|
|
79
|
+
/>
|
|
80
|
+
</InputField.Root>
|
|
81
|
+
<Button
|
|
82
|
+
icon="PlusIcon"
|
|
83
|
+
disabled={readOnly}
|
|
84
|
+
onClick={() => handleValueChange(value + step)}
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
});
|
|
@@ -40,15 +40,15 @@ export const Switch = function Switch({
|
|
|
40
40
|
onChange(newValue);
|
|
41
41
|
}}
|
|
42
42
|
className={cx(
|
|
43
|
-
"all-unset w-8 h-[19px] bg-active-background rounded-full relative cursor-pointer ring-offset-background [-webkit-tap-highlight-color:rgba(0,0,0,0)] focus:ring-2 focus:ring-primary focus:ring-offset-[1px] outline-none data-[state=checked]:bg-primary transition-all",
|
|
44
|
-
colorScheme === "secondary" && "data-[state=checked]:bg-secondary",
|
|
45
|
-
"focus:z-interactable",
|
|
43
|
+
"n-all-unset n-w-8 n-h-[19px] n-bg-active-background n-rounded-full n-relative n-cursor-pointer n-ring-offset-background n-[-webkit-tap-highlight-color:rgba(0,0,0,0)] focus:n-ring-2 focus:n-ring-primary focus:n-ring-offset-[1px] n-outline-none data-[state=checked]:n-bg-primary n-transition-all",
|
|
44
|
+
colorScheme === "secondary" && "data-[state=checked]:n-bg-secondary",
|
|
45
|
+
"focus:n-z-interactable",
|
|
46
46
|
className
|
|
47
47
|
)}
|
|
48
48
|
onFocus={onFocus}
|
|
49
49
|
onBlur={onBlur}
|
|
50
50
|
>
|
|
51
|
-
<SwitchPrimitive.Thumb className="block w-[15px] h-[15px] bg-background rounded-full transition-transform translate-x-[2px] data-[state=checked]:translate-x-[15px]" />
|
|
51
|
+
<SwitchPrimitive.Thumb className="n-block n-w-[15px] n-h-[15px] n-bg-background n-rounded-full n-transition-transform n-translate-x-[2px] data-[state=checked]:n-translate-x-[15px]" />
|
|
52
52
|
</SwitchPrimitive.Root>
|
|
53
53
|
);
|
|
54
54
|
};
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -31,10 +31,10 @@ export function Tabs<T extends string = string>({
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
return (
|
|
34
|
-
<div {...props} className={cx("flex flex-col", props.className)}>
|
|
35
|
-
<div className="flex flex-row px-3">
|
|
34
|
+
<div {...props} className={cx("n-flex n-flex-col", props.className)}>
|
|
35
|
+
<div className="n-flex n-flex-row n-px-3">
|
|
36
36
|
<SegmentedControl
|
|
37
|
-
className="flex-1"
|
|
37
|
+
className="n-flex-1"
|
|
38
38
|
value={activeTab}
|
|
39
39
|
onValueChange={setActiveTab}
|
|
40
40
|
variant={variant}
|
package/src/components/Text.tsx
CHANGED
|
@@ -15,6 +15,7 @@ type Variant =
|
|
|
15
15
|
| "heading5"
|
|
16
16
|
| "body"
|
|
17
17
|
| "small"
|
|
18
|
+
| "xs"
|
|
18
19
|
| "button"
|
|
19
20
|
| "code"
|
|
20
21
|
| "label";
|
|
@@ -29,24 +30,26 @@ const elements: Record<Variant, React.HTMLElementType> = {
|
|
|
29
30
|
heading5: "h5",
|
|
30
31
|
body: "p",
|
|
31
32
|
small: "span",
|
|
33
|
+
xs: "span",
|
|
32
34
|
button: "span",
|
|
33
35
|
code: "code",
|
|
34
36
|
label: "span",
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
export const textStyles: Record<Variant, string> = {
|
|
38
|
-
title: "font-sans text-title font-bold",
|
|
39
|
-
subtitle: "font-sans text-subtitle font-medium",
|
|
40
|
-
heading1: "font-sans text-heading1 font-semibold",
|
|
41
|
-
heading2: "font-sans text-heading2 font-medium",
|
|
42
|
-
heading3: "font-sans text-heading3 font-normal",
|
|
43
|
-
heading4: "font-sans text-heading4 font-medium",
|
|
44
|
-
heading5: "font-sans text-heading5 font-medium",
|
|
45
|
-
body: "font-sans text-
|
|
46
|
-
small: "font-sans text-heading5 font-normal",
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
title: "n-font-sans n-text-title n-font-bold",
|
|
41
|
+
subtitle: "n-font-sans n-text-subtitle n-font-medium",
|
|
42
|
+
heading1: "n-font-sans n-text-heading1 n-font-semibold",
|
|
43
|
+
heading2: "n-font-sans n-text-heading2 n-font-medium",
|
|
44
|
+
heading3: "n-font-sans n-text-heading3 n-font-normal",
|
|
45
|
+
heading4: "n-font-sans n-text-heading4 n-font-medium",
|
|
46
|
+
heading5: "n-font-sans n-text-heading5 n-font-medium",
|
|
47
|
+
body: "n-font-sans n-text-body n-font-normal",
|
|
48
|
+
small: "n-font-sans n-text-heading5 n-font-normal",
|
|
49
|
+
xs: "n-font-sans n-text-xs n-font-normal",
|
|
50
|
+
button: "n-font-sans n-text-button n-font-medium",
|
|
51
|
+
code: "n-font-mono n-text-code",
|
|
52
|
+
label: "n-font-sans n-text-label n-font-normal n-uppercase",
|
|
50
53
|
} as const;
|
|
51
54
|
|
|
52
55
|
export type TextProps = {
|
|
@@ -86,7 +89,8 @@ export const Text = forwardRef(function Text(
|
|
|
86
89
|
<Component
|
|
87
90
|
ref={forwardedRef}
|
|
88
91
|
className={cx(
|
|
89
|
-
|
|
92
|
+
textStyles[variant],
|
|
93
|
+
`n-text-${camelToKebabCase(String(color)) ?? "text"}`,
|
|
90
94
|
className
|
|
91
95
|
)}
|
|
92
96
|
style={style}
|
|
@@ -145,6 +149,12 @@ export const Small = forwardRef(
|
|
|
145
149
|
)
|
|
146
150
|
);
|
|
147
151
|
|
|
152
|
+
export const ExtraSmall = forwardRef(
|
|
153
|
+
(props: PresetProps, ref: ForwardedRef<HTMLElement>) => (
|
|
154
|
+
<Text ref={ref} {...props} variant="xs" />
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
|
|
148
158
|
// export const Label = forwardRef(
|
|
149
159
|
// (props: PresetProps, ref: ForwardedRef<HTMLElement>) => (
|
|
150
160
|
// <Text ref={ref} {...props} variant="label" />
|
|
@@ -68,7 +68,7 @@ export const TextArea = memo(
|
|
|
68
68
|
return (
|
|
69
69
|
<textarea
|
|
70
70
|
className={cx(
|
|
71
|
-
`font-sans text-heading5 font-normal text-text bg-input-background flex-1 py-1 px-1.5 border-none outline-none min-h-6 w-full rounded resize-none placeholder:text-text-disabled focus:ring-2 focus:ring-primary read-only:text-text-disabled focus:z-interactable transition-
|
|
71
|
+
`n-font-sans n-text-heading5 n-font-normal n-text-text n-bg-input-background n-flex-1 n-py-1 n-px-1.5 n-border-none n-outline-none n-min-h-6 n-w-full n-rounded n-resize-none placeholder:n-text-text-disabled focus:n-ring-2 focus:n-ring-primary read-only:n-text-text-disabled focus:n-z-interactable n-transition-[box-shadow]`,
|
|
72
72
|
className
|
|
73
73
|
)}
|
|
74
74
|
{...rest}
|
|
@@ -102,10 +102,10 @@ export const TextAreaRow = memo(
|
|
|
102
102
|
return (
|
|
103
103
|
<div
|
|
104
104
|
ref={forwardedRef}
|
|
105
|
-
className={cx("relative w-full h-full", className)}
|
|
105
|
+
className={cx("n-relative n-w-full n-h-full", className)}
|
|
106
106
|
>
|
|
107
107
|
<TextArea className={textAreaClassName} {...rest} ref={textAreaRef} />
|
|
108
|
-
<div className={cx("absolute right-1 top-4", endClassName)}>{end}</div>
|
|
108
|
+
<div className={cx("n-absolute n-right-1 n-top-4", endClassName)}>{end}</div>
|
|
109
109
|
</div>
|
|
110
110
|
);
|
|
111
111
|
})
|
package/src/components/Toast.tsx
CHANGED
|
@@ -15,18 +15,18 @@ export const Toast = ({
|
|
|
15
15
|
}) => {
|
|
16
16
|
return (
|
|
17
17
|
<ToastPrimitive.Root
|
|
18
|
-
className="px-2 py-2.5 grid grid-cols-[auto_max-content] gap-x-2.5 items-center rounded text-sm bg-popover-background shadow-popover text-text-muted"
|
|
18
|
+
className="n-px-2 n-py-2.5 n-grid n-grid-cols-[auto_max-content] n-gap-x-2.5 n-items-center n-rounded n-text-sm n-bg-popover-background n-shadow-popover n-text-text-muted"
|
|
19
19
|
{...props}
|
|
20
20
|
>
|
|
21
21
|
{title && (
|
|
22
22
|
<ToastPrimitive.Title
|
|
23
|
-
className={`mb-[5px] ${textStyles.label} font-bold text-text`}
|
|
23
|
+
className={`n-mb-[5px] ${textStyles.label} n-font-bold n-text-text`}
|
|
24
24
|
>
|
|
25
25
|
{title}
|
|
26
26
|
</ToastPrimitive.Title>
|
|
27
27
|
)}
|
|
28
28
|
<ToastPrimitive.Description
|
|
29
|
-
className={`${textStyles.small} text-text-muted`}
|
|
29
|
+
className={`${textStyles.small} n-text-text-muted`}
|
|
30
30
|
>
|
|
31
31
|
{content}
|
|
32
32
|
</ToastPrimitive.Description>
|
|
@@ -45,6 +45,6 @@ export const Toast = ({
|
|
|
45
45
|
export const ToastProvider = ({ children }: { children: React.ReactNode }) => (
|
|
46
46
|
<ToastPrimitive.Provider>
|
|
47
47
|
{children}
|
|
48
|
-
<ToastPrimitive.Viewport className="fixed bottom-0 right-0 flex flex-col p-5
|
|
48
|
+
<ToastPrimitive.Viewport className="n-fixed n-bottom-0 n-right-0 n-flex n-flex-col n-p-5 n-gap-2.5 n-min-w-[200px] n-max-w-[100vw] n-m-0 n-list-none n-z-[2147483647] n-outline-none" />
|
|
49
49
|
</ToastPrimitive.Provider>
|
|
50
50
|
);
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
4
|
-
import React, {
|
|
4
|
+
import React, {
|
|
5
|
+
ComponentProps,
|
|
6
|
+
createContext,
|
|
7
|
+
ReactNode,
|
|
8
|
+
useContext,
|
|
9
|
+
} from "react";
|
|
5
10
|
|
|
6
11
|
import { memoGeneric } from "@noya-app/react-utils";
|
|
7
12
|
import { BaseToolbar } from "./BaseToolbar";
|
|
@@ -24,6 +29,10 @@ import { Tooltip } from "./Tooltip";
|
|
|
24
29
|
|
|
25
30
|
const SIDE_OFFSET = 6;
|
|
26
31
|
|
|
32
|
+
export const ToolbarMenuContext = createContext<{
|
|
33
|
+
dividerOverflow?: number;
|
|
34
|
+
}>({});
|
|
35
|
+
|
|
27
36
|
export const ToolbarMenuDropdown = memoGeneric(function ToolbarMenuDropdown<
|
|
28
37
|
T extends string,
|
|
29
38
|
>({
|
|
@@ -66,7 +75,7 @@ export const ToolbarShortcut = ({
|
|
|
66
75
|
label?: ReactNode;
|
|
67
76
|
}) => {
|
|
68
77
|
return (
|
|
69
|
-
<div className="flex items-center">
|
|
78
|
+
<div className="n-flex n-items-center">
|
|
70
79
|
{label}
|
|
71
80
|
<Spacer.Horizontal size={6} />
|
|
72
81
|
<KeyboardShortcut shortcut={shortcut} />
|
|
@@ -140,20 +149,23 @@ export const ToolbarMenuButton = memoGeneric(function ToolbarMenuButton<
|
|
|
140
149
|
as,
|
|
141
150
|
activeValue,
|
|
142
151
|
tooltipSide,
|
|
152
|
+
displayFilter,
|
|
143
153
|
}: {
|
|
144
154
|
item: SelectableMenuItem<T>;
|
|
145
155
|
onSelectMenuItem?: (value: T) => void;
|
|
146
156
|
as?: ComponentProps<typeof Button>["as"];
|
|
147
157
|
activeValue?: T;
|
|
148
158
|
tooltipSide?: ComponentProps<typeof Tooltip>["side"];
|
|
159
|
+
displayFilter?: DisplayFilter;
|
|
149
160
|
}) {
|
|
150
161
|
const isActive = item.checked || activeValue === item.value;
|
|
162
|
+
|
|
151
163
|
const content = (
|
|
152
164
|
<Button
|
|
153
165
|
as={as}
|
|
154
166
|
disabled={item.disabled}
|
|
155
167
|
active={isActive}
|
|
156
|
-
icon={item.icon}
|
|
168
|
+
icon={displayFilter === "textOnly" ? undefined : item.icon}
|
|
157
169
|
{...(as === "a" && { href: item.value })}
|
|
158
170
|
onClick={() => {
|
|
159
171
|
if (onSelectMenuItem && item.value) {
|
|
@@ -161,14 +173,18 @@ export const ToolbarMenuButton = memoGeneric(function ToolbarMenuButton<
|
|
|
161
173
|
}
|
|
162
174
|
}}
|
|
163
175
|
>
|
|
164
|
-
{item.title}
|
|
176
|
+
{displayFilter === "iconOnly" ? undefined : item.title}
|
|
165
177
|
</Button>
|
|
166
178
|
);
|
|
167
179
|
|
|
180
|
+
const tooltip =
|
|
181
|
+
item.tooltip ??
|
|
182
|
+
(displayFilter === "iconOnly" && item.title ? item.title : undefined);
|
|
183
|
+
|
|
168
184
|
return item.drawer && isActive ? (
|
|
169
185
|
<ToolbarDrawer trigger={content}>{item.drawer}</ToolbarDrawer>
|
|
170
|
-
) :
|
|
171
|
-
<Tooltip sideOffset={SIDE_OFFSET} content={
|
|
186
|
+
) : tooltip ? (
|
|
187
|
+
<Tooltip sideOffset={SIDE_OFFSET} content={tooltip} side={tooltipSide}>
|
|
172
188
|
{content}
|
|
173
189
|
</Tooltip>
|
|
174
190
|
) : (
|
|
@@ -185,6 +201,8 @@ export const ToolbarMenuItem = memoGeneric(function ToolbarMenuItem<
|
|
|
185
201
|
activeValue,
|
|
186
202
|
tooltipSide,
|
|
187
203
|
portalContainer,
|
|
204
|
+
displayFilter,
|
|
205
|
+
dividerOverflow: dividerOverflowProp,
|
|
188
206
|
}: {
|
|
189
207
|
item: MenuItem<T>;
|
|
190
208
|
onSelectMenuItem?: (value: T) => void;
|
|
@@ -192,14 +210,24 @@ export const ToolbarMenuItem = memoGeneric(function ToolbarMenuItem<
|
|
|
192
210
|
activeValue?: T;
|
|
193
211
|
tooltipSide?: ComponentProps<typeof Tooltip>["side"];
|
|
194
212
|
portalContainer?: HTMLElement | null;
|
|
213
|
+
displayFilter?: DisplayFilter;
|
|
214
|
+
dividerOverflow?: number;
|
|
195
215
|
}) {
|
|
216
|
+
const { dividerOverflow: contextDividerOverflow } =
|
|
217
|
+
useContext(ToolbarMenuContext);
|
|
218
|
+
|
|
219
|
+
const dividerOverflow = dividerOverflowProp ?? contextDividerOverflow ?? 4;
|
|
220
|
+
|
|
196
221
|
if (item.type === "sectionHeader") return null;
|
|
222
|
+
|
|
197
223
|
if (item.type === "separator") {
|
|
198
|
-
return <DividerVertical overflow={
|
|
224
|
+
return <DividerVertical overflow={dividerOverflow} />;
|
|
199
225
|
}
|
|
226
|
+
|
|
200
227
|
if (item.type === "popover") {
|
|
201
228
|
return <ToolbarMenuPopover item={item} portalContainer={portalContainer} />;
|
|
202
229
|
}
|
|
230
|
+
|
|
203
231
|
if (isSelectableMenuItem(item)) {
|
|
204
232
|
return (
|
|
205
233
|
<ToolbarMenuButton
|
|
@@ -208,6 +236,7 @@ export const ToolbarMenuItem = memoGeneric(function ToolbarMenuItem<
|
|
|
208
236
|
as={buttonAs}
|
|
209
237
|
activeValue={activeValue}
|
|
210
238
|
tooltipSide={tooltipSide}
|
|
239
|
+
displayFilter={displayFilter}
|
|
211
240
|
/>
|
|
212
241
|
);
|
|
213
242
|
}
|
|
@@ -217,6 +246,8 @@ export const ToolbarMenuItem = memoGeneric(function ToolbarMenuItem<
|
|
|
217
246
|
);
|
|
218
247
|
});
|
|
219
248
|
|
|
249
|
+
type DisplayFilter = "iconOnly" | "iconAndText" | "textOnly";
|
|
250
|
+
|
|
220
251
|
export const ToolbarMenu = memoGeneric(function ToolbarMenu<T extends string>({
|
|
221
252
|
items,
|
|
222
253
|
onSelectMenuItem,
|
|
@@ -224,6 +255,8 @@ export const ToolbarMenu = memoGeneric(function ToolbarMenu<T extends string>({
|
|
|
224
255
|
activeValue,
|
|
225
256
|
tooltipSide,
|
|
226
257
|
portalContainer,
|
|
258
|
+
displayFilter = "iconAndText",
|
|
259
|
+
dividerOverflow,
|
|
227
260
|
}: {
|
|
228
261
|
items: MenuItem<T>[];
|
|
229
262
|
onSelectMenuItem?: (value: T) => void;
|
|
@@ -231,6 +264,8 @@ export const ToolbarMenu = memoGeneric(function ToolbarMenu<T extends string>({
|
|
|
231
264
|
activeValue?: T;
|
|
232
265
|
tooltipSide?: ComponentProps<typeof Tooltip>["side"];
|
|
233
266
|
portalContainer?: HTMLElement | null;
|
|
267
|
+
displayFilter?: DisplayFilter;
|
|
268
|
+
dividerOverflow?: number;
|
|
234
269
|
}) {
|
|
235
270
|
return (
|
|
236
271
|
<>
|
|
@@ -244,6 +279,8 @@ export const ToolbarMenu = memoGeneric(function ToolbarMenu<T extends string>({
|
|
|
244
279
|
activeValue={activeValue}
|
|
245
280
|
tooltipSide={tooltipSide}
|
|
246
281
|
portalContainer={portalContainer}
|
|
282
|
+
displayFilter={displayFilter}
|
|
283
|
+
dividerOverflow={dividerOverflow}
|
|
247
284
|
/>
|
|
248
285
|
);
|
|
249
286
|
})}
|
|
@@ -259,6 +296,7 @@ export interface ToolbarProps<T extends string = string> {
|
|
|
259
296
|
onSelectMenuItem?: (value: T) => void;
|
|
260
297
|
/** Whether to bind keyboard shortcuts for menu items. @default true */
|
|
261
298
|
shouldBindKeyboardShortcuts?: boolean;
|
|
299
|
+
dividerOverflow?: number;
|
|
262
300
|
}
|
|
263
301
|
|
|
264
302
|
export function Toolbar<T extends string = string>({
|
|
@@ -268,6 +306,7 @@ export function Toolbar<T extends string = string>({
|
|
|
268
306
|
rightMenuItems = [],
|
|
269
307
|
onSelectMenuItem,
|
|
270
308
|
shouldBindKeyboardShortcuts = true,
|
|
309
|
+
dividerOverflow,
|
|
271
310
|
}: ToolbarProps<T>) {
|
|
272
311
|
// Register keyboard shortcuts for all menu items
|
|
273
312
|
const allMenuItems = React.useMemo(
|
|
@@ -290,20 +329,22 @@ export function Toolbar<T extends string = string>({
|
|
|
290
329
|
logo={logo}
|
|
291
330
|
left={
|
|
292
331
|
leftMenuItems.length > 0 && (
|
|
293
|
-
<div className="flex gap-2">
|
|
332
|
+
<div className="n-flex n-gap-2">
|
|
294
333
|
<ToolbarMenu
|
|
295
334
|
items={leftMenuItems}
|
|
296
335
|
onSelectMenuItem={onSelectMenuItem}
|
|
336
|
+
dividerOverflow={dividerOverflow}
|
|
297
337
|
/>
|
|
298
338
|
</div>
|
|
299
339
|
)
|
|
300
340
|
}
|
|
301
341
|
right={
|
|
302
342
|
rightMenuItems.length > 0 && (
|
|
303
|
-
<div className="flex gap-2">
|
|
343
|
+
<div className="n-flex n-gap-2">
|
|
304
344
|
<ToolbarMenu
|
|
305
345
|
items={rightMenuItems}
|
|
306
346
|
onSelectMenuItem={onSelectMenuItem}
|
|
347
|
+
dividerOverflow={dividerOverflow}
|
|
307
348
|
/>
|
|
308
349
|
</div>
|
|
309
350
|
)
|
|
@@ -12,9 +12,9 @@ export const ToolbarDrawer = memo(
|
|
|
12
12
|
ref: ForwardedRef<HTMLDivElement>
|
|
13
13
|
) {
|
|
14
14
|
return (
|
|
15
|
-
<div className="relative" ref={ref}>
|
|
15
|
+
<div className="n-relative" ref={ref}>
|
|
16
16
|
<div
|
|
17
|
-
className="absolute bottom-full left-1/2 -translate-x-1/2 rounded-t-lg border border-toolbar-drawer-border border-b-transparent bg-toolbar-drawer-background -z-10"
|
|
17
|
+
className="n-absolute n-bottom-full n-left-1/2 -n-translate-x-1/2 n-rounded-t-lg n-border n-border-toolbar-drawer-border n-border-b-transparent n-bg-toolbar-drawer-background -n-z-10"
|
|
18
18
|
style={{
|
|
19
19
|
marginBottom: `${sideOffset}px`,
|
|
20
20
|
boxShadow: "0px -2px 12px 0px var(--n-toolbar-drawer-shadow)",
|
|
@@ -35,7 +35,7 @@ export const Tooltip = React.memo(function Tooltip({
|
|
|
35
35
|
align="center"
|
|
36
36
|
sideOffset={sideOffset}
|
|
37
37
|
collisionPadding={8}
|
|
38
|
-
className={`${textStyles.small} text-text rounded-sm p-2 bg-popover-background shadow-tooltip z-menu`}
|
|
38
|
+
className={`${textStyles.small} n-text-text n-rounded-sm n-p-2 n-bg-popover-background n-shadow-tooltip n-z-menu`}
|
|
39
39
|
>
|
|
40
40
|
{content}
|
|
41
41
|
</TooltipPrimitive.Content>
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
forwardRefGeneric,
|
|
5
|
+
memoGeneric,
|
|
6
|
+
useStableCallback,
|
|
7
|
+
} from "@noya-app/react-utils";
|
|
4
8
|
import React, { ForwardedRef, ReactNode, useCallback, useContext } from "react";
|
|
5
9
|
import { IconButton } from "./IconButton";
|
|
6
10
|
import { IconName, renderIcon } from "./Icons";
|
|
7
11
|
import { ListView } from "./ListView";
|
|
8
12
|
import { Spacer } from "./Spacer";
|
|
13
|
+
import { ListViewContext } from "./listView/ListViewContexts";
|
|
9
14
|
|
|
10
15
|
/* ----------------------------------------------------------------------------
|
|
11
16
|
* Row
|
|
@@ -33,14 +38,16 @@ const TreeRow = forwardRefGeneric(function TreeRow<MenuItemType extends string>(
|
|
|
33
38
|
}: TreeViewRowProps<MenuItemType>,
|
|
34
39
|
forwardedRef: ForwardedRef<HTMLLIElement>
|
|
35
40
|
) {
|
|
36
|
-
const { expandable } = useContext(
|
|
41
|
+
const { expandable } = useContext(ListViewContext);
|
|
42
|
+
|
|
43
|
+
const stableOnClickChevron = useStableCallback(onClickChevron);
|
|
37
44
|
|
|
38
45
|
const handleClickChevron = useCallback(
|
|
39
46
|
(event: React.MouseEvent) => {
|
|
40
47
|
event.stopPropagation();
|
|
41
|
-
|
|
48
|
+
stableOnClickChevron?.({ altKey: event.altKey });
|
|
42
49
|
},
|
|
43
|
-
[
|
|
50
|
+
[stableOnClickChevron]
|
|
44
51
|
);
|
|
45
52
|
|
|
46
53
|
return (
|
|
@@ -27,8 +27,8 @@ const UserPointerContainer = memo(function UserPointerContainer({
|
|
|
27
27
|
...style,
|
|
28
28
|
}}
|
|
29
29
|
className={cx(
|
|
30
|
-
"pointer-events-none",
|
|
31
|
-
visible ? "opacity-100" : "opacity-0",
|
|
30
|
+
"n-pointer-events-none",
|
|
31
|
+
visible ? "n-opacity-100" : "n-opacity-0",
|
|
32
32
|
className
|
|
33
33
|
)}
|
|
34
34
|
>
|
|
@@ -51,7 +51,7 @@ const UserNameTag = memo(function UserNameTag({
|
|
|
51
51
|
return (
|
|
52
52
|
<span
|
|
53
53
|
className={cx(
|
|
54
|
-
"relative inline-block rounded-full text-xs font-medium leading-none text-white shadow-sm px-2 py-1.5 border border-background",
|
|
54
|
+
"n-relative n-inline-block n-rounded-full n-text-xs n-font-medium n-leading-none n-text-white n-shadow-sm n-px-2 n-py-1.5 n-border n-border-background",
|
|
55
55
|
className
|
|
56
56
|
)}
|
|
57
57
|
style={{
|
|
@@ -153,7 +153,7 @@ export const UserPointer = memo(function UserPointer({
|
|
|
153
153
|
style={style}
|
|
154
154
|
>
|
|
155
155
|
{name && (
|
|
156
|
-
<div className="relative">
|
|
156
|
+
<div className="n-relative">
|
|
157
157
|
<UserPointerIcon
|
|
158
158
|
size={POINTER_SIZE}
|
|
159
159
|
color={userBackgroundColor}
|
|
@@ -14,7 +14,7 @@ import { TextAreaRow } from "../TextArea";
|
|
|
14
14
|
|
|
15
15
|
export const AIAssistantLoadingIndicator = () => {
|
|
16
16
|
return (
|
|
17
|
-
<div className="flex gap-2">
|
|
17
|
+
<div className="n-flex n-gap-2">
|
|
18
18
|
<Avatar
|
|
19
19
|
name="Assistant"
|
|
20
20
|
size={INPUT_HEIGHT}
|
|
@@ -22,7 +22,7 @@ export const AIAssistantLoadingIndicator = () => {
|
|
|
22
22
|
>
|
|
23
23
|
<Logo style={{ width: 15 }} fill={cssVars.colors.primary} />
|
|
24
24
|
</Avatar>
|
|
25
|
-
<div className="animate-pulse">▋</div>
|
|
25
|
+
<div className="n-animate-pulse">▋</div>
|
|
26
26
|
</div>
|
|
27
27
|
);
|
|
28
28
|
};
|
|
@@ -45,7 +45,7 @@ export const AIAssistantInput = forwardRef<
|
|
|
45
45
|
value={value}
|
|
46
46
|
onChange={onChange}
|
|
47
47
|
ref={ref}
|
|
48
|
-
textAreaClassName="py-2 pl-3 !pr-9 w-full mt-3"
|
|
48
|
+
textAreaClassName="n-py-2 n-pl-3 !n-pr-9 n-w-full n-mt-3"
|
|
49
49
|
placeholder="Tell me what you'd like to do..."
|
|
50
50
|
onKeyDown={onKeyDown}
|
|
51
51
|
disabled={disabled}
|
|
@@ -54,7 +54,7 @@ export const AIAssistantInput = forwardRef<
|
|
|
54
54
|
iconName="ArrowUpIcon"
|
|
55
55
|
onClick={onSubmitClick}
|
|
56
56
|
disabled={!value.trim() || disabled}
|
|
57
|
-
className="h-8 w-8 z-20 rounded-full"
|
|
57
|
+
className="n-h-8 n-w-8 n-z-20 n-rounded-full"
|
|
58
58
|
size={20}
|
|
59
59
|
color={cssVars.colors.text}
|
|
60
60
|
style={{
|
|
@@ -90,14 +90,14 @@ export const AIAssistantLayout = forwardRef<
|
|
|
90
90
|
ref
|
|
91
91
|
) => {
|
|
92
92
|
return (
|
|
93
|
-
<div className={cx("flex flex-col flex-1", className)} style={style}>
|
|
94
|
-
<div className="flex-1 min-h-0 overflow-auto" ref={ref}>
|
|
95
|
-
<div className="flex flex-col gap-2 pb-4 pt-1">
|
|
93
|
+
<div className={cx("n-flex n-flex-col n-flex-1", className)} style={style}>
|
|
94
|
+
<div className="n-flex-1 n-min-h-0 n-overflow-auto" ref={ref}>
|
|
95
|
+
<div className="n-flex n-flex-col n-gap-2 n-pb-4 n-pt-1">
|
|
96
96
|
{renderMessages()}
|
|
97
97
|
{isLoading ? renderLoadingIndicator?.() : null}
|
|
98
98
|
</div>
|
|
99
99
|
</div>
|
|
100
|
-
<div className="border-t border-divider pt-1 px-1">{renderInput()}</div>
|
|
100
|
+
<div className="n-border-t n-border-divider n-pt-1 n-px-1">{renderInput()}</div>
|
|
101
101
|
</div>
|
|
102
102
|
);
|
|
103
103
|
}
|
|
@@ -5,7 +5,7 @@ import React, { ForwardedRef, forwardRef } from "react";
|
|
|
5
5
|
type ImageState = "loading" | "error" | "loaded";
|
|
6
6
|
|
|
7
7
|
const placeholderClassName =
|
|
8
|
-
"cursor-pointer flex items-center justify-center p-4 border border-dashed border-indigo-100 rounded-md bg-indigo-50";
|
|
8
|
+
"n-cursor-pointer n-flex n-items-center n-justify-center n-p-4 n-border n-border-dashed n-border-indigo-100 n-rounded-md n-bg-indigo-50";
|
|
9
9
|
|
|
10
10
|
export function decodeImageSrc(src?: string): string | undefined {
|
|
11
11
|
if (!src) return undefined;
|
|
@@ -44,7 +44,7 @@ const ImagePlaceholderComponent = forwardRef(function ImagePlaceholderComponent(
|
|
|
44
44
|
contentEditable={false}
|
|
45
45
|
className={cx(placeholderClassName, props.className)}
|
|
46
46
|
>
|
|
47
|
-
<ImageIcon className="w-[30px] h-[30px] text-indigo-900 pointer-events-none" />
|
|
47
|
+
<ImageIcon className="n-w-[30px] n-h-[30px] n-text-indigo-900 n-pointer-events-none" />
|
|
48
48
|
</span>
|
|
49
49
|
);
|
|
50
50
|
});
|
|
@@ -60,7 +60,7 @@ const ImageErrorComponent = forwardRef(function ImageErrorComponent(
|
|
|
60
60
|
contentEditable={false}
|
|
61
61
|
className={cx(placeholderClassName, props.className)}
|
|
62
62
|
>
|
|
63
|
-
<span className="text-cm-error font-mono text-sm">
|
|
63
|
+
<span className="n-text-cm-error n-font-mono n-text-sm">
|
|
64
64
|
Invalid image URL: {src ?? "No URL provided"}
|
|
65
65
|
</span>
|
|
66
66
|
</span>
|
|
@@ -86,10 +86,16 @@ const ImageDisplayComponent = forwardRef(function ImageDisplayComponent(
|
|
|
86
86
|
src={src}
|
|
87
87
|
alt={alt ?? ""}
|
|
88
88
|
title={title ?? undefined}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
// use styles over classname for rendering to static HTML
|
|
90
|
+
style={{
|
|
91
|
+
maxWidth: "100%",
|
|
92
|
+
maxHeight: "720px",
|
|
93
|
+
height: "auto",
|
|
94
|
+
objectFit: "contain",
|
|
95
|
+
margin: "32px auto",
|
|
96
|
+
...props.style,
|
|
97
|
+
}}
|
|
98
|
+
className={cx("n-cursor-pointer", props.className)}
|
|
93
99
|
/>
|
|
94
100
|
);
|
|
95
101
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { INPUT_HEIGHT } from "../../theme";
|
|
5
5
|
import { Avatar, AvatarProps, AvatarStack } from "../Avatar";
|
|
6
|
-
import Button from "../Button";
|
|
6
|
+
import { Button } from "../Button";
|
|
7
7
|
import { Small } from "../Text";
|
|
8
8
|
import { Tooltip } from "../Tooltip";
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ export const UserAvatar = ({ userId, name, image }: AvatarProps) => (
|
|
|
11
11
|
<Tooltip
|
|
12
12
|
key={userId}
|
|
13
13
|
content={
|
|
14
|
-
<div className="flex flex-col">
|
|
14
|
+
<div className="n-flex n-flex-col">
|
|
15
15
|
<Small>{name}</Small>
|
|
16
16
|
</div>
|
|
17
17
|
}
|
|
@@ -32,8 +32,8 @@ export const ConnectedUsersMenuLayout = ({
|
|
|
32
32
|
isAssistantOpen,
|
|
33
33
|
}: ConnectedUsersMenuLayoutProps) => {
|
|
34
34
|
return (
|
|
35
|
-
<div className="flex gap-1.5">
|
|
36
|
-
<AvatarStack size={INPUT_HEIGHT} className="mr-1">
|
|
35
|
+
<div className="n-flex n-gap-1.5">
|
|
36
|
+
<AvatarStack size={INPUT_HEIGHT} className="n-mr-1">
|
|
37
37
|
{renderUsers()}
|
|
38
38
|
</AvatarStack>
|
|
39
39
|
{launchAIAssistant && (
|