@noya-app/noya-designsystem 0.1.47 → 0.1.49
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 +18 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +389 -241
- package/dist/index.d.ts +389 -241
- package/dist/index.js +4802 -3990
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4715 -3915
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/validateDropIndicator.test.ts +263 -0
- package/src/components/ActionMenu.tsx +51 -0
- package/src/components/ActivityIndicator.tsx +7 -1
- package/src/components/BaseToolbar.tsx +2 -2
- package/src/components/Checkbox.tsx +2 -2
- package/src/components/Chip.tsx +7 -6
- package/src/components/Collection.tsx +30 -2
- package/src/components/Combobox.tsx +27 -15
- package/src/components/ComboboxMenu.tsx +15 -6
- package/src/components/Dialog.tsx +17 -12
- package/src/components/DimensionInput.tsx +14 -12
- package/src/components/Drawer.tsx +98 -0
- package/src/components/EditableText.tsx +3 -1
- package/src/components/FillInputField.tsx +2 -2
- package/src/components/Grid.tsx +161 -111
- package/src/components/GridView.tsx +73 -41
- package/src/components/InputField.tsx +148 -208
- package/src/components/Label.tsx +4 -68
- package/src/components/LabeledField.tsx +7 -1
- package/src/components/List.tsx +135 -50
- package/src/components/ListView.tsx +63 -43
- package/src/components/MediaThumbnail.tsx +117 -0
- package/src/components/Message.tsx +8 -8
- package/src/components/NoyaLogo.tsx +41 -0
- package/src/components/SearchCompletionMenu.tsx +30 -16
- package/src/components/SegmentedControl.tsx +1 -1
- package/src/components/SelectMenu.tsx +28 -21
- package/src/components/Slider.tsx +16 -7
- package/src/components/Sortable.tsx +125 -62
- package/src/components/internal/Menu.tsx +45 -25
- package/src/components/internal/MenuViewport.tsx +7 -1
- package/src/components/internal/SelectItem.tsx +53 -28
- package/src/components/internal/__tests__/Menu.test.tsx +12 -0
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +86 -0
- package/src/components/workspace/PanelWorkspaceLayout.tsx +102 -0
- package/src/components/{WorkspaceLayout.tsx → workspace/WorkspaceLayout.tsx} +109 -106
- package/src/components/workspace/types.ts +31 -0
- package/src/contexts/DialogContext.tsx +49 -34
- package/src/hooks/usePreservePanelSize.tsx +1 -5
- package/src/index.css +8 -1
- package/src/index.tsx +6 -1
- package/src/theme/index.ts +2 -0
- package/src/utils/classNames.ts +51 -3
- package/src/utils/inputs.ts +21 -0
- package/tailwind.config.ts +8 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { ImageIcon, SpeakerLoudIcon, VideoIcon } from "@noya-app/noya-icons";
|
|
2
|
+
import React, { memo, useMemo } from "react";
|
|
3
|
+
import { cssVars } from "../theme";
|
|
4
|
+
import { cx } from "../utils/classNames";
|
|
5
|
+
import { IconName, Icons } from "./Icons";
|
|
6
|
+
|
|
7
|
+
type ColorScheme = "primary" | "icon" | "warning";
|
|
8
|
+
|
|
9
|
+
type AssetType = "image" | "video" | "audio";
|
|
10
|
+
|
|
11
|
+
const getAssetType = (contentType?: string): AssetType | undefined => {
|
|
12
|
+
if (!contentType) return undefined;
|
|
13
|
+
if (contentType.startsWith("image/")) return "image";
|
|
14
|
+
if (contentType.startsWith("video/")) return "video";
|
|
15
|
+
if (contentType.startsWith("audio/")) return "audio";
|
|
16
|
+
return undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type MediaThumbnailProps = {
|
|
20
|
+
contentType?: string;
|
|
21
|
+
url?: string;
|
|
22
|
+
selected?: boolean;
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Color scheme for the thumbnail. Affects icon color and background.
|
|
25
|
+
* @default "icon"
|
|
26
|
+
*/
|
|
27
|
+
colorScheme?: ColorScheme;
|
|
28
|
+
/**
|
|
29
|
+
* If provided, use this icon instead of the default one for the asset type
|
|
30
|
+
*/
|
|
31
|
+
iconName?: IconName;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getColors = (colorScheme: ColorScheme, selected: boolean) => {
|
|
35
|
+
if (selected) {
|
|
36
|
+
return {
|
|
37
|
+
icon: cssVars.colors.primary,
|
|
38
|
+
background: cssVars.colors.primaryPastel,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
switch (colorScheme) {
|
|
43
|
+
case "primary":
|
|
44
|
+
return {
|
|
45
|
+
icon: cssVars.colors.primary,
|
|
46
|
+
background: cssVars.colors.listViewThumbnailBackground,
|
|
47
|
+
};
|
|
48
|
+
case "warning":
|
|
49
|
+
return {
|
|
50
|
+
icon: cssVars.colors.warning,
|
|
51
|
+
background: cssVars.colors.listViewThumbnailBackground,
|
|
52
|
+
};
|
|
53
|
+
case "icon":
|
|
54
|
+
default:
|
|
55
|
+
return {
|
|
56
|
+
icon: cssVars.colors.icon,
|
|
57
|
+
background: cssVars.colors.listViewThumbnailBackground,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const iconStyles = {
|
|
63
|
+
width: "max(15px, 20%)",
|
|
64
|
+
height: "max(15px, 20%)",
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const MediaThumbnail = memo(function MediaThumbnail({
|
|
68
|
+
contentType: contentTypeProp,
|
|
69
|
+
selected = false,
|
|
70
|
+
className,
|
|
71
|
+
colorScheme = "icon",
|
|
72
|
+
url,
|
|
73
|
+
iconName = "FileIcon",
|
|
74
|
+
}: MediaThumbnailProps) {
|
|
75
|
+
const { icon: iconColor, background: backgroundColor } = getColors(
|
|
76
|
+
colorScheme,
|
|
77
|
+
selected
|
|
78
|
+
);
|
|
79
|
+
const contentType = getAssetType(contentTypeProp);
|
|
80
|
+
|
|
81
|
+
const content = useMemo(() => {
|
|
82
|
+
switch (contentType) {
|
|
83
|
+
case "image":
|
|
84
|
+
if (!url) return <ImageIcon color={iconColor} style={iconStyles} />;
|
|
85
|
+
return (
|
|
86
|
+
<img
|
|
87
|
+
src={url}
|
|
88
|
+
alt=""
|
|
89
|
+
className="object-contain w-full h-full"
|
|
90
|
+
tabIndex={-1}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
case "video":
|
|
95
|
+
return <VideoIcon color={iconColor} style={iconStyles} />;
|
|
96
|
+
|
|
97
|
+
case "audio":
|
|
98
|
+
return <SpeakerLoudIcon color={iconColor} style={iconStyles} />;
|
|
99
|
+
|
|
100
|
+
default:
|
|
101
|
+
const Icon = Icons[iconName];
|
|
102
|
+
return <Icon color={iconColor} style={iconStyles} />;
|
|
103
|
+
}
|
|
104
|
+
}, [contentType, url, iconColor, iconName]);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div
|
|
108
|
+
className={cx(
|
|
109
|
+
"w-full h-full justify-center flex items-center aspect-square",
|
|
110
|
+
className
|
|
111
|
+
)}
|
|
112
|
+
style={{ backgroundColor }}
|
|
113
|
+
>
|
|
114
|
+
{content}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { MultiplayerUser } from "@noya-app/noya-multiplayer-react";
|
|
1
2
|
import React, { forwardRef, memo, useMemo } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { Avatar } from "./Avatar";
|
|
3
|
+
import { cssVars, INPUT_HEIGHT } from "../theme";
|
|
4
4
|
import { cx } from "../utils/classNames";
|
|
5
|
-
import { Text } from "./Text";
|
|
6
|
-
import { MultiplayerUser } from "@noya-app/noya-multiplayer-react";
|
|
7
5
|
import { colorFromString } from "../utils/colorFromString";
|
|
8
|
-
import {
|
|
6
|
+
import { Avatar } from "./Avatar";
|
|
7
|
+
import { Logo } from "./NoyaLogo";
|
|
8
|
+
import { Text } from "./Text";
|
|
9
9
|
|
|
10
10
|
export type MessageProps = {
|
|
11
11
|
role: "user" | "assistant" | "system" | "data";
|
|
@@ -17,7 +17,7 @@ export type MessageProps = {
|
|
|
17
17
|
|
|
18
18
|
export const Message = memo(
|
|
19
19
|
forwardRef(function Message(
|
|
20
|
-
{ role, children, user, avatarSize =
|
|
20
|
+
{ role, children, user, avatarSize = INPUT_HEIGHT }: MessageProps,
|
|
21
21
|
ref: React.ForwardedRef<HTMLDivElement>
|
|
22
22
|
) {
|
|
23
23
|
const randomId = crypto.randomUUID();
|
|
@@ -42,9 +42,9 @@ export const Message = memo(
|
|
|
42
42
|
<Avatar
|
|
43
43
|
name="Assistant"
|
|
44
44
|
size={avatarSize}
|
|
45
|
-
backgroundColor={cssVars.colors.
|
|
45
|
+
backgroundColor={cssVars.colors.primaryPastel}
|
|
46
46
|
>
|
|
47
|
-
<
|
|
47
|
+
<Logo style={{ width: 15 }} fill={cssVars.colors.primary} />
|
|
48
48
|
</Avatar>
|
|
49
49
|
) : (
|
|
50
50
|
<Avatar
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { cssVars } from "@noya-app/noya-designsystem";
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
|
|
4
|
+
export const Logo = forwardRef(function Logo(
|
|
5
|
+
props: React.ComponentProps<"svg">,
|
|
6
|
+
ref: React.Ref<SVGSVGElement>
|
|
7
|
+
) {
|
|
8
|
+
const fill = props.fill || cssVars.colors.logoFill;
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
ref={ref}
|
|
13
|
+
viewBox="0 0 24 26"
|
|
14
|
+
fill="none"
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
{...props}
|
|
17
|
+
className="w-6 aspect-[24/26]"
|
|
18
|
+
>
|
|
19
|
+
<path
|
|
20
|
+
d="M6.5 3H2V12H5V6H6.5C7.32843 6 8 6.67157 8 7.5V12H11V7.5C11 5.01472 8.98528 3 6.5 3Z"
|
|
21
|
+
fill={fill}
|
|
22
|
+
/>
|
|
23
|
+
<path
|
|
24
|
+
fillRule="evenodd"
|
|
25
|
+
clipRule="evenodd"
|
|
26
|
+
d="M17.5 12C19.9853 12 22 9.98528 22 7.5C22 5.01472 19.9853 3 17.5 3C15.0147 3 13 5.01472 13 7.5C13 9.98528 15.0147 12 17.5 12ZM17.5 9C18.3284 9 19 8.32843 19 7.5C19 6.67157 18.3284 6 17.5 6C16.6716 6 16 6.67157 16 7.5C16 8.32843 16.6716 9 17.5 9Z"
|
|
27
|
+
fill={fill}
|
|
28
|
+
/>
|
|
29
|
+
<path
|
|
30
|
+
d="M5 14H2V18.5C2 20.9853 4.01472 23 6.5 23H8V26H11V17H8V20H6.5C5.67157 20 5 19.3284 5 18.5V14Z"
|
|
31
|
+
fill={fill}
|
|
32
|
+
/>
|
|
33
|
+
<path
|
|
34
|
+
fillRule="evenodd"
|
|
35
|
+
clipRule="evenodd"
|
|
36
|
+
d="M17.5 23C15.0147 23 13 20.9853 13 18.5C13 16.0147 15.0147 14 17.5 14C19.9853 14 22 16.0147 22 18.5V23H17.5ZM17.5 20C18.3284 20 19 19.3284 19 18.5C19 17.6716 18.3284 17 17.5 17C16.6716 17 16 17.6716 16 18.5C16 19.3284 16.6716 20 17.5 20Z"
|
|
37
|
+
fill={fill}
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ComboboxMenu,
|
|
3
|
-
Divider,
|
|
4
|
-
IScoredItem,
|
|
5
|
-
InputField,
|
|
6
|
-
ListView,
|
|
7
|
-
SelectableMenuItem,
|
|
8
|
-
Small,
|
|
9
|
-
cssVars,
|
|
10
|
-
fuzzyFilter,
|
|
11
|
-
getNextIndex,
|
|
12
|
-
isSelectableMenuItem,
|
|
13
|
-
} from "@noya-app/noya-designsystem";
|
|
14
1
|
import { getCurrentPlatform, handleKeyboardEvent } from "@noya-app/noya-keymap";
|
|
15
2
|
import React, {
|
|
16
3
|
forwardRef,
|
|
@@ -21,6 +8,21 @@ import React, {
|
|
|
21
8
|
useRef,
|
|
22
9
|
useState,
|
|
23
10
|
} from "react";
|
|
11
|
+
import { cssVars } from "../theme";
|
|
12
|
+
import { getNextIndex } from "../utils/combobox";
|
|
13
|
+
import { fuzzyFilter, IScoredItem } from "../utils/fuzzyScorer";
|
|
14
|
+
import { ComboboxMenu } from "./ComboboxMenu";
|
|
15
|
+
import { Divider } from "./Divider";
|
|
16
|
+
import { InputField } from "./InputField";
|
|
17
|
+
import {
|
|
18
|
+
CHECKBOX_INDENT_WIDTH,
|
|
19
|
+
CHECKBOX_RIGHT_INSET,
|
|
20
|
+
CHECKBOX_WIDTH,
|
|
21
|
+
isSelectableMenuItem,
|
|
22
|
+
SelectableMenuItem,
|
|
23
|
+
} from "./internal/Menu";
|
|
24
|
+
import { ListView } from "./ListView";
|
|
25
|
+
import { Small } from "./Text";
|
|
24
26
|
|
|
25
27
|
export interface ISearchCompletionMenu {
|
|
26
28
|
focus: () => void;
|
|
@@ -33,17 +35,21 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
|
|
|
33
35
|
onClose,
|
|
34
36
|
items,
|
|
35
37
|
width = 200,
|
|
38
|
+
testSelectedIndex,
|
|
39
|
+
testSearch,
|
|
36
40
|
}: {
|
|
37
41
|
onSelect: (item: SelectableMenuItem<string>) => void;
|
|
38
42
|
onHover?: (item: SelectableMenuItem<string>) => void;
|
|
39
43
|
onClose: () => void;
|
|
40
44
|
items: SelectableMenuItem<string>[];
|
|
41
45
|
width?: number;
|
|
46
|
+
testSelectedIndex?: number;
|
|
47
|
+
testSearch?: string;
|
|
42
48
|
},
|
|
43
49
|
forwardedRef: React.ForwardedRef<ISearchCompletionMenu>
|
|
44
50
|
) {
|
|
45
51
|
const [state, setState] = useState({
|
|
46
|
-
search: "",
|
|
52
|
+
search: testSearch ?? "",
|
|
47
53
|
index: 0,
|
|
48
54
|
});
|
|
49
55
|
|
|
@@ -51,6 +57,8 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
|
|
|
51
57
|
|
|
52
58
|
const listRef = React.useRef<ListView.VirtualizedList>(null);
|
|
53
59
|
|
|
60
|
+
const hasCheckedItems = items.some((item) => item.checked);
|
|
61
|
+
|
|
54
62
|
useEffect(() => {
|
|
55
63
|
listRef.current?.scrollToIndex(index);
|
|
56
64
|
}, [index]);
|
|
@@ -157,7 +165,12 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
|
|
|
157
165
|
outline: "none",
|
|
158
166
|
boxShadow: "none",
|
|
159
167
|
backgroundColor: cssVars.colors.inputBackground,
|
|
160
|
-
|
|
168
|
+
paddingTop: "4px",
|
|
169
|
+
paddingBottom: "4px",
|
|
170
|
+
paddingLeft: hasCheckedItems
|
|
171
|
+
? `${CHECKBOX_WIDTH - CHECKBOX_RIGHT_INSET + 12 + CHECKBOX_INDENT_WIDTH}px`
|
|
172
|
+
: "12px",
|
|
173
|
+
paddingRight: "12px",
|
|
161
174
|
}}
|
|
162
175
|
onChange={setSearch}
|
|
163
176
|
onKeyDown={handleKeyDown}
|
|
@@ -169,13 +182,14 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
|
|
|
169
182
|
ref={listRef}
|
|
170
183
|
listSize={listSize}
|
|
171
184
|
items={results}
|
|
172
|
-
selectedIndex={index}
|
|
185
|
+
selectedIndex={testSelectedIndex ?? index}
|
|
173
186
|
onSelectItem={(item) => {
|
|
174
187
|
if (isSelectableMenuItem(item)) {
|
|
175
188
|
selectAndClose(item);
|
|
176
189
|
}
|
|
177
190
|
}}
|
|
178
191
|
onHoverIndex={setIndex}
|
|
192
|
+
indented={hasCheckedItems}
|
|
179
193
|
/>
|
|
180
194
|
) : (
|
|
181
195
|
<div
|
|
@@ -141,7 +141,7 @@ export const SegmentedControl = memoGeneric(function SegmentedControl<
|
|
|
141
141
|
value={value}
|
|
142
142
|
onValueChange={handleValueChange}
|
|
143
143
|
className={cx(
|
|
144
|
-
`flex items-stretch flex-auto appearance-none relative outline-none min-h-
|
|
144
|
+
`flex items-stretch flex-auto appearance-none relative outline-none min-h-input-height rounded bg-input-background py-[2px] px-[2px]`,
|
|
145
145
|
className
|
|
146
146
|
)}
|
|
147
147
|
style={style}
|
|
@@ -15,6 +15,7 @@ import React, {
|
|
|
15
15
|
import { useLabel, useLabelPosition } from "../hooks/useLabel";
|
|
16
16
|
import { cx } from "../utils/classNames";
|
|
17
17
|
|
|
18
|
+
import { getInsetEndStyles } from "../utils/inputs";
|
|
18
19
|
import { Button } from "./Button";
|
|
19
20
|
import { renderIcon } from "./Icons";
|
|
20
21
|
import {
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
styles,
|
|
25
26
|
} from "./internal/Menu";
|
|
26
27
|
import { MenuComponents, MenuViewport } from "./internal/MenuViewport";
|
|
27
|
-
import {
|
|
28
|
+
import { Label } from "./Label";
|
|
28
29
|
|
|
29
30
|
type Props<T extends string> = {
|
|
30
31
|
id?: string;
|
|
@@ -57,6 +58,8 @@ const scrollButtonStyles = `
|
|
|
57
58
|
hover:text-text
|
|
58
59
|
`;
|
|
59
60
|
|
|
61
|
+
const insetEndStyles = getInsetEndStyles();
|
|
62
|
+
|
|
60
63
|
interface SelectMenuTriggerProps {
|
|
61
64
|
id?: string;
|
|
62
65
|
style?: React.CSSProperties;
|
|
@@ -93,7 +96,7 @@ const SelectMenuTrigger = memoGeneric(function SelectMenuTrigger({
|
|
|
93
96
|
id={id}
|
|
94
97
|
style={style}
|
|
95
98
|
className={cx(
|
|
96
|
-
className ?? "flex w-full
|
|
99
|
+
className ?? "flex w-full",
|
|
97
100
|
"flex-1 focus:z-interactable relative",
|
|
98
101
|
isOpen && "ring-2 ring-primary"
|
|
99
102
|
)}
|
|
@@ -101,22 +104,21 @@ const SelectMenuTrigger = memoGeneric(function SelectMenuTrigger({
|
|
|
101
104
|
>
|
|
102
105
|
{icon && <span className="pr-1.5">{renderIcon(icon)}</span>}
|
|
103
106
|
{label && labelPosition === "inset" && (
|
|
104
|
-
<
|
|
105
|
-
{
|
|
106
|
-
|
|
107
|
+
<div className={insetEndStyles}>
|
|
108
|
+
<Label className="pr-4 !text-text-disabled" htmlFor={id}>
|
|
109
|
+
{label}
|
|
110
|
+
</Label>
|
|
111
|
+
</div>
|
|
107
112
|
)}
|
|
108
113
|
<span className="flex-1 flex">
|
|
109
114
|
<Select.Value placeholder={placeholder} />
|
|
110
115
|
</span>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)}
|
|
118
|
-
/>
|
|
119
|
-
</span>
|
|
116
|
+
<DropdownChevronIcon
|
|
117
|
+
className={cx(
|
|
118
|
+
"transition-transform duration-100 ml-1.5",
|
|
119
|
+
isOpen ? "rotate-180" : "rotate-0"
|
|
120
|
+
)}
|
|
121
|
+
/>
|
|
120
122
|
</Button>
|
|
121
123
|
</Select.SelectTrigger>
|
|
122
124
|
);
|
|
@@ -143,7 +145,7 @@ export const SelectMenu = memoGeneric(function SelectMenu<
|
|
|
143
145
|
onFocus,
|
|
144
146
|
onBlur,
|
|
145
147
|
onOpenChange,
|
|
146
|
-
contentStyle,
|
|
148
|
+
contentStyle: contentStyleProp,
|
|
147
149
|
...props
|
|
148
150
|
}: Props<T>) {
|
|
149
151
|
const selectedItem = items.find(
|
|
@@ -181,6 +183,15 @@ export const SelectMenu = memoGeneric(function SelectMenu<
|
|
|
181
183
|
[icon, id, style, className, disabled, value, selectedItem]
|
|
182
184
|
);
|
|
183
185
|
|
|
186
|
+
const contentStyle = useMemo(() => {
|
|
187
|
+
return {
|
|
188
|
+
width: "var(--radix-select-trigger-width)",
|
|
189
|
+
minWidth: "max-content",
|
|
190
|
+
maxHeight: "500px",
|
|
191
|
+
...contentStyleProp,
|
|
192
|
+
};
|
|
193
|
+
}, [contentStyleProp]);
|
|
194
|
+
|
|
184
195
|
const content = (
|
|
185
196
|
<Select.Root
|
|
186
197
|
value={value}
|
|
@@ -206,12 +217,8 @@ export const SelectMenu = memoGeneric(function SelectMenu<
|
|
|
206
217
|
position="popper"
|
|
207
218
|
sideOffset={6}
|
|
208
219
|
collisionPadding={8}
|
|
209
|
-
align="
|
|
210
|
-
style={
|
|
211
|
-
width: "var(--radix-select-trigger-width)",
|
|
212
|
-
maxHeight: "500px",
|
|
213
|
-
...contentStyle,
|
|
214
|
-
}}
|
|
220
|
+
align="center"
|
|
221
|
+
style={contentStyle}
|
|
215
222
|
>
|
|
216
223
|
<Select.ScrollUpButton className={scrollButtonStyles}>
|
|
217
224
|
<ChevronUpIcon
|
|
@@ -2,7 +2,8 @@ import * as RadixSlider from "@radix-ui/react-slider";
|
|
|
2
2
|
import React, { FocusEventHandler, memo, useCallback, useMemo } from "react";
|
|
3
3
|
import { useLabel, useLabelPosition } from "../hooks/useLabel";
|
|
4
4
|
import { cx } from "../utils/classNames";
|
|
5
|
-
import {
|
|
5
|
+
import { getInsetEndStyles } from "../utils/inputs";
|
|
6
|
+
import { Label } from "./Label";
|
|
6
7
|
|
|
7
8
|
type ColorScheme = "primary" | "secondary";
|
|
8
9
|
|
|
@@ -28,6 +29,8 @@ const thumbStyle = {
|
|
|
28
29
|
width: THUMB_WIDTH,
|
|
29
30
|
};
|
|
30
31
|
|
|
32
|
+
const insetEndStyles = getInsetEndStyles();
|
|
33
|
+
|
|
31
34
|
export const Slider = memo(function Slider({
|
|
32
35
|
style,
|
|
33
36
|
className,
|
|
@@ -95,7 +98,7 @@ export const Slider = memo(function Slider({
|
|
|
95
98
|
value={arrayValue}
|
|
96
99
|
onValueChange={handleValueChange}
|
|
97
100
|
className={cx(
|
|
98
|
-
"flex relative items-center select-none touch-none h-
|
|
101
|
+
"flex relative items-center select-none touch-none h-input-height rounded overflow-hidden flex-grow max-h-input-height",
|
|
99
102
|
className
|
|
100
103
|
)}
|
|
101
104
|
style={style}
|
|
@@ -105,7 +108,11 @@ export const Slider = memo(function Slider({
|
|
|
105
108
|
>
|
|
106
109
|
<RadixSlider.Track className="flex-grow h-full rounded overflow-hidden bg-input-background">
|
|
107
110
|
{label && labelPosition === "inset" && (
|
|
108
|
-
<
|
|
111
|
+
<div className={insetEndStyles}>
|
|
112
|
+
<Label htmlFor={id} className="!text-text-disabled">
|
|
113
|
+
{label}
|
|
114
|
+
</Label>
|
|
115
|
+
</div>
|
|
109
116
|
)}
|
|
110
117
|
<div
|
|
111
118
|
style={trackFillStyle}
|
|
@@ -117,14 +124,16 @@ export const Slider = memo(function Slider({
|
|
|
117
124
|
/>
|
|
118
125
|
</RadixSlider.Track>
|
|
119
126
|
{label && labelPosition === "inset" && colorScheme !== undefined && (
|
|
120
|
-
<
|
|
121
|
-
{
|
|
122
|
-
|
|
127
|
+
<div className={insetEndStyles}>
|
|
128
|
+
<Label className="text-white overflow-hidden" style={labelStyle}>
|
|
129
|
+
{label}
|
|
130
|
+
</Label>
|
|
131
|
+
</div>
|
|
123
132
|
)}
|
|
124
133
|
<RadixSlider.Thumb
|
|
125
134
|
style={thumbStyle}
|
|
126
135
|
className={cx(
|
|
127
|
-
"block h-
|
|
136
|
+
"block h-input-height rounded border border-solid bg-slider-thumb-background transition-colors focus:border-primary focus:border-2 outline-none",
|
|
128
137
|
colorScheme === undefined && "border-slider-border",
|
|
129
138
|
colorScheme === "primary" && "border-primary",
|
|
130
139
|
colorScheme === "secondary" && "border-secondary"
|