@noya-app/noya-designsystem 0.1.63 → 0.1.64
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 +13 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +169 -127
- package/dist/index.d.ts +169 -127
- package/dist/index.js +3131 -2642
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2941 -2459
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -22
- package/src/__tests__/validateDropIndicator.test.ts +26 -41
- package/src/__tests__/workspaceLayout.test.ts +281 -0
- package/src/components/ActionMenu.tsx +2 -0
- package/src/components/ActivityIndicator.tsx +5 -3
- package/src/components/AnimatePresence.tsx +6 -4
- package/src/components/Avatar.tsx +4 -2
- package/src/components/BaseToolbar.tsx +45 -34
- package/src/components/Breadcrumbs.tsx +2 -0
- package/src/components/Button.tsx +9 -3
- package/src/components/Chip.tsx +2 -0
- package/src/components/Collection.tsx +4 -1
- package/src/components/ColorSwatch.tsx +42 -22
- package/src/components/ColorSwatchControl.tsx +5 -3
- package/src/components/Combobox.tsx +2 -0
- package/src/components/CommandPalette.tsx +2 -0
- package/src/components/ContextMenu.tsx +3 -1
- package/src/components/Dialog.tsx +3 -1
- package/src/components/DimensionInput.tsx +2 -0
- package/src/components/Divider.tsx +10 -6
- package/src/components/DraggableMenuButton.tsx +2 -0
- package/src/components/Drawer.tsx +11 -3
- package/src/components/DropdownMenu.tsx +3 -1
- package/src/components/EditableText.tsx +2 -0
- package/src/components/FileUploadIndicator.tsx +108 -0
- package/src/components/FillPreviewBackground.tsx +2 -0
- package/src/components/FloatingWindow.tsx +2 -0
- package/src/components/GradientPicker.tsx +2 -0
- package/src/components/Grid.tsx +47 -38
- package/src/components/GridView.tsx +33 -11
- package/src/components/IconButton.tsx +2 -0
- package/src/components/Icons.tsx +1 -1
- package/src/components/InputField.tsx +2 -0
- package/src/components/Label.tsx +1 -1
- package/src/components/LabeledElementView.tsx +6 -2
- package/src/components/LabeledField.tsx +2 -0
- package/src/components/List.tsx +10 -2
- package/src/components/ListView.tsx +27 -14
- package/src/components/MediaThumbnail.tsx +31 -2
- package/src/components/Message.tsx +8 -9
- package/src/components/Popover.tsx +3 -1
- package/src/components/Progress.tsx +20 -7
- package/src/components/ScrollArea.tsx +3 -1
- package/src/components/SearchCompletionMenu.tsx +2 -0
- package/src/components/Section.tsx +2 -0
- package/src/components/SegmentedControl.tsx +42 -16
- package/src/components/SelectMenu.tsx +3 -1
- package/src/components/SelectionToolbar.tsx +3 -1
- package/src/components/Slider.tsx +3 -1
- package/src/components/Switch.tsx +3 -1
- package/src/components/Tabs.tsx +3 -1
- package/src/components/Text.tsx +6 -5
- package/src/components/TextArea.tsx +2 -0
- package/src/components/Toast.tsx +1 -1
- package/src/components/Toolbar.tsx +8 -2
- package/src/components/ToolbarDrawer.tsx +29 -0
- package/src/components/Tooltip.tsx +1 -1
- package/src/components/TreeView.tsx +2 -0
- package/src/components/UserPointer.tsx +2 -0
- package/src/components/ai-assistant/AIAssistantLayout.tsx +2 -0
- package/src/components/blocks/ImageBlockComponent.tsx +156 -0
- package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +2 -0
- package/src/components/file-explorer/FileExplorerLayout.tsx +2 -0
- package/src/components/internal/Checkmark.tsx +24 -0
- package/src/components/internal/Menu.tsx +2 -1
- package/src/components/internal/MenuViewport.tsx +4 -2
- package/src/components/internal/SelectItem.tsx +4 -23
- package/src/components/internal/TextInput.tsx +2 -0
- package/src/components/sorting/DragRegistration.tsx +8 -4
- package/src/components/sorting/SharedDragProvider.tsx +43 -18
- package/src/components/sorting/Sortable.tsx +19 -10
- package/src/components/sorting/createSharedDrag.tsx +7 -6
- package/src/components/sorting/sorting.ts +6 -9
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +107 -26
- package/src/components/workspace/PanelWorkspaceLayout.tsx +98 -65
- package/src/components/workspace/VerticalTabMenu.tsx +36 -0
- package/src/components/workspace/WorkspaceLayout.tsx +46 -42
- package/src/components/workspace/constants.ts +4 -0
- package/src/components/workspace/panelStorage.ts +216 -0
- package/src/components/workspace/types.ts +11 -4
- package/src/contexts/DesignSystemConfiguration.tsx +12 -5
- package/src/contexts/DialogContext.tsx +2 -0
- package/src/contexts/FloatingWindowContext.tsx +2 -0
- package/src/contexts/GlobalInputBlurContext.tsx +2 -0
- package/src/contexts/ImageDataContext.tsx +2 -0
- package/src/contexts/LinkComponentContext.tsx +17 -0
- package/src/contexts/OpenPortalsContext.tsx +2 -0
- package/src/contexts/PortalScopeContext.tsx +2 -0
- package/src/hooks/mergeEventHandlers.ts +1 -1
- package/src/hooks/useHover.ts +30 -17
- package/src/hooks/useIndent.ts +2 -0
- package/src/hooks/useLabel.ts +2 -0
- package/src/hooks/useObjectURL.ts +5 -3
- package/src/hooks/usePlatform.ts +5 -3
- package/src/hooks/useTheme.ts +3 -1
- package/src/index.css +19 -0
- package/src/index.tsx +5 -2
- package/src/utils/classNames.ts +4 -3
- package/src/utils/combobox.ts +2 -0
- package/src/utils/formatByteSize.ts +8 -0
- package/src/utils/withSeparatorElements.ts +1 -1
- package/src/hooks/usePreservePanelSize.tsx +0 -183
- package/src/mediaQuery.ts +0 -13
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { memoGeneric } from "@noya-app/react-utils";
|
|
2
|
-
import
|
|
4
|
+
import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui";
|
|
3
5
|
import React, {
|
|
4
6
|
createContext,
|
|
5
7
|
forwardRef,
|
|
@@ -15,7 +17,7 @@ import { SelectableMenuItem } from "./internal/Menu";
|
|
|
15
17
|
import { Tooltip } from "./Tooltip";
|
|
16
18
|
|
|
17
19
|
type SegmentedControlColorScheme = "primary" | "secondary";
|
|
18
|
-
type SegmentedControlVariant = "default" | "tabs";
|
|
20
|
+
type SegmentedControlVariant = "default" | "tabs" | "buttons";
|
|
19
21
|
|
|
20
22
|
type SegmentedControlContextValue = {
|
|
21
23
|
/** @default primary */
|
|
@@ -75,26 +77,49 @@ const SegmentedControlItem = forwardRef(function SegmentedControlItem<
|
|
|
75
77
|
className={cx(
|
|
76
78
|
"group",
|
|
77
79
|
"flex items-center justify-center",
|
|
78
|
-
"font-sans text-button relative flex-1 appearance-none
|
|
79
|
-
|
|
80
|
+
"font-sans text-button relative flex-1 appearance-none focus:outline-none transition-colors",
|
|
81
|
+
// text color
|
|
82
|
+
variant === "buttons"
|
|
83
|
+
? "text-button-text"
|
|
84
|
+
: "text-segmented-control-item",
|
|
85
|
+
// font weight
|
|
86
|
+
variant === "tabs"
|
|
87
|
+
? "font-semibold"
|
|
88
|
+
: variant === "buttons"
|
|
89
|
+
? "font-medium"
|
|
90
|
+
: "font-normal",
|
|
91
|
+
// focus ring
|
|
80
92
|
variant === "tabs"
|
|
81
93
|
? ""
|
|
82
|
-
:
|
|
83
|
-
? "focus:ring-2 focus:ring-
|
|
84
|
-
:
|
|
94
|
+
: variant === "buttons"
|
|
95
|
+
? "focus-visible:ring-2 focus-visible:ring-primary focus:shadow-[0_0_0_1px_var(--n-popover-background)_inset] transition-all"
|
|
96
|
+
: colorScheme === "secondary"
|
|
97
|
+
? "focus:ring-2 focus:ring-secondary focus:ring-offset-1"
|
|
98
|
+
: "focus:ring-2 focus:ring-primary focus:ring-offset-1",
|
|
99
|
+
// checked
|
|
85
100
|
variant === "tabs"
|
|
86
101
|
? "aria-checked:text-primary"
|
|
87
|
-
:
|
|
88
|
-
? "
|
|
89
|
-
: colorScheme === "
|
|
90
|
-
? "aria-checked:bg-
|
|
91
|
-
:
|
|
102
|
+
: variant === "buttons"
|
|
103
|
+
? "active:text-button-text-active active:bg-button-background-active aria-checked:text-button-text-active aria-checked:bg-button-background-active"
|
|
104
|
+
: colorScheme === "secondary"
|
|
105
|
+
? "aria-checked:bg-secondary aria-checked:text-white"
|
|
106
|
+
: colorScheme === "primary"
|
|
107
|
+
? "aria-checked:bg-primary aria-checked:text-white"
|
|
108
|
+
: "aria-checked:bg-segmented-control-item-active-background aria-checked:text-segmented-control-item-active-text",
|
|
92
109
|
"focus:z-interactable",
|
|
93
|
-
|
|
94
|
-
? "px-1 rounded aria-checked:shadow-segment"
|
|
95
|
-
: "px-1.5 border-y-2 border-y-transparent aria-checked:border-b-primary",
|
|
110
|
+
// checked default (all colorSchemes)
|
|
96
111
|
variant === "default" &&
|
|
97
|
-
"
|
|
112
|
+
"aria-checked:border-r-transparent [&:has(+[aria-checked=true])]:border-r-transparent aria-checked:shadow-segment",
|
|
113
|
+
// hover
|
|
114
|
+
variant === "buttons" && "hover:bg-button-background-hover",
|
|
115
|
+
// spacing and borders
|
|
116
|
+
variant === "default"
|
|
117
|
+
? "px-1 rounded border-r border-divider last:border-r-0"
|
|
118
|
+
: variant === "buttons"
|
|
119
|
+
? "px-1 rounded-sm max-w-fit"
|
|
120
|
+
: "px-1.5 border-y-2 border-y-transparent aria-checked:border-b-primary",
|
|
121
|
+
// icon only buttons
|
|
122
|
+
variant === "buttons" && title === "" && icon && "min-w-input-height",
|
|
98
123
|
className
|
|
99
124
|
)}
|
|
100
125
|
{...props}
|
|
@@ -155,6 +180,7 @@ export const SegmentedControl = memoGeneric(function SegmentedControl<
|
|
|
155
180
|
variant === "default" &&
|
|
156
181
|
"grid min-h-input-height bg-input-background rounded py-0.5 px-0.5",
|
|
157
182
|
variant === "tabs" && "flex gap-1.5 min-h-[33px]",
|
|
183
|
+
variant === "buttons" && "flex gap-1.5 min-h-input-height",
|
|
158
184
|
className
|
|
159
185
|
)}
|
|
160
186
|
style={{
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
ChevronDownIcon,
|
|
3
5
|
ChevronUpIcon,
|
|
4
6
|
DropdownChevronIcon,
|
|
5
7
|
} from "@noya-app/noya-icons";
|
|
6
8
|
import { memoGeneric } from "@noya-app/react-utils";
|
|
7
|
-
import
|
|
9
|
+
import { Select } from "radix-ui";
|
|
8
10
|
import { type SelectProps } from "@radix-ui/react-select";
|
|
9
11
|
import React, {
|
|
10
12
|
CSSProperties,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
cssVarNames,
|
|
3
5
|
cx,
|
|
@@ -76,7 +78,7 @@ export const SelectionToolbarContainer = memo(
|
|
|
76
78
|
collisionPadding={10}
|
|
77
79
|
contentEditable={false}
|
|
78
80
|
style={{
|
|
79
|
-
zIndex:
|
|
81
|
+
zIndex: 10,
|
|
80
82
|
opacity: size ? 1 : 0,
|
|
81
83
|
transition: `opacity ${transitionDuration}s ease-in-out`,
|
|
82
84
|
[cssVarNames.colors.inputBackground]: "transparent",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Slider as RadixSlider } from "radix-ui";
|
|
2
4
|
import React, { FocusEventHandler, memo, useCallback, useMemo } from "react";
|
|
3
5
|
import { useLabel } from "../hooks/useLabel";
|
|
4
6
|
import { cx } from "../utils/classNames";
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -11,6 +11,7 @@ export type TabsProps<T extends string = string> = {
|
|
|
11
11
|
onValueChange?: (value: T) => void;
|
|
12
12
|
items: MenuItem<T>[];
|
|
13
13
|
renderContent: ({ value }: { value: T }) => React.ReactNode;
|
|
14
|
+
variant?: "default" | "tabs" | "buttons";
|
|
14
15
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
|
15
16
|
|
|
16
17
|
export function Tabs<T extends string = string>({
|
|
@@ -18,6 +19,7 @@ export function Tabs<T extends string = string>({
|
|
|
18
19
|
onValueChange,
|
|
19
20
|
items,
|
|
20
21
|
renderContent,
|
|
22
|
+
variant = "tabs",
|
|
21
23
|
...props
|
|
22
24
|
}: TabsProps<T>) {
|
|
23
25
|
const selectableItems = items.filter(isSelectableMenuItem);
|
|
@@ -35,7 +37,7 @@ export function Tabs<T extends string = string>({
|
|
|
35
37
|
className="flex-1"
|
|
36
38
|
value={activeTab}
|
|
37
39
|
onValueChange={setActiveTab}
|
|
38
|
-
variant=
|
|
40
|
+
variant={variant}
|
|
39
41
|
items={selectableItems}
|
|
40
42
|
/>
|
|
41
43
|
</div>
|
package/src/components/Text.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { ForwardedRef, forwardRef, ReactNode } from "react";
|
|
2
4
|
import { ThemeColor } from "../theme";
|
|
3
5
|
import { camelToKebabCase, KebabToCamelCase } from "../theme/themeUtils";
|
|
4
6
|
import { cx } from "../utils/classNames";
|
|
@@ -17,7 +19,7 @@ type Variant =
|
|
|
17
19
|
| "code"
|
|
18
20
|
| "label";
|
|
19
21
|
|
|
20
|
-
const elements: Record<Variant,
|
|
22
|
+
const elements: Record<Variant, React.HTMLElementType> = {
|
|
21
23
|
title: "h1",
|
|
22
24
|
subtitle: "h1",
|
|
23
25
|
heading1: "h1",
|
|
@@ -48,7 +50,7 @@ export const textStyles: Record<Variant, string> = {
|
|
|
48
50
|
} as const;
|
|
49
51
|
|
|
50
52
|
export type TextProps = {
|
|
51
|
-
as?:
|
|
53
|
+
as?: React.HTMLElementType;
|
|
52
54
|
href?: string;
|
|
53
55
|
className?: string;
|
|
54
56
|
style?: React.CSSProperties;
|
|
@@ -78,11 +80,10 @@ export const Text = forwardRef(function Text(
|
|
|
78
80
|
}: TextProps,
|
|
79
81
|
forwardedRef: ForwardedRef<HTMLElement>
|
|
80
82
|
) {
|
|
81
|
-
const Component = as ?? elements[variant] ?? "span";
|
|
83
|
+
const Component = (as ?? elements[variant] ?? "span") as "span";
|
|
82
84
|
|
|
83
85
|
return (
|
|
84
86
|
<Component
|
|
85
|
-
// @ts-expect-error expected to be many semantic html elements
|
|
86
87
|
ref={forwardedRef}
|
|
87
88
|
className={cx(
|
|
88
89
|
`${textStyles[variant]} text-${camelToKebabCase(String(color)) ?? "text"} `,
|
package/src/components/Toast.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
2
4
|
import React, { ComponentProps, ReactNode } from "react";
|
|
3
5
|
|
|
@@ -17,6 +19,7 @@ import {
|
|
|
17
19
|
} from "./internal/Menu";
|
|
18
20
|
import { Popover } from "./Popover";
|
|
19
21
|
import { Spacer } from "./Spacer";
|
|
22
|
+
import { ToolbarDrawer } from "./ToolbarDrawer";
|
|
20
23
|
import { Tooltip } from "./Tooltip";
|
|
21
24
|
|
|
22
25
|
const SIDE_OFFSET = 6;
|
|
@@ -144,11 +147,12 @@ export const ToolbarMenuButton = memoGeneric(function ToolbarMenuButton<
|
|
|
144
147
|
activeValue?: T;
|
|
145
148
|
tooltipSide?: ComponentProps<typeof Tooltip>["side"];
|
|
146
149
|
}) {
|
|
150
|
+
const isActive = item.checked || activeValue === item.value;
|
|
147
151
|
const content = (
|
|
148
152
|
<Button
|
|
149
153
|
as={as}
|
|
150
154
|
disabled={item.disabled}
|
|
151
|
-
active={
|
|
155
|
+
active={isActive}
|
|
152
156
|
icon={item.icon}
|
|
153
157
|
{...(as === "a" && { href: item.value })}
|
|
154
158
|
onClick={() => {
|
|
@@ -161,7 +165,9 @@ export const ToolbarMenuButton = memoGeneric(function ToolbarMenuButton<
|
|
|
161
165
|
</Button>
|
|
162
166
|
);
|
|
163
167
|
|
|
164
|
-
return item.
|
|
168
|
+
return item.drawer && isActive ? (
|
|
169
|
+
<ToolbarDrawer trigger={content}>{item.drawer}</ToolbarDrawer>
|
|
170
|
+
) : item.tooltip ? (
|
|
165
171
|
<Tooltip sideOffset={SIDE_OFFSET} content={item.tooltip} side={tooltipSide}>
|
|
166
172
|
{content}
|
|
167
173
|
</Tooltip>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { ForwardedRef, forwardRef, memo, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
type ToolbarDrawerProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
trigger: ReactNode;
|
|
6
|
+
sideOffset?: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const ToolbarDrawer = memo(
|
|
10
|
+
forwardRef(function ToolbarDrawer(
|
|
11
|
+
{ children, trigger, sideOffset = 8 }: ToolbarDrawerProps,
|
|
12
|
+
ref: ForwardedRef<HTMLDivElement>
|
|
13
|
+
) {
|
|
14
|
+
return (
|
|
15
|
+
<div className="relative" ref={ref}>
|
|
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"
|
|
18
|
+
style={{
|
|
19
|
+
marginBottom: `${sideOffset}px`,
|
|
20
|
+
boxShadow: "0px -2px 12px 0px var(--n-toolbar-drawer-shadow)",
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</div>
|
|
25
|
+
{trigger}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
})
|
|
29
|
+
);
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { ActivityIndicator, cx } from "@noya-app/noya-designsystem";
|
|
2
|
+
import { ImageIcon } from "@noya-app/noya-icons";
|
|
3
|
+
import React, { ForwardedRef, forwardRef } from "react";
|
|
4
|
+
|
|
5
|
+
type ImageState = "loading" | "error" | "loaded";
|
|
6
|
+
|
|
7
|
+
const placeholderClassName =
|
|
8
|
+
"cursor-pointer flex items-center justify-center p-4 border border-dashed border-indigo-100 rounded-md bg-indigo-50";
|
|
9
|
+
|
|
10
|
+
export function decodeImageSrc(src?: string): string | undefined {
|
|
11
|
+
if (!src) return undefined;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
return decodeURIComponent(src);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ImageLoadingComponent = forwardRef(function ImageLoadingComponent(
|
|
21
|
+
props: React.HTMLAttributes<HTMLSpanElement>,
|
|
22
|
+
forwardedRef: ForwardedRef<HTMLSpanElement>
|
|
23
|
+
) {
|
|
24
|
+
return (
|
|
25
|
+
<span
|
|
26
|
+
{...props}
|
|
27
|
+
ref={forwardedRef}
|
|
28
|
+
contentEditable={false}
|
|
29
|
+
className={cx(placeholderClassName, props.className)}
|
|
30
|
+
>
|
|
31
|
+
<ActivityIndicator />
|
|
32
|
+
</span>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const ImagePlaceholderComponent = forwardRef(function ImagePlaceholderComponent(
|
|
37
|
+
props: React.HTMLAttributes<HTMLSpanElement>,
|
|
38
|
+
forwardedRef: ForwardedRef<HTMLSpanElement>
|
|
39
|
+
) {
|
|
40
|
+
return (
|
|
41
|
+
<span
|
|
42
|
+
{...props}
|
|
43
|
+
ref={forwardedRef}
|
|
44
|
+
contentEditable={false}
|
|
45
|
+
className={cx(placeholderClassName, props.className)}
|
|
46
|
+
>
|
|
47
|
+
<ImageIcon className="w-[30px] h-[30px] text-indigo-900 pointer-events-none" />
|
|
48
|
+
</span>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const ImageErrorComponent = forwardRef(function ImageErrorComponent(
|
|
53
|
+
{ src, ...props }: React.HTMLAttributes<HTMLSpanElement> & { src?: string },
|
|
54
|
+
forwardedRef: ForwardedRef<HTMLSpanElement>
|
|
55
|
+
) {
|
|
56
|
+
return (
|
|
57
|
+
<span
|
|
58
|
+
{...props}
|
|
59
|
+
ref={forwardedRef}
|
|
60
|
+
contentEditable={false}
|
|
61
|
+
className={cx(placeholderClassName, props.className)}
|
|
62
|
+
>
|
|
63
|
+
<span className="text-cm-error font-mono text-sm">
|
|
64
|
+
Invalid image URL: {src ?? "No URL provided"}
|
|
65
|
+
</span>
|
|
66
|
+
</span>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const ImageDisplayComponent = forwardRef(function ImageDisplayComponent(
|
|
71
|
+
{
|
|
72
|
+
src,
|
|
73
|
+
alt,
|
|
74
|
+
title,
|
|
75
|
+
...props
|
|
76
|
+
}: React.DetailedHTMLProps<
|
|
77
|
+
React.ImgHTMLAttributes<HTMLImageElement>,
|
|
78
|
+
HTMLImageElement
|
|
79
|
+
>,
|
|
80
|
+
forwardedRef: ForwardedRef<HTMLImageElement>
|
|
81
|
+
) {
|
|
82
|
+
return (
|
|
83
|
+
<img
|
|
84
|
+
{...props}
|
|
85
|
+
ref={forwardedRef}
|
|
86
|
+
src={src}
|
|
87
|
+
alt={alt ?? ""}
|
|
88
|
+
title={title ?? undefined}
|
|
89
|
+
className={cx(
|
|
90
|
+
"cursor-pointer max-w-full max-h-[720px] object-contain mx-auto my-8",
|
|
91
|
+
props.className
|
|
92
|
+
)}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const ImageBlockComponent_ = forwardRef(function ImageBlockComponent(
|
|
98
|
+
{
|
|
99
|
+
src,
|
|
100
|
+
alt,
|
|
101
|
+
title,
|
|
102
|
+
imageState,
|
|
103
|
+
...props
|
|
104
|
+
}: React.DetailedHTMLProps<
|
|
105
|
+
React.ImgHTMLAttributes<HTMLImageElement>,
|
|
106
|
+
HTMLImageElement
|
|
107
|
+
> & { imageState?: ImageState },
|
|
108
|
+
forwardedRef: ForwardedRef<HTMLImageElement>
|
|
109
|
+
) {
|
|
110
|
+
if (imageState === "loading") {
|
|
111
|
+
return (
|
|
112
|
+
<ImageLoadingComponent
|
|
113
|
+
{...props}
|
|
114
|
+
ref={forwardedRef as ForwardedRef<HTMLSpanElement>}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!src) {
|
|
120
|
+
return (
|
|
121
|
+
<ImagePlaceholderComponent
|
|
122
|
+
{...props}
|
|
123
|
+
ref={forwardedRef as ForwardedRef<HTMLSpanElement>}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const decodedSrc = decodeImageSrc(src.toString());
|
|
129
|
+
|
|
130
|
+
if (!decodedSrc || imageState === "error") {
|
|
131
|
+
return (
|
|
132
|
+
<ImageErrorComponent
|
|
133
|
+
{...props}
|
|
134
|
+
src={src.toString()}
|
|
135
|
+
ref={forwardedRef as ForwardedRef<HTMLSpanElement>}
|
|
136
|
+
/>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<ImageDisplayComponent
|
|
142
|
+
{...props}
|
|
143
|
+
ref={forwardedRef}
|
|
144
|
+
src={src}
|
|
145
|
+
alt={alt}
|
|
146
|
+
title={title}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export const ImageBlockComponent = Object.assign(ImageBlockComponent_, {
|
|
152
|
+
Loading: ImageLoadingComponent,
|
|
153
|
+
Placeholder: ImagePlaceholderComponent,
|
|
154
|
+
Error: ImageErrorComponent,
|
|
155
|
+
Display: ImageDisplayComponent,
|
|
156
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export function Checkmark(props: React.SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg
|
|
6
|
+
viewBox="0 0 15 15"
|
|
7
|
+
fill="none"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
aria-hidden="true"
|
|
10
|
+
width={15}
|
|
11
|
+
height={15}
|
|
12
|
+
{...props}
|
|
13
|
+
>
|
|
14
|
+
<path
|
|
15
|
+
className="scale-90 origin-center"
|
|
16
|
+
d="M3 8L6 11L12 5"
|
|
17
|
+
strokeWidth="1.1"
|
|
18
|
+
strokeLinecap="round"
|
|
19
|
+
strokeLinejoin="round"
|
|
20
|
+
stroke="currentColor"
|
|
21
|
+
/>
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -68,7 +68,7 @@ export const separator: SeparatorItem = {
|
|
|
68
68
|
|
|
69
69
|
type FalsyReactNode = false | "" | null | undefined;
|
|
70
70
|
|
|
71
|
-
export type MenuItemIcon = IconName | React.ReactElement | FalsyReactNode;
|
|
71
|
+
export type MenuItemIcon = IconName | React.ReactElement<any> | FalsyReactNode;
|
|
72
72
|
|
|
73
73
|
type BaseMenuItem = {
|
|
74
74
|
checked?: boolean;
|
|
@@ -93,6 +93,7 @@ export type SelectableMenuItem<T extends string> = BaseMenuItem & {
|
|
|
93
93
|
value: T;
|
|
94
94
|
testSelected?: boolean;
|
|
95
95
|
tooltip?: ReactNode;
|
|
96
|
+
drawer?: ReactNode;
|
|
96
97
|
};
|
|
97
98
|
|
|
98
99
|
export type SubMenuItem<T extends string> = BaseMenuItem & {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { ChevronRightIcon } from "@noya-app/noya-icons";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
+
import { ContextMenu as RadixContextMenu } from "radix-ui";
|
|
5
|
+
import { DropdownMenu as RadixDropdownMenu } from "radix-ui";
|
|
4
6
|
import React from "react";
|
|
5
7
|
import {
|
|
6
8
|
portalScopeProps,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { renderIcon } from "../Icons";
|
|
2
4
|
|
|
3
|
-
import
|
|
5
|
+
import { Select } from "radix-ui";
|
|
4
6
|
import React, { useCallback } from "react";
|
|
5
7
|
import { cx } from "../../utils/classNames";
|
|
6
8
|
import { Spacer } from "../Spacer";
|
|
9
|
+
import { Checkmark } from "./Checkmark";
|
|
7
10
|
import {
|
|
8
11
|
CHECKBOX_INDENT_WIDTH,
|
|
9
12
|
CHECKBOX_RIGHT_INSET,
|
|
@@ -133,25 +136,3 @@ export const SelectItem = React.forwardRef(
|
|
|
133
136
|
);
|
|
134
137
|
}
|
|
135
138
|
);
|
|
136
|
-
|
|
137
|
-
function Checkmark() {
|
|
138
|
-
return (
|
|
139
|
-
<svg
|
|
140
|
-
viewBox="0 0 15 15"
|
|
141
|
-
fill="none"
|
|
142
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
143
|
-
aria-hidden="true"
|
|
144
|
-
width={15}
|
|
145
|
-
height={15}
|
|
146
|
-
>
|
|
147
|
-
<path
|
|
148
|
-
className="scale-90 origin-center"
|
|
149
|
-
d="M3 8L6 11L12 5"
|
|
150
|
-
strokeWidth="1.1"
|
|
151
|
-
strokeLinecap="round"
|
|
152
|
-
strokeLinejoin="round"
|
|
153
|
-
stroke="currentColor"
|
|
154
|
-
/>
|
|
155
|
-
</svg>
|
|
156
|
-
);
|
|
157
|
-
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
AcceptsDrop,
|
|
3
5
|
DragState,
|
|
@@ -5,7 +7,7 @@ import {
|
|
|
5
7
|
RelativeDropPosition,
|
|
6
8
|
} from "./sorting";
|
|
7
9
|
|
|
8
|
-
import {
|
|
10
|
+
import { ClientRect, UniqueIdentifier } from "@dnd-kit/core";
|
|
9
11
|
import { AcceptsFromList } from "./sorting";
|
|
10
12
|
|
|
11
13
|
import { Point } from "@noya-app/noya-geometry";
|
|
@@ -13,8 +15,9 @@ import React from "react";
|
|
|
13
15
|
|
|
14
16
|
export type GetDropIndicatorParameters = {
|
|
15
17
|
absolutePosition: Point;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
activeIndex: number;
|
|
19
|
+
overIndex: number;
|
|
20
|
+
overRect: ClientRect;
|
|
18
21
|
sourceListId: string;
|
|
19
22
|
targetListId: string;
|
|
20
23
|
};
|
|
@@ -27,7 +30,8 @@ export interface RegisteredList {
|
|
|
27
30
|
acceptsFromList: AcceptsFromList;
|
|
28
31
|
acceptsDrop: AcceptsDrop;
|
|
29
32
|
getDropIndicator: (
|
|
30
|
-
parameters: GetDropIndicatorParameters
|
|
33
|
+
parameters: GetDropIndicatorParameters,
|
|
34
|
+
acceptsDrop: AcceptsDrop
|
|
31
35
|
) => RelativeDropPosition | undefined;
|
|
32
36
|
}
|
|
33
37
|
|