@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
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.65",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -22,12 +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.28",
|
|
26
|
+
"@noya-app/noya-utils": "0.1.7",
|
|
27
|
+
"@noya-app/noya-geometry": "0.1.14",
|
|
28
|
+
"@noya-app/noya-icons": "0.1.13",
|
|
29
29
|
"@noya-app/noya-keymap": "0.1.4",
|
|
30
|
-
"@noya-app/noya-tailwind-config": "0.1.
|
|
30
|
+
"@noya-app/noya-tailwind-config": "0.1.7",
|
|
31
31
|
"radix-ui": "1.4.2",
|
|
32
32
|
"@radix-ui/react-compose-refs": "^1.0.0",
|
|
33
33
|
"@radix-ui/primitive": "^1.0.1",
|
|
@@ -9,6 +9,7 @@ interface Props {
|
|
|
9
9
|
color?: string;
|
|
10
10
|
trackColor?: string;
|
|
11
11
|
className?: string;
|
|
12
|
+
style?: React.CSSProperties;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
@@ -17,8 +18,12 @@ export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
|
17
18
|
color = "black",
|
|
18
19
|
trackColor = "rgba(0, 0, 0, 0.1)",
|
|
19
20
|
className,
|
|
21
|
+
style,
|
|
20
22
|
}: Props) {
|
|
21
|
-
const
|
|
23
|
+
const containerStyle = React.useMemo(
|
|
24
|
+
() => ({ opacity, ...style }),
|
|
25
|
+
[opacity, style]
|
|
26
|
+
);
|
|
22
27
|
const dynamicStyles = React.useMemo(
|
|
23
28
|
() => ({
|
|
24
29
|
border: `2px solid ${trackColor}`,
|
|
@@ -30,10 +35,10 @@ export const ActivityIndicator = React.memo(function ActivityIndicator({
|
|
|
30
35
|
);
|
|
31
36
|
return (
|
|
32
37
|
<span
|
|
33
|
-
className={cx("flex justify-center items-center", className)}
|
|
34
|
-
style={
|
|
38
|
+
className={cx("n-flex n-justify-center n-items-center", className)}
|
|
39
|
+
style={containerStyle}
|
|
35
40
|
>
|
|
36
|
-
<span style={dynamicStyles} className="animate-spin rounded-[50%]" />
|
|
41
|
+
<span style={dynamicStyles} className="n-animate-spin n-rounded-[50%]" />
|
|
37
42
|
</span>
|
|
38
43
|
);
|
|
39
44
|
});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cx } from "../utils/classNames";
|
|
3
|
+
import { Avatar, AvatarStack } from "./Avatar";
|
|
4
|
+
import { Button } from "./Button";
|
|
5
|
+
import { Divider } from "./Divider";
|
|
6
|
+
import { DropdownMenu } from "./DropdownMenu";
|
|
7
|
+
import { IconProp, renderIcon } from "./Icons";
|
|
8
|
+
import { ExtraSmall, Small } from "./Text";
|
|
9
|
+
import { MenuItem } from "./internal/Menu";
|
|
10
|
+
|
|
11
|
+
export type ActivityIconSemanticColor = "add" | "remove" | "update";
|
|
12
|
+
|
|
13
|
+
const IconContainer = ({
|
|
14
|
+
children,
|
|
15
|
+
semanticColor,
|
|
16
|
+
}: {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
semanticColor?: ActivityIconSemanticColor;
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className={cx(
|
|
23
|
+
"n-w-[23px] n-h-[23px] n-rounded-full n-flex n-items-center n-justify-center n-flex-none",
|
|
24
|
+
semanticColor === "add" && "n-bg-secondary-pastel n-text-secondary",
|
|
25
|
+
semanticColor === "remove" &&
|
|
26
|
+
"n-bg-banner-error-background n-text-banner-error-text",
|
|
27
|
+
semanticColor === "update" && "n-bg-[#d1ecfe] n-text-[#1984cc]",
|
|
28
|
+
semanticColor === undefined && "n-bg-primary-pastel n-text-primary"
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const ActivityLine = () => {
|
|
37
|
+
return (
|
|
38
|
+
<div className="n-w-[3px] n-flex-1 n-relative">
|
|
39
|
+
<div className="n-rounded-full n-bg-primary-150 n-absolute n-w-full n-top-1 -n-bottom-3" />
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const ActivityLeft = ({ children }: { children: React.ReactNode }) => {
|
|
45
|
+
return (
|
|
46
|
+
<div className="n-flex n-flex-none n-relative n-isolate n-flex-col n-items-center">
|
|
47
|
+
{children}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const ActivityRight = ({
|
|
53
|
+
children,
|
|
54
|
+
className,
|
|
55
|
+
}: {
|
|
56
|
+
children: React.ReactNode;
|
|
57
|
+
className?: string;
|
|
58
|
+
}) => {
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
className={cx(
|
|
62
|
+
"n-flex-1 n-rounded n-flex n-p-2 n-gap-2 n-bg-canvas-background n-border n-border-divider-subtle",
|
|
63
|
+
className
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const ActivityCard = ({ children }: { children: React.ReactNode }) => {
|
|
72
|
+
return <div className="n-flex n-gap-2">{children}</div>;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const ActivityEventIndicator = () => {
|
|
76
|
+
return (
|
|
77
|
+
<div className="n-w-1 n-bg-primary-300 n-rounded-full n-mx-0.5 n-flex-none" />
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type ActivityUser = {
|
|
82
|
+
userId?: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
image?: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type ActivityLogItem<M extends string = string> = {
|
|
88
|
+
title: React.ReactNode;
|
|
89
|
+
description: React.ReactNode;
|
|
90
|
+
time?: React.ReactNode;
|
|
91
|
+
icon: IconProp;
|
|
92
|
+
iconSemanticColor?: ActivityIconSemanticColor;
|
|
93
|
+
menuItems?: MenuItem<M>[];
|
|
94
|
+
onSelectMenuItem?: (value: M) => void;
|
|
95
|
+
} & ({ type: "change"; users?: ActivityUser[] } | { type: "event" });
|
|
96
|
+
|
|
97
|
+
type ActivityLogProps<M extends string> = {
|
|
98
|
+
style?: React.CSSProperties;
|
|
99
|
+
className?: string;
|
|
100
|
+
items?: ActivityLogItem<M>[];
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export function ActivityLog<M extends string = string>({
|
|
104
|
+
style,
|
|
105
|
+
className,
|
|
106
|
+
items,
|
|
107
|
+
}: ActivityLogProps<M>) {
|
|
108
|
+
return (
|
|
109
|
+
<div
|
|
110
|
+
className={cx(
|
|
111
|
+
"n-flex n-flex-col n-relative n-gap-4 n-isolate",
|
|
112
|
+
className
|
|
113
|
+
)}
|
|
114
|
+
style={style}
|
|
115
|
+
>
|
|
116
|
+
{items?.map((item, index, list) => (
|
|
117
|
+
<ActivityCard key={index}>
|
|
118
|
+
<ActivityLeft>
|
|
119
|
+
<IconContainer semanticColor={item.iconSemanticColor}>
|
|
120
|
+
{renderIcon(item.icon)}
|
|
121
|
+
</IconContainer>
|
|
122
|
+
{index !== list.length - 1 && <ActivityLine />}
|
|
123
|
+
</ActivityLeft>
|
|
124
|
+
<ActivityRight>
|
|
125
|
+
{item.type === "event" && (
|
|
126
|
+
<>
|
|
127
|
+
<ActivityEventIndicator />
|
|
128
|
+
<div className="n-flex n-flex-col n-justify-center n-flex-1 n-gap-0.5">
|
|
129
|
+
<Small className="n-leading-snug">{item.title}</Small>
|
|
130
|
+
{item.description && (
|
|
131
|
+
<ExtraSmall
|
|
132
|
+
className="n-leading-snug n-break-all"
|
|
133
|
+
color="textSubtle"
|
|
134
|
+
>
|
|
135
|
+
{item.description}
|
|
136
|
+
</ExtraSmall>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
{item.menuItems && item.onSelectMenuItem && (
|
|
140
|
+
<DropdownMenu
|
|
141
|
+
items={item.menuItems}
|
|
142
|
+
onSelect={item.onSelectMenuItem}
|
|
143
|
+
>
|
|
144
|
+
{({ open }) => (
|
|
145
|
+
<Button
|
|
146
|
+
className="n-self-start"
|
|
147
|
+
icon="DotsVerticalIcon"
|
|
148
|
+
variant="ghost"
|
|
149
|
+
active={open}
|
|
150
|
+
/>
|
|
151
|
+
)}
|
|
152
|
+
</DropdownMenu>
|
|
153
|
+
)}
|
|
154
|
+
</>
|
|
155
|
+
)}
|
|
156
|
+
{item.type === "change" && (
|
|
157
|
+
<div className="n-flex n-flex-col n-flex-1">
|
|
158
|
+
<div className="n-flex n-items-start n-flex-1 n-gap-1.5">
|
|
159
|
+
{item.users && (
|
|
160
|
+
<AvatarStack
|
|
161
|
+
size={24}
|
|
162
|
+
overlapAmount={12}
|
|
163
|
+
className="n-flex-none n-self-start"
|
|
164
|
+
>
|
|
165
|
+
{item.users.map((user) => (
|
|
166
|
+
<Avatar
|
|
167
|
+
key={user.userId}
|
|
168
|
+
variant="borderless"
|
|
169
|
+
image={user.image}
|
|
170
|
+
name={user.name}
|
|
171
|
+
userId={user.userId}
|
|
172
|
+
/>
|
|
173
|
+
))}
|
|
174
|
+
</AvatarStack>
|
|
175
|
+
)}
|
|
176
|
+
<Small className="n-py-[3px] n-flex-1">{item.title}</Small>
|
|
177
|
+
<ExtraSmall
|
|
178
|
+
color="text"
|
|
179
|
+
className="n-flex n-items-center n-justify-center n-opacity-50 n-pt-[5px] n-whitespace-pre"
|
|
180
|
+
>
|
|
181
|
+
{item.time}
|
|
182
|
+
</ExtraSmall>
|
|
183
|
+
</div>
|
|
184
|
+
{item.description && (
|
|
185
|
+
<>
|
|
186
|
+
<Divider overflow={8} className="n-my-1.5" />
|
|
187
|
+
<Small>{item.description}</Small>
|
|
188
|
+
</>
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
</ActivityRight>
|
|
193
|
+
</ActivityCard>
|
|
194
|
+
))}
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
@@ -11,7 +11,13 @@ import React, {
|
|
|
11
11
|
useState,
|
|
12
12
|
} from "react";
|
|
13
13
|
|
|
14
|
-
type
|
|
14
|
+
export type AnimatePresenceChildState =
|
|
15
|
+
| "entering"
|
|
16
|
+
| "entered"
|
|
17
|
+
| "exiting"
|
|
18
|
+
| "exited";
|
|
19
|
+
|
|
20
|
+
export type AnimatePresenceProps = {
|
|
15
21
|
children: React.ReactNode;
|
|
16
22
|
/**
|
|
17
23
|
* Duration of enter/exit animations in milliseconds
|
|
@@ -35,17 +41,16 @@ type AnimatePresenceProps = {
|
|
|
35
41
|
*/
|
|
36
42
|
mode?: "wait" | "crossfade";
|
|
37
43
|
className?: string;
|
|
44
|
+
onChildStateChange?: (key: string, state: AnimatePresenceChildState) => void;
|
|
38
45
|
};
|
|
39
46
|
|
|
40
|
-
const defaultDuration = 150;
|
|
41
|
-
|
|
42
|
-
type AnimationState = "entering" | "entered" | "exiting" | "exited";
|
|
43
|
-
|
|
44
47
|
type PresenceChildProps = {
|
|
45
48
|
isPresent: boolean;
|
|
46
49
|
onExitComplete: () => void;
|
|
47
50
|
waitingToEnter?: boolean;
|
|
48
51
|
className?: string;
|
|
52
|
+
childKey: string;
|
|
53
|
+
onStateChange?: (key: string, state: AnimatePresenceChildState) => void;
|
|
49
54
|
} & Pick<
|
|
50
55
|
AnimatePresenceProps,
|
|
51
56
|
"animationStyles" | "children" | "duration" | "skipInitialAnimation"
|
|
@@ -56,15 +61,15 @@ const defaultAnimationStyles: Required<
|
|
|
56
61
|
> = {
|
|
57
62
|
entering: {
|
|
58
63
|
opacity: 0,
|
|
59
|
-
transition: `opacity
|
|
64
|
+
transition: `opacity 200ms ease-in`,
|
|
60
65
|
},
|
|
61
66
|
entered: {
|
|
62
67
|
opacity: 1,
|
|
63
|
-
transition: `opacity
|
|
68
|
+
transition: `opacity 200ms ease-in`,
|
|
64
69
|
},
|
|
65
70
|
exiting: {
|
|
66
71
|
opacity: 0,
|
|
67
|
-
transition: `opacity
|
|
72
|
+
transition: `opacity 200ms ease-out`,
|
|
68
73
|
},
|
|
69
74
|
};
|
|
70
75
|
|
|
@@ -76,24 +81,28 @@ const PresenceChild = ({
|
|
|
76
81
|
onExitComplete,
|
|
77
82
|
skipInitialAnimation,
|
|
78
83
|
className,
|
|
84
|
+
childKey,
|
|
85
|
+
onStateChange,
|
|
79
86
|
}: PresenceChildProps) => {
|
|
80
|
-
const [animationState, setAnimationState] =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
const [animationState, setAnimationState] =
|
|
88
|
+
useState<AnimatePresenceChildState>(() =>
|
|
89
|
+
skipInitialAnimation && isPresent
|
|
90
|
+
? "entered"
|
|
91
|
+
: isPresent
|
|
92
|
+
? "entering"
|
|
93
|
+
: "exited"
|
|
94
|
+
);
|
|
87
95
|
const timeoutRef = useRef<number>(undefined);
|
|
88
96
|
const isInitialMount = useRef(true);
|
|
89
97
|
|
|
90
|
-
const mergedAnimationStyles
|
|
98
|
+
const mergedAnimationStyles: Record<
|
|
99
|
+
AnimatePresenceChildState,
|
|
100
|
+
React.CSSProperties
|
|
101
|
+
> = {
|
|
91
102
|
...defaultAnimationStyles,
|
|
92
103
|
...animationStyles,
|
|
93
104
|
exited: {},
|
|
94
|
-
|
|
95
|
-
backfaceVisibility: "hidden",
|
|
96
|
-
} as Record<AnimationState, React.CSSProperties>;
|
|
105
|
+
};
|
|
97
106
|
|
|
98
107
|
useLayoutEffect(() => {
|
|
99
108
|
let rafId: number;
|
|
@@ -132,6 +141,11 @@ const PresenceChild = ({
|
|
|
132
141
|
skipInitialAnimation,
|
|
133
142
|
]);
|
|
134
143
|
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!childKey) return;
|
|
146
|
+
onStateChange?.(childKey, animationState);
|
|
147
|
+
}, [animationState, childKey, onStateChange]);
|
|
148
|
+
|
|
135
149
|
if (animationState === "exited" && !isPresent) {
|
|
136
150
|
return null;
|
|
137
151
|
}
|
|
@@ -151,11 +165,12 @@ type MountedChild = {
|
|
|
151
165
|
|
|
152
166
|
export const AnimatePresence = ({
|
|
153
167
|
children,
|
|
154
|
-
duration =
|
|
168
|
+
duration = 200,
|
|
155
169
|
animationStyles,
|
|
156
170
|
skipInitialAnimation,
|
|
157
171
|
mode = "wait",
|
|
158
172
|
className,
|
|
173
|
+
onChildStateChange,
|
|
159
174
|
}: AnimatePresenceProps) => {
|
|
160
175
|
const [mountedChildren, setMountedChildren] = useState<MountedChild[]>([]);
|
|
161
176
|
const previousChildrenRef = useRef<React.ReactElement<any>[]>([]);
|
|
@@ -255,12 +270,14 @@ export const AnimatePresence = ({
|
|
|
255
270
|
{mountedChildren.map(({ child, isPresent, skipInitialAnimation }) => (
|
|
256
271
|
<PresenceChild
|
|
257
272
|
key={child.key}
|
|
273
|
+
childKey={child.key?.toString() ?? ""}
|
|
258
274
|
duration={duration}
|
|
259
275
|
animationStyles={animationStyles}
|
|
260
276
|
isPresent={isPresent}
|
|
261
277
|
skipInitialAnimation={skipInitialAnimation}
|
|
262
278
|
onExitComplete={() => removeChild(child.key?.toString() ?? "")}
|
|
263
279
|
className={className}
|
|
280
|
+
onStateChange={onChildStateChange}
|
|
264
281
|
>
|
|
265
282
|
{child}
|
|
266
283
|
</PresenceChild>
|
|
@@ -268,5 +285,3 @@ export const AnimatePresence = ({
|
|
|
268
285
|
</>
|
|
269
286
|
);
|
|
270
287
|
};
|
|
271
|
-
|
|
272
|
-
export type { AnimatePresenceProps };
|
|
@@ -7,9 +7,10 @@ import { colorFromString } from "../utils/colorFromString";
|
|
|
7
7
|
|
|
8
8
|
const getInnerAvatarStyles = (
|
|
9
9
|
size: number,
|
|
10
|
-
variant: "normal" | "bare"
|
|
10
|
+
variant: "normal" | "bare" | "borderless"
|
|
11
11
|
): React.CSSProperties => {
|
|
12
|
-
const borderSize =
|
|
12
|
+
const borderSize =
|
|
13
|
+
variant === "bare" ? 4 : variant === "borderless" ? 0 : size > 36 ? 8 : 6;
|
|
13
14
|
const dimension = `${size - borderSize}px`;
|
|
14
15
|
return {
|
|
15
16
|
width: dimension,
|
|
@@ -20,7 +21,7 @@ const getInnerAvatarStyles = (
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const AvatarRoot = React.forwardRef<
|
|
23
|
-
React.
|
|
24
|
+
React.ComponentRef<typeof AvatarPrimitive.Root>,
|
|
24
25
|
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> &
|
|
25
26
|
Pick<AvatarProps, "size" | "variant" | "backgroundColor" | "disabled">
|
|
26
27
|
>(
|
|
@@ -51,8 +52,8 @@ const AvatarRoot = React.forwardRef<
|
|
|
51
52
|
ref={ref}
|
|
52
53
|
style={dynamicStyles}
|
|
53
54
|
className={cx(
|
|
54
|
-
"flex items-center justify-center align-middle overflow-hidden select-none cursor-pointer rounded-full",
|
|
55
|
-
variant !== "bare" && "border border-background",
|
|
55
|
+
"n-flex n-items-center n-justify-center n-align-middle n-overflow-hidden n-select-none n-cursor-pointer n-rounded-full",
|
|
56
|
+
variant !== "bare" && "n-border n-border-background",
|
|
56
57
|
className
|
|
57
58
|
)}
|
|
58
59
|
{...props}
|
|
@@ -62,7 +63,7 @@ const AvatarRoot = React.forwardRef<
|
|
|
62
63
|
);
|
|
63
64
|
|
|
64
65
|
const AvatarImage = React.forwardRef<
|
|
65
|
-
React.
|
|
66
|
+
React.ComponentRef<typeof AvatarPrimitive.Image>,
|
|
66
67
|
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> &
|
|
67
68
|
Pick<AvatarProps, "size" | "variant">
|
|
68
69
|
>(({ className, size = 21, variant = "normal", ...props }, ref) => {
|
|
@@ -70,7 +71,7 @@ const AvatarImage = React.forwardRef<
|
|
|
70
71
|
<AvatarPrimitive.Image
|
|
71
72
|
ref={ref}
|
|
72
73
|
className={cx(
|
|
73
|
-
"object-cover overflow-hidden rounded-full w-full h-full",
|
|
74
|
+
"n-object-cover n-overflow-hidden n-rounded-full n-w-full n-h-full",
|
|
74
75
|
className
|
|
75
76
|
)}
|
|
76
77
|
style={getInnerAvatarStyles(size, variant)}
|
|
@@ -84,7 +85,7 @@ function getMonogram(text?: string) {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
const AvatarFallback = React.forwardRef<
|
|
87
|
-
React.
|
|
88
|
+
React.ComponentRef<typeof AvatarPrimitive.Fallback>,
|
|
88
89
|
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> &
|
|
89
90
|
Pick<AvatarProps, "size" | "variant" | "backgroundColor">
|
|
90
91
|
>(
|
|
@@ -102,7 +103,7 @@ const AvatarFallback = React.forwardRef<
|
|
|
102
103
|
...style,
|
|
103
104
|
}}
|
|
104
105
|
className={cx(
|
|
105
|
-
"font-medium flex items-center justify-center text-white",
|
|
106
|
+
"n-font-medium n-flex n-items-center n-justify-center n-text-white",
|
|
106
107
|
className
|
|
107
108
|
)}
|
|
108
109
|
{...props}
|
|
@@ -125,7 +126,7 @@ export type AvatarProps = {
|
|
|
125
126
|
/** colors are generated from the fallback string or title, but you can override it here */
|
|
126
127
|
backgroundColor?: string;
|
|
127
128
|
/** @default normal */
|
|
128
|
-
variant?: "normal" | "bare";
|
|
129
|
+
variant?: "normal" | "bare" | "borderless";
|
|
129
130
|
disabled?: boolean;
|
|
130
131
|
/** Intended to be used in place of a fallback monogram, like an icon */
|
|
131
132
|
children?: React.ReactNode;
|
|
@@ -139,7 +140,7 @@ export const Avatar = React.memo(
|
|
|
139
140
|
name,
|
|
140
141
|
userId,
|
|
141
142
|
size = 21,
|
|
142
|
-
backgroundColor,
|
|
143
|
+
backgroundColor: backgroundColorProp,
|
|
143
144
|
variant = "normal",
|
|
144
145
|
children,
|
|
145
146
|
className,
|
|
@@ -147,14 +148,17 @@ export const Avatar = React.memo(
|
|
|
147
148
|
}: AvatarProps,
|
|
148
149
|
forwardedRef: React.ForwardedRef<HTMLDivElement>
|
|
149
150
|
) {
|
|
150
|
-
const
|
|
151
|
-
|
|
151
|
+
const backgroundColor =
|
|
152
|
+
backgroundColorProp ??
|
|
153
|
+
(variant === "borderless" && image
|
|
154
|
+
? undefined
|
|
155
|
+
: colorFromString(userId ?? name ?? ""));
|
|
152
156
|
|
|
153
157
|
return (
|
|
154
158
|
<AvatarRoot
|
|
155
159
|
ref={forwardedRef}
|
|
156
160
|
size={size}
|
|
157
|
-
backgroundColor={
|
|
161
|
+
backgroundColor={backgroundColor}
|
|
158
162
|
variant={variant}
|
|
159
163
|
className={className}
|
|
160
164
|
{...props}
|
|
@@ -163,7 +167,7 @@ export const Avatar = React.memo(
|
|
|
163
167
|
<AvatarImage src={image} alt={name} size={size} variant={variant} />
|
|
164
168
|
) : (
|
|
165
169
|
<AvatarFallback
|
|
166
|
-
backgroundColor={
|
|
170
|
+
backgroundColor={backgroundColor}
|
|
167
171
|
size={size}
|
|
168
172
|
variant={variant}
|
|
169
173
|
>
|
|
@@ -196,12 +200,14 @@ export const AvatarStack = React.memo(function AvatarStack({
|
|
|
196
200
|
children,
|
|
197
201
|
max = 3,
|
|
198
202
|
className,
|
|
203
|
+
overlapAmount = size > 36 ? 12 : 6,
|
|
199
204
|
}: {
|
|
200
205
|
size?: number;
|
|
201
206
|
/** @default 3 */
|
|
202
207
|
max?: number;
|
|
203
208
|
children: React.ReactNode;
|
|
204
209
|
className?: string;
|
|
210
|
+
overlapAmount?: number;
|
|
205
211
|
}) {
|
|
206
212
|
const avatarCount = React.Children.count(children);
|
|
207
213
|
// can add logic later to shorten values over 2 digits, etc.
|
|
@@ -209,7 +215,10 @@ export const AvatarStack = React.memo(function AvatarStack({
|
|
|
209
215
|
|
|
210
216
|
const childrenArray = useMemo(() => {
|
|
211
217
|
const processedChildren = React.Children.toArray(children)
|
|
212
|
-
.map((child) =>
|
|
218
|
+
.map((child) =>
|
|
219
|
+
React.cloneElement(child as React.ReactElement<any>, { size })
|
|
220
|
+
)
|
|
221
|
+
.reverse()
|
|
213
222
|
.slice(0, max);
|
|
214
223
|
|
|
215
224
|
if (avatarCount > max) {
|
|
@@ -222,20 +231,28 @@ export const AvatarStack = React.memo(function AvatarStack({
|
|
|
222
231
|
return processedChildren;
|
|
223
232
|
}, [children, max, size, avatarCount, overflowCount]);
|
|
224
233
|
|
|
234
|
+
const containerStyle = useMemo(
|
|
235
|
+
() => ({
|
|
236
|
+
paddingLeft: overlapAmount,
|
|
237
|
+
}),
|
|
238
|
+
[overlapAmount]
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const itemStyle = useMemo(
|
|
242
|
+
() => ({
|
|
243
|
+
marginLeft: -overlapAmount,
|
|
244
|
+
}),
|
|
245
|
+
[overlapAmount]
|
|
246
|
+
);
|
|
247
|
+
|
|
225
248
|
return (
|
|
226
249
|
<div
|
|
227
|
-
className={cx(
|
|
228
|
-
|
|
229
|
-
size > 36 ? "pl-3" : "pl-1.5",
|
|
230
|
-
className
|
|
231
|
-
)}
|
|
250
|
+
className={cx("n-flex n-flex-row-reverse", className)}
|
|
251
|
+
style={containerStyle}
|
|
232
252
|
>
|
|
233
253
|
{childrenArray.map((child, index) => {
|
|
234
254
|
return (
|
|
235
|
-
<div
|
|
236
|
-
className={cx("relative", size > 36 ? "-ml-3" : "-ml-1.5")}
|
|
237
|
-
key={index}
|
|
238
|
-
>
|
|
255
|
+
<div key={index} className="n-relative" style={itemStyle}>
|
|
239
256
|
{child}
|
|
240
257
|
</div>
|
|
241
258
|
);
|
|
@@ -1,29 +1,75 @@
|
|
|
1
|
+
import { ExclamationTriangleIcon, InfoCircledIcon } from "@noya-app/noya-icons";
|
|
1
2
|
import React, { CSSProperties, ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { cx } from "../utils/classNames";
|
|
3
|
+
import { cx, mergeConflictingClassNames } from "../utils/classNames";
|
|
4
4
|
import { Small } from "./Text";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
backgroundColor: cssVars.colors.inputBackground,
|
|
8
|
-
color: cssVars.colors.textDisabled,
|
|
9
|
-
};
|
|
6
|
+
type BannerVariant = "muted" | "info" | "error";
|
|
10
7
|
|
|
11
8
|
export type BannerProps = {
|
|
12
|
-
|
|
9
|
+
children?: ReactNode;
|
|
13
10
|
className?: string;
|
|
14
11
|
style?: CSSProperties;
|
|
12
|
+
variant?: BannerVariant;
|
|
13
|
+
labelStyle?: CSSProperties;
|
|
14
|
+
labelClassName?: string;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export function Banner({
|
|
17
|
+
export function Banner({
|
|
18
|
+
children: label = "No items",
|
|
19
|
+
className,
|
|
20
|
+
style,
|
|
21
|
+
variant = "muted",
|
|
22
|
+
labelStyle,
|
|
23
|
+
labelClassName: labelClassNameProp,
|
|
24
|
+
}: BannerProps) {
|
|
25
|
+
const labelClassName = mergeConflictingClassNames(
|
|
26
|
+
[
|
|
27
|
+
"n-flex-1 n-text-center",
|
|
28
|
+
variant === "muted"
|
|
29
|
+
? "!n-text-text-disabled"
|
|
30
|
+
: variant === "error"
|
|
31
|
+
? "!n-text-banner-error-text"
|
|
32
|
+
: "!n-text-banner-info-text",
|
|
33
|
+
labelClassNameProp,
|
|
34
|
+
],
|
|
35
|
+
{
|
|
36
|
+
categories: ["textAlign"],
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
18
40
|
return (
|
|
19
41
|
<div
|
|
20
42
|
className={cx(
|
|
21
|
-
"flex
|
|
43
|
+
"n-flex n-py-1 n-px-1.5 n-items-center n-justify-center n-select-none n-rounded n-gap-1.5 n-min-h-input-height",
|
|
44
|
+
variant === "muted" && "n-bg-input-background",
|
|
45
|
+
variant === "info" &&
|
|
46
|
+
"n-bg-banner-info-background n-border n-border-banner-info-border",
|
|
47
|
+
variant === "error" &&
|
|
48
|
+
"n-bg-banner-error-background n-border n-border-banner-error-border",
|
|
22
49
|
className
|
|
23
50
|
)}
|
|
24
|
-
style={
|
|
51
|
+
style={style}
|
|
25
52
|
>
|
|
26
|
-
|
|
53
|
+
{(variant === "info" || variant === "error") && (
|
|
54
|
+
<Small
|
|
55
|
+
className={cx(
|
|
56
|
+
"n-flex-none n-self-start n-flex n-items-center",
|
|
57
|
+
variant === "error"
|
|
58
|
+
? "!n-text-banner-error-text"
|
|
59
|
+
: "!n-text-banner-info-text"
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
{`\u200B`}
|
|
63
|
+
{variant === "error" ? (
|
|
64
|
+
<ExclamationTriangleIcon className="n-text-heading5" />
|
|
65
|
+
) : (
|
|
66
|
+
<InfoCircledIcon className="n-text-heading5" />
|
|
67
|
+
)}
|
|
68
|
+
</Small>
|
|
69
|
+
)}
|
|
70
|
+
<Small className={labelClassName} style={labelStyle}>
|
|
71
|
+
{label}
|
|
72
|
+
</Small>
|
|
27
73
|
</div>
|
|
28
74
|
);
|
|
29
75
|
}
|