@vuer-ai/vuer-uikit 0.0.12 → 0.0.13
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/package.json +3 -2
- package/src/highlight-cursor/cursor-context.tsx +23 -0
- package/src/highlight-cursor/cursor-provider.tsx +264 -0
- package/src/highlight-cursor/enhanced-components.tsx +16 -0
- package/src/highlight-cursor/index.ts +21 -0
- package/src/highlight-cursor/tabs-cursor-context.tsx +121 -0
- package/src/highlight-cursor/types.ts +40 -0
- package/src/highlight-cursor/with-cursor.tsx +144 -0
- package/src/index.css +5 -0
- package/src/index.ts +5 -0
- package/src/styles/theme.css +80 -0
- package/src/styles/toast.css +64 -0
- package/src/styles/variables.css +194 -0
- package/src/ui/avatar.tsx +92 -0
- package/src/ui/badge.tsx +68 -0
- package/src/ui/button.tsx +100 -0
- package/src/ui/card.tsx +88 -0
- package/src/ui/checkbox.tsx +76 -0
- package/src/ui/collapsible.tsx +36 -0
- package/src/ui/dropdown.tsx +375 -0
- package/src/ui/index.ts +31 -0
- package/src/ui/input-numbers.tsx +201 -0
- package/src/ui/input.tsx +141 -0
- package/src/ui/layout.tsx +41 -0
- package/src/ui/modal.tsx +198 -0
- package/src/ui/popover.tsx +59 -0
- package/src/ui/radio-group.tsx +56 -0
- package/src/ui/select.tsx +292 -0
- package/src/ui/sheet.tsx +131 -0
- package/src/ui/slider.tsx +189 -0
- package/src/ui/switch.tsx +43 -0
- package/src/ui/tabs.tsx +128 -0
- package/src/ui/textarea.tsx +52 -0
- package/src/ui/theme-context.tsx +80 -0
- package/src/ui/timeline.tsx +717 -0
- package/src/ui/toast.tsx +27 -0
- package/src/ui/toggle-group.tsx +82 -0
- package/src/ui/toggle.tsx +88 -0
- package/src/ui/tooltip.tsx +132 -0
- package/src/ui/tree-view-v2.tsx +300 -0
- package/src/ui/tree-view.tsx +550 -0
- package/src/ui/version-badge.tsx +65 -0
- package/src/utils/cn.ts +21 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/use-local-storage.ts +59 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
4
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../utils";
|
|
7
|
+
|
|
8
|
+
function Select({ ...props }: ComponentProps<typeof SelectPrimitive.Root>) {
|
|
9
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function SelectGroup({ className, ...props }: ComponentProps<typeof SelectPrimitive.Group>) {
|
|
13
|
+
return (
|
|
14
|
+
<SelectPrimitive.Group
|
|
15
|
+
data-slot="select-group"
|
|
16
|
+
className={cn("space-y-xs", className)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function SelectValue({ ...props }: ComponentProps<typeof SelectPrimitive.Value>) {
|
|
23
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const selectTriggerVariants = cva(
|
|
27
|
+
[
|
|
28
|
+
"flex",
|
|
29
|
+
"items-center",
|
|
30
|
+
"justify-between",
|
|
31
|
+
"gap-2",
|
|
32
|
+
"rounded-uk-sm",
|
|
33
|
+
"bg-bg-secondary",
|
|
34
|
+
"whitespace-nowrap",
|
|
35
|
+
"shadow-xs",
|
|
36
|
+
"transition-[color,box-shadow]",
|
|
37
|
+
"outline-none",
|
|
38
|
+
"*:data-[slot=select-value]:line-clamp-1",
|
|
39
|
+
"*:data-[slot=select-value]:flex",
|
|
40
|
+
"*:data-[slot=select-value]:items-center",
|
|
41
|
+
"*:data-[slot=select-value]:gap-2",
|
|
42
|
+
"[&_svg]:shrink-0",
|
|
43
|
+
"[&_svg]:pointer-events-none",
|
|
44
|
+
"[&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
45
|
+
],
|
|
46
|
+
{
|
|
47
|
+
variants: {
|
|
48
|
+
state: {
|
|
49
|
+
default: ["hover:bg-bg-tertiary", "has-[input:focus]:bg-bg-quaternary"],
|
|
50
|
+
disabled: ["disabled:cursor-not-allowed", "bg-bg-tertiary", "text-text-tertiary"],
|
|
51
|
+
error: ["hover:bg-danger-primary/10", "bg-danger-primary/20"],
|
|
52
|
+
},
|
|
53
|
+
size: {
|
|
54
|
+
sm: "px-sm py-xs text-uk-sm h-5.5 [&_svg:not([class*='size-'])]:size-lg",
|
|
55
|
+
base: "px-md py-sm text-uk-md h-7 [&_svg:not([class*='size-'])]:size-[14px]",
|
|
56
|
+
lg: "px-lg py-sm text-uk-lg h-8 [&_svg:not([class*='size-'])]:size-xl",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
state: "default",
|
|
61
|
+
size: "base",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
interface SelectTriggerProps
|
|
67
|
+
extends ComponentProps<typeof SelectPrimitive.Trigger>,
|
|
68
|
+
VariantProps<typeof selectTriggerVariants> {}
|
|
69
|
+
|
|
70
|
+
function SelectTrigger({
|
|
71
|
+
className,
|
|
72
|
+
size,
|
|
73
|
+
children,
|
|
74
|
+
disabled,
|
|
75
|
+
state,
|
|
76
|
+
...props
|
|
77
|
+
}: SelectTriggerProps) {
|
|
78
|
+
return (
|
|
79
|
+
<SelectPrimitive.Trigger
|
|
80
|
+
data-slot="select-trigger"
|
|
81
|
+
data-size={size}
|
|
82
|
+
className={cn(
|
|
83
|
+
selectTriggerVariants({ size, className, state: disabled ? "disabled" : state }),
|
|
84
|
+
)}
|
|
85
|
+
disabled={disabled}
|
|
86
|
+
{...props}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
<SelectPrimitive.Icon asChild>
|
|
90
|
+
<ChevronDownIcon className="opacity-50" />
|
|
91
|
+
</SelectPrimitive.Icon>
|
|
92
|
+
</SelectPrimitive.Trigger>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function SelectContent({
|
|
97
|
+
className,
|
|
98
|
+
children,
|
|
99
|
+
position = "item-aligned",
|
|
100
|
+
...props
|
|
101
|
+
}: ComponentProps<typeof SelectPrimitive.Content>) {
|
|
102
|
+
return (
|
|
103
|
+
<SelectPrimitive.Portal>
|
|
104
|
+
<SelectPrimitive.Content
|
|
105
|
+
data-slot="select-content"
|
|
106
|
+
className={cn(
|
|
107
|
+
[
|
|
108
|
+
"bg-bg-primary",
|
|
109
|
+
"data-[state=open]:animate-in",
|
|
110
|
+
"data-[state=closed]:animate-out",
|
|
111
|
+
"data-[state=closed]:fade-out-0",
|
|
112
|
+
"data-[state=open]:fade-in-0",
|
|
113
|
+
"data-[state=closed]:zoom-out-95",
|
|
114
|
+
"data-[state=open]:zoom-in-95",
|
|
115
|
+
"data-[side=bottom]:slide-in-from-top-2",
|
|
116
|
+
"data-[side=left]:slide-in-from-right-2",
|
|
117
|
+
"data-[side=right]:slide-in-from-left-2",
|
|
118
|
+
"data-[side=top]:slide-in-from-bottom-2",
|
|
119
|
+
"relative",
|
|
120
|
+
"z-50",
|
|
121
|
+
"max-h-(--radix-select-content-available-height)",
|
|
122
|
+
"min-w-[8rem]",
|
|
123
|
+
"origin-(--radix-select-content-transform-origin)",
|
|
124
|
+
"overflow-x-hidden",
|
|
125
|
+
"overflow-y-auto",
|
|
126
|
+
"rounded-uk-md",
|
|
127
|
+
"shadow-md",
|
|
128
|
+
"shadow-[0_8px_20px_0_rgba(0,0,0,.80)]",
|
|
129
|
+
"liquid:liquid-bg",
|
|
130
|
+
],
|
|
131
|
+
{
|
|
132
|
+
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1":
|
|
133
|
+
position === "popper",
|
|
134
|
+
},
|
|
135
|
+
className,
|
|
136
|
+
)}
|
|
137
|
+
position={position}
|
|
138
|
+
{...props}
|
|
139
|
+
>
|
|
140
|
+
<SelectScrollUpButton />
|
|
141
|
+
<SelectPrimitive.Viewport
|
|
142
|
+
className={cn("p-md", {
|
|
143
|
+
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1":
|
|
144
|
+
position === "popper",
|
|
145
|
+
})}
|
|
146
|
+
>
|
|
147
|
+
{children}
|
|
148
|
+
</SelectPrimitive.Viewport>
|
|
149
|
+
<SelectScrollDownButton />
|
|
150
|
+
</SelectPrimitive.Content>
|
|
151
|
+
</SelectPrimitive.Portal>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function SelectLabel({ className, ...props }: ComponentProps<typeof SelectPrimitive.Label>) {
|
|
156
|
+
return (
|
|
157
|
+
<SelectPrimitive.Label
|
|
158
|
+
data-slot="select-label"
|
|
159
|
+
className={cn("text-text-secondary text-uk-xs px-2 py-1.5", className)}
|
|
160
|
+
{...props}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface SelectItemProps extends Omit<ComponentProps<typeof SelectPrimitive.Item>, "prefix"> {
|
|
166
|
+
prefix?: ReactNode;
|
|
167
|
+
suffix?: ReactNode;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function SelectItem({ className, children, prefix, suffix, disabled, ...props }: SelectItemProps) {
|
|
171
|
+
return (
|
|
172
|
+
<SelectPrimitive.Item
|
|
173
|
+
data-slot="select-item"
|
|
174
|
+
disabled={disabled}
|
|
175
|
+
className={cn(
|
|
176
|
+
[
|
|
177
|
+
"group/select-item",
|
|
178
|
+
"w-full",
|
|
179
|
+
"flex",
|
|
180
|
+
"gap-md",
|
|
181
|
+
"items-center",
|
|
182
|
+
"px-md",
|
|
183
|
+
"py-xs",
|
|
184
|
+
"relative",
|
|
185
|
+
"cursor-default",
|
|
186
|
+
"rounded-uk-xs",
|
|
187
|
+
"text-uk-xs",
|
|
188
|
+
"outline-hidden",
|
|
189
|
+
"select-none",
|
|
190
|
+
"focus:bg-bg-secondary",
|
|
191
|
+
"data-[state=checked]:bg-brand-primary",
|
|
192
|
+
"data-[disabled]:pointer-events-none",
|
|
193
|
+
"data-[disabled]:text-bg-quaternary",
|
|
194
|
+
"[&_svg]:pointer-events-none",
|
|
195
|
+
"[&_svg]:shrink-0",
|
|
196
|
+
"[&_svg:not([class*='size-'])]:size-4",
|
|
197
|
+
"[&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
198
|
+
"*:[span]:last:flex",
|
|
199
|
+
"*:[span]:last:items-center",
|
|
200
|
+
"*:[span]:last:gap-2",
|
|
201
|
+
],
|
|
202
|
+
className,
|
|
203
|
+
)}
|
|
204
|
+
{...props}
|
|
205
|
+
>
|
|
206
|
+
<p
|
|
207
|
+
data-disabled={disabled}
|
|
208
|
+
className={cn([
|
|
209
|
+
"text-text-tertiary",
|
|
210
|
+
"flex",
|
|
211
|
+
"shrink-0",
|
|
212
|
+
"gap-0.5",
|
|
213
|
+
"data-[disabled=true]:text-bg-quaternary",
|
|
214
|
+
"group-data-[state=checked]/select-item:text-text-withbg",
|
|
215
|
+
])}
|
|
216
|
+
>
|
|
217
|
+
{prefix}
|
|
218
|
+
</p>
|
|
219
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
220
|
+
<p
|
|
221
|
+
data-disabled={disabled}
|
|
222
|
+
className={cn(
|
|
223
|
+
"text-text-tertiary",
|
|
224
|
+
"ml-auto",
|
|
225
|
+
"flex",
|
|
226
|
+
"shrink-0",
|
|
227
|
+
"gap-0.5",
|
|
228
|
+
"data-[disabled=true]:text-bg-quaternary",
|
|
229
|
+
"group-data-[state=checked]/select-item:text-text-withbg",
|
|
230
|
+
)}
|
|
231
|
+
>
|
|
232
|
+
{suffix}
|
|
233
|
+
</p>
|
|
234
|
+
</SelectPrimitive.Item>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function SelectSeparator({
|
|
239
|
+
className,
|
|
240
|
+
...props
|
|
241
|
+
}: ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
242
|
+
return (
|
|
243
|
+
<SelectPrimitive.Separator
|
|
244
|
+
data-slot="select-separator"
|
|
245
|
+
className={cn("bg-line-primary my-lg pointer-events-none -mx-1 h-px", className)}
|
|
246
|
+
{...props}
|
|
247
|
+
/>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function SelectScrollUpButton({
|
|
252
|
+
className,
|
|
253
|
+
...props
|
|
254
|
+
}: ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
255
|
+
return (
|
|
256
|
+
<SelectPrimitive.ScrollUpButton
|
|
257
|
+
data-slot="select-scroll-up-button"
|
|
258
|
+
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
|
259
|
+
{...props}
|
|
260
|
+
>
|
|
261
|
+
<ChevronUpIcon className="size-4" />
|
|
262
|
+
</SelectPrimitive.ScrollUpButton>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function SelectScrollDownButton({
|
|
267
|
+
className,
|
|
268
|
+
...props
|
|
269
|
+
}: ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
270
|
+
return (
|
|
271
|
+
<SelectPrimitive.ScrollDownButton
|
|
272
|
+
data-slot="select-scroll-down-button"
|
|
273
|
+
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
|
274
|
+
{...props}
|
|
275
|
+
>
|
|
276
|
+
<ChevronDownIcon className="size-4" />
|
|
277
|
+
</SelectPrimitive.ScrollDownButton>
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export {
|
|
282
|
+
Select,
|
|
283
|
+
SelectContent,
|
|
284
|
+
SelectGroup,
|
|
285
|
+
SelectItem,
|
|
286
|
+
SelectLabel,
|
|
287
|
+
SelectScrollDownButton,
|
|
288
|
+
SelectScrollUpButton,
|
|
289
|
+
SelectSeparator,
|
|
290
|
+
SelectTrigger,
|
|
291
|
+
SelectValue,
|
|
292
|
+
};
|
package/src/ui/sheet.tsx
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
2
|
+
import { XIcon } from "lucide-react";
|
|
3
|
+
import { ComponentProps } from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../utils/cn";
|
|
6
|
+
|
|
7
|
+
function Sheet({ ...props }: ComponentProps<typeof SheetPrimitive.Root>) {
|
|
8
|
+
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function SheetTrigger({ ...props }: ComponentProps<typeof SheetPrimitive.Trigger>) {
|
|
12
|
+
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function SheetClose({ ...props }: ComponentProps<typeof SheetPrimitive.Close>) {
|
|
16
|
+
return (
|
|
17
|
+
<SheetPrimitive.Close
|
|
18
|
+
data-slot="sheet-close"
|
|
19
|
+
className={cn("focus:ring-0 focus:outline-none")}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function SheetPortal({ ...props }: ComponentProps<typeof SheetPrimitive.Portal>) {
|
|
26
|
+
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function SheetOverlay({ className, ...props }: ComponentProps<typeof SheetPrimitive.Overlay>) {
|
|
30
|
+
return (
|
|
31
|
+
<SheetPrimitive.Overlay
|
|
32
|
+
data-slot="sheet-overlay"
|
|
33
|
+
className={cn(
|
|
34
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-bg-primary/50 fixed inset-0 z-50",
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function SheetContent({
|
|
43
|
+
className,
|
|
44
|
+
children,
|
|
45
|
+
side = "right",
|
|
46
|
+
...props
|
|
47
|
+
}: ComponentProps<typeof SheetPrimitive.Content> & {
|
|
48
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
49
|
+
}) {
|
|
50
|
+
return (
|
|
51
|
+
<SheetPortal>
|
|
52
|
+
<SheetOverlay />
|
|
53
|
+
<SheetPrimitive.Content
|
|
54
|
+
data-slot="sheet-content"
|
|
55
|
+
className={cn(
|
|
56
|
+
"liquid:liquid-bg bg-bg-primary data-[state=open]:animate-in data-[state=closed]:animate-out p-xl fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
57
|
+
side === "right" &&
|
|
58
|
+
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-[340px]",
|
|
59
|
+
side === "left" &&
|
|
60
|
+
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-[340px]",
|
|
61
|
+
side === "top" &&
|
|
62
|
+
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto",
|
|
63
|
+
side === "bottom" &&
|
|
64
|
+
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto",
|
|
65
|
+
className,
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
<SheetPrimitive.Close className="text-icon-primary hover:text-icon-highlight absolute top-4 right-4 disabled:pointer-events-none">
|
|
71
|
+
<XIcon className="size-4" />
|
|
72
|
+
<span className="sr-only">Close</span>
|
|
73
|
+
</SheetPrimitive.Close>
|
|
74
|
+
</SheetPrimitive.Content>
|
|
75
|
+
</SheetPortal>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function SheetHeader({ className, ...props }: ComponentProps<"div">) {
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
data-slot="sheet-header"
|
|
83
|
+
className={cn("gap-md pb-xl flex flex-col", className)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function SheetFooter({ className, ...props }: ComponentProps<"div">) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="sheet-footer"
|
|
93
|
+
className={cn("gap-lg pt-xl mt-auto flex flex-col", className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function SheetTitle({ className, ...props }: ComponentProps<typeof SheetPrimitive.Title>) {
|
|
100
|
+
return (
|
|
101
|
+
<SheetPrimitive.Title
|
|
102
|
+
data-slot="sheet-title"
|
|
103
|
+
className={cn("text-text-highlight text-uk-xl leading-uk-xl font-medium", className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function SheetDescription({
|
|
110
|
+
className,
|
|
111
|
+
...props
|
|
112
|
+
}: ComponentProps<typeof SheetPrimitive.Description>) {
|
|
113
|
+
return (
|
|
114
|
+
<SheetPrimitive.Description
|
|
115
|
+
data-slot="sheet-description"
|
|
116
|
+
className={cn("text-text-secondary text-uk-md leading-uk-md", className)}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
Sheet,
|
|
124
|
+
SheetTrigger,
|
|
125
|
+
SheetClose,
|
|
126
|
+
SheetContent,
|
|
127
|
+
SheetHeader,
|
|
128
|
+
SheetFooter,
|
|
129
|
+
SheetTitle,
|
|
130
|
+
SheetDescription,
|
|
131
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
2
|
+
import { ComponentProps, ComponentRef, forwardRef, useMemo, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../utils";
|
|
5
|
+
|
|
6
|
+
interface SliderProps extends ComponentProps<typeof SliderPrimitive.Root> {
|
|
7
|
+
showStep?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Slider = forwardRef<ComponentRef<typeof SliderPrimitive.Root>, SliderProps>(function Slider(
|
|
11
|
+
{
|
|
12
|
+
className,
|
|
13
|
+
defaultValue,
|
|
14
|
+
value,
|
|
15
|
+
onValueChange,
|
|
16
|
+
showStep = false,
|
|
17
|
+
step = 1,
|
|
18
|
+
min = 0,
|
|
19
|
+
max = 100,
|
|
20
|
+
...props
|
|
21
|
+
},
|
|
22
|
+
ref,
|
|
23
|
+
) {
|
|
24
|
+
const [currentValue, setCurrentValue] = useState<number[]>(value ?? defaultValue ?? [0]);
|
|
25
|
+
|
|
26
|
+
const _values = useMemo(
|
|
27
|
+
() => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]),
|
|
28
|
+
[value, defaultValue, min, max],
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<SliderPrimitive.Root
|
|
33
|
+
data-slot="slider"
|
|
34
|
+
value={value}
|
|
35
|
+
defaultValue={defaultValue}
|
|
36
|
+
onValueChange={(v) => {
|
|
37
|
+
onValueChange?.(v);
|
|
38
|
+
setCurrentValue(v);
|
|
39
|
+
}}
|
|
40
|
+
ref={ref}
|
|
41
|
+
min={min}
|
|
42
|
+
max={max}
|
|
43
|
+
step={step}
|
|
44
|
+
className={cn(
|
|
45
|
+
"relative",
|
|
46
|
+
"flex",
|
|
47
|
+
"w-full",
|
|
48
|
+
"touch-none",
|
|
49
|
+
"select-none",
|
|
50
|
+
"items-center",
|
|
51
|
+
"data-[orientation=vertical]:h-full",
|
|
52
|
+
"data-[orientation=vertical]:min-h-44",
|
|
53
|
+
"data-[orientation=vertical]:w-auto",
|
|
54
|
+
"data-[orientation=vertical]:flex-col",
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
>
|
|
59
|
+
<SliderPrimitive.Track
|
|
60
|
+
data-slot="slider-track"
|
|
61
|
+
className={cn(
|
|
62
|
+
"peer/slider-track",
|
|
63
|
+
"bg-line-primary",
|
|
64
|
+
"relative",
|
|
65
|
+
"grow",
|
|
66
|
+
"overflow-hidden",
|
|
67
|
+
"rounded-full",
|
|
68
|
+
"data-[disabled]:bg-bg-secondary",
|
|
69
|
+
"data-[orientation=vertical]:w-0.5",
|
|
70
|
+
"data-[orientation=vertical]:h-full",
|
|
71
|
+
"data-[orientation=horizontal]:h-0.5",
|
|
72
|
+
"data-[orientation=horizontal]:w-full",
|
|
73
|
+
)}
|
|
74
|
+
>
|
|
75
|
+
<SliderPrimitive.Range
|
|
76
|
+
data-slot="slider-range"
|
|
77
|
+
className={cn(
|
|
78
|
+
"bg-brand-primary",
|
|
79
|
+
"absolute",
|
|
80
|
+
"data-[disabled]:bg-bg-secondary",
|
|
81
|
+
"data-[orientation=vertical]:w-full",
|
|
82
|
+
"data-[orientation=horizontal]:h-full",
|
|
83
|
+
)}
|
|
84
|
+
/>
|
|
85
|
+
</SliderPrimitive.Track>
|
|
86
|
+
|
|
87
|
+
{showStep && <SliderSteps currentValue={currentValue} max={max} min={min} step={step} />}
|
|
88
|
+
|
|
89
|
+
{Array.from({ length: _values.length }, (_, index) => (
|
|
90
|
+
<SliderPrimitive.Thumb
|
|
91
|
+
data-slot="slider-thumb"
|
|
92
|
+
key={index}
|
|
93
|
+
className={cn(
|
|
94
|
+
"ring-brand-primary/50",
|
|
95
|
+
"bg-brand-primary",
|
|
96
|
+
"block",
|
|
97
|
+
"h-4",
|
|
98
|
+
"w-[0.6rem]",
|
|
99
|
+
"shrink-0",
|
|
100
|
+
"rounded-[3px]",
|
|
101
|
+
"transition-[color,box-shadow]",
|
|
102
|
+
"hover:ring-4",
|
|
103
|
+
"hover:cursor-ew-resize",
|
|
104
|
+
"focus-visible:ring-4",
|
|
105
|
+
"focus-visible:outline-hidden",
|
|
106
|
+
"data-[disabled]:bg-bg-tertiary",
|
|
107
|
+
"data-[disabled]:pointer-events-none",
|
|
108
|
+
)}
|
|
109
|
+
/>
|
|
110
|
+
))}
|
|
111
|
+
</SliderPrimitive.Root>
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
interface SliderStepsProps {
|
|
116
|
+
min: number;
|
|
117
|
+
max: number;
|
|
118
|
+
step: number;
|
|
119
|
+
currentValue: number[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function SliderSteps({ step, min, max, currentValue }: SliderStepsProps) {
|
|
123
|
+
const steps = useMemo(() => {
|
|
124
|
+
const value = max - min;
|
|
125
|
+
const stepCount = Math.ceil(value / step);
|
|
126
|
+
return Array.from({ length: stepCount + 1 }, (_, i) => {
|
|
127
|
+
return { position: Math.min((100 / value) * (i * step), 100), v: i * step + min };
|
|
128
|
+
});
|
|
129
|
+
}, [max, min, step]);
|
|
130
|
+
|
|
131
|
+
const [minRange, maxRange] = useMemo(() => {
|
|
132
|
+
if (currentValue.length > 1) {
|
|
133
|
+
return [Math.min(...currentValue), Math.max(...currentValue)];
|
|
134
|
+
} else {
|
|
135
|
+
return [0, ...currentValue];
|
|
136
|
+
}
|
|
137
|
+
}, [currentValue]);
|
|
138
|
+
|
|
139
|
+
return steps.map((step, i) => {
|
|
140
|
+
/*
|
|
141
|
+
* 9.6 is the width of the thumb in pixels
|
|
142
|
+
* 1 is the direction of the thumb (1 for right, -1 for left)
|
|
143
|
+
* */
|
|
144
|
+
const thumbInBoundsOffset = getThumbInBoundsOffset(9.6, step.position, 1);
|
|
145
|
+
return (
|
|
146
|
+
<span
|
|
147
|
+
key={i}
|
|
148
|
+
data-slot="slider-step"
|
|
149
|
+
style={{ left: `calc(${step.position}% + ${thumbInBoundsOffset}px)` }}
|
|
150
|
+
className={cn(
|
|
151
|
+
"absolute",
|
|
152
|
+
"top-1/2",
|
|
153
|
+
"translate-y-[-50%]",
|
|
154
|
+
"translate-x-[-50%]",
|
|
155
|
+
"bg-brand-primary",
|
|
156
|
+
"block",
|
|
157
|
+
"h-[5pt]",
|
|
158
|
+
"w-[1pt]",
|
|
159
|
+
"shrink-0",
|
|
160
|
+
"rounded-[1px]",
|
|
161
|
+
"peer-has-data-[disabled]/slider-track:bg-bg-tertiary",
|
|
162
|
+
{ "bg-bg-tertiary": step.v < minRange || step.v > maxRange },
|
|
163
|
+
)}
|
|
164
|
+
/>
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Offsets the thumb centre point while sliding to ensure it remains
|
|
171
|
+
* within the bounds of the slider when reaching the edges
|
|
172
|
+
*/
|
|
173
|
+
function getThumbInBoundsOffset(width: number, left: number, direction: number) {
|
|
174
|
+
const halfWidth = width / 2;
|
|
175
|
+
const halfPercent = 50;
|
|
176
|
+
const offset = linearScale([0, halfPercent], [0, halfWidth]);
|
|
177
|
+
return (halfWidth - offset(left) * direction) * direction;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function linearScale(input: [number, number], output: [number, number]) {
|
|
181
|
+
return (value: number) => {
|
|
182
|
+
if (input[0] === input[1] || output[0] === output[1]) return output[0];
|
|
183
|
+
const ratio = (output[1] - output[0]) / (input[1] - input[0]);
|
|
184
|
+
return output[0] + ratio * (value - input[0]);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { Slider };
|
|
189
|
+
export type { SliderProps };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
|
2
|
+
import { type ComponentProps } from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../utils";
|
|
5
|
+
|
|
6
|
+
function Switch({ className, ...props }: ComponentProps<typeof SwitchPrimitive.Root>) {
|
|
7
|
+
return (
|
|
8
|
+
<SwitchPrimitive.Root
|
|
9
|
+
data-slot="switch"
|
|
10
|
+
className={cn(
|
|
11
|
+
"group",
|
|
12
|
+
"w-[32px]",
|
|
13
|
+
"h-[16px]",
|
|
14
|
+
"rounded-[24px]",
|
|
15
|
+
"bg-bg-tertiary",
|
|
16
|
+
"data-[state=checked]:bg-brand-primary",
|
|
17
|
+
"disabled:bg-bg-secondary",
|
|
18
|
+
"disabled:cursor-not-allowed",
|
|
19
|
+
"disabled:data-[state=checked]:bg-bg-secondary",
|
|
20
|
+
"disabled:data-[state=unchecked]:bg-bg-secondary",
|
|
21
|
+
className,
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<SwitchPrimitive.Thumb
|
|
26
|
+
data-slot="switch-thumb"
|
|
27
|
+
className={cn(
|
|
28
|
+
"block",
|
|
29
|
+
"size-[12px]",
|
|
30
|
+
"rounded-full",
|
|
31
|
+
"bg-icon-withbg",
|
|
32
|
+
"group-disabled:bg-bg-primary",
|
|
33
|
+
"transition-transform",
|
|
34
|
+
"duration-200",
|
|
35
|
+
"translate-x-[2px]",
|
|
36
|
+
"data-[state=checked]:translate-x-[18px]",
|
|
37
|
+
)}
|
|
38
|
+
/>
|
|
39
|
+
</SwitchPrimitive.Root>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { Switch };
|