@quarklab/rad-ui 0.3.0 → 0.3.2

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.
@@ -1,209 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { cva, type VariantProps } from "class-variance-authority";
5
-
6
- import { cn } from "../lib/utils";
7
- import { Button } from "./button";
8
- import { Input } from "./input";
9
- import { Textarea } from "./textarea";
10
-
11
- // ---------------------------------------------------------------------------
12
- // InputGroup
13
- // ---------------------------------------------------------------------------
14
-
15
- const InputGroup = React.forwardRef<
16
- HTMLDivElement,
17
- React.HTMLAttributes<HTMLDivElement>
18
- >(({ className, ...props }, ref) => (
19
- <div
20
- ref={ref}
21
- data-slot="input-group"
22
- className={cn(
23
- "group/input-group flex min-w-0 items-stretch rounded-md border border-input shadow-sm",
24
- "focus-within:ring-1 focus-within:ring-ring",
25
- "data-[disabled=true]:opacity-50",
26
- className
27
- )}
28
- {...props}
29
- />
30
- ));
31
- InputGroup.displayName = "InputGroup";
32
-
33
- // ---------------------------------------------------------------------------
34
- // InputGroupAddon
35
- // ---------------------------------------------------------------------------
36
-
37
- const inputGroupAddonVariants = cva(
38
- "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 group-data-[disabled=true]/input-group:opacity-50",
39
- {
40
- variants: {
41
- align: {
42
- "inline-start":
43
- "order-first ps-3 has-[>button]:ms-[-0.45rem] has-[>kbd]:ms-[-0.35rem]",
44
- "inline-end":
45
- "order-last pe-3 has-[>button]:me-[-0.45rem] has-[>kbd]:me-[-0.35rem]",
46
- "block-start":
47
- "order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5",
48
- "block-end":
49
- "order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5",
50
- },
51
- },
52
- defaultVariants: {
53
- align: "inline-start",
54
- },
55
- }
56
- );
57
-
58
- export interface InputGroupAddonProps
59
- extends
60
- React.HTMLAttributes<HTMLDivElement>,
61
- VariantProps<typeof inputGroupAddonVariants> {}
62
-
63
- const InputGroupAddon = React.forwardRef<HTMLDivElement, InputGroupAddonProps>(
64
- ({ className, align = "inline-start", ...props }, ref) => (
65
- <div
66
- ref={ref}
67
- data-slot="input-group-addon"
68
- data-align={align}
69
- className={cn(inputGroupAddonVariants({ align }), className)}
70
- onClick={(e) => {
71
- if ((e.target as HTMLElement).closest("button")) {
72
- return;
73
- }
74
- e.currentTarget.parentElement
75
- ?.querySelector<
76
- HTMLInputElement | HTMLTextAreaElement
77
- >("input, textarea")
78
- ?.focus();
79
- }}
80
- {...props}
81
- />
82
- )
83
- );
84
- InputGroupAddon.displayName = "InputGroupAddon";
85
-
86
- // ---------------------------------------------------------------------------
87
- // InputGroupButton
88
- // ---------------------------------------------------------------------------
89
-
90
- const inputGroupButtonVariants = cva(
91
- "text-sm shadow-none flex gap-2 items-center",
92
- {
93
- variants: {
94
- size: {
95
- xs: "h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2",
96
- sm: "h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5",
97
- "icon-xs":
98
- "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
99
- "icon-sm": "size-8 p-0 has-[>svg]:p-0",
100
- },
101
- },
102
- defaultVariants: {
103
- size: "xs",
104
- },
105
- }
106
- );
107
-
108
- export interface InputGroupButtonProps
109
- extends
110
- Omit<React.ComponentPropsWithRef<typeof Button>, "size">,
111
- VariantProps<typeof inputGroupButtonVariants> {}
112
-
113
- const InputGroupButton = React.forwardRef<
114
- HTMLButtonElement,
115
- InputGroupButtonProps
116
- >(
117
- (
118
- { className, type = "button", variant = "ghost", size = "xs", ...props },
119
- ref
120
- ) => (
121
- <Button
122
- ref={ref}
123
- type={type}
124
- variant={variant}
125
- className={cn(inputGroupButtonVariants({ size }), className)}
126
- {...props}
127
- />
128
- )
129
- );
130
- InputGroupButton.displayName = "InputGroupButton";
131
-
132
- // ---------------------------------------------------------------------------
133
- // InputGroupText
134
- // ---------------------------------------------------------------------------
135
-
136
- const InputGroupText = React.forwardRef<
137
- HTMLSpanElement,
138
- React.HTMLAttributes<HTMLSpanElement>
139
- >(({ className, ...props }, ref) => (
140
- <span
141
- ref={ref}
142
- data-slot="input-group-text"
143
- className={cn("text-muted-foreground text-sm", className)}
144
- {...props}
145
- />
146
- ));
147
- InputGroupText.displayName = "InputGroupText";
148
-
149
- // ---------------------------------------------------------------------------
150
- // InputGroupInput
151
- // ---------------------------------------------------------------------------
152
-
153
- type InputGroupInputProps = Omit<
154
- React.ComponentPropsWithRef<typeof Input>,
155
- "ref"
156
- >;
157
-
158
- const InputGroupInput = React.forwardRef<
159
- HTMLInputElement,
160
- InputGroupInputProps
161
- >(({ className, ...props }, ref) => (
162
- <Input
163
- ref={ref}
164
- data-slot="input-group-control"
165
- className={cn(
166
- "border-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 rounded-none",
167
- "group-has-[[data-align=inline-start]]/input-group:rounded-e-md",
168
- "group-has-[[data-align=inline-end]]/input-group:rounded-s-md",
169
- className
170
- )}
171
- {...props}
172
- />
173
- ));
174
- InputGroupInput.displayName = "InputGroupInput";
175
-
176
- // ---------------------------------------------------------------------------
177
- // InputGroupTextarea
178
- // ---------------------------------------------------------------------------
179
-
180
- const InputGroupTextarea = React.forwardRef<
181
- HTMLTextAreaElement,
182
- React.TextareaHTMLAttributes<HTMLTextAreaElement>
183
- >(({ className, ...props }, ref) => (
184
- <Textarea
185
- ref={ref}
186
- data-slot="input-group-control"
187
- className={cn(
188
- "border-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 rounded-none min-h-0",
189
- className
190
- )}
191
- {...props}
192
- />
193
- ));
194
- InputGroupTextarea.displayName = "InputGroupTextarea";
195
-
196
- // ---------------------------------------------------------------------------
197
- // Exports
198
- // ---------------------------------------------------------------------------
199
-
200
- export {
201
- InputGroup,
202
- InputGroupAddon,
203
- inputGroupAddonVariants,
204
- InputGroupButton,
205
- inputGroupButtonVariants,
206
- InputGroupText,
207
- InputGroupInput,
208
- InputGroupTextarea,
209
- };
@@ -1,85 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { OTPInput, OTPInputContext } from "input-otp";
5
- import { MinusIcon } from "lucide-react";
6
-
7
- import { cn } from "../lib/utils";
8
-
9
- const PERSIAN_DIGITS = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"];
10
-
11
- function toPersianDigit(
12
- str: string | null | undefined
13
- ): string | null | undefined {
14
- if (!str) return str;
15
- return str.replace(/\d/g, (d) => PERSIAN_DIGITS[parseInt(d)] ?? d);
16
- }
17
-
18
- const InputOTP = React.forwardRef<
19
- React.ElementRef<typeof OTPInput>,
20
- React.ComponentPropsWithoutRef<typeof OTPInput> & {
21
- containerClassName?: string;
22
- }
23
- >(({ className, containerClassName, ...props }, ref) => (
24
- <div dir="ltr">
25
- <OTPInput
26
- ref={ref}
27
- containerClassName={cn(
28
- "flex items-center gap-2 has-[:disabled]:opacity-50",
29
- containerClassName
30
- )}
31
- className={cn("disabled:cursor-not-allowed", className)}
32
- {...props}
33
- />
34
- </div>
35
- ));
36
- InputOTP.displayName = "InputOTP";
37
-
38
- const InputOTPGroup = React.forwardRef<
39
- React.ElementRef<"div">,
40
- React.ComponentPropsWithoutRef<"div">
41
- >(({ className, ...props }, ref) => (
42
- <div ref={ref} className={cn("flex items-center", className)} {...props} />
43
- ));
44
- InputOTPGroup.displayName = "InputOTPGroup";
45
-
46
- const InputOTPSlot = React.forwardRef<
47
- React.ElementRef<"div">,
48
- React.ComponentPropsWithoutRef<"div"> & { index: number }
49
- >(({ index, className, ...props }, ref) => {
50
- const inputOTPContext = React.useContext(OTPInputContext);
51
- const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
52
-
53
- return (
54
- <div
55
- ref={ref}
56
- className={cn(
57
- "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all",
58
- "first:rounded-l-md first:border-l last:rounded-r-md",
59
- isActive && "z-10 ring-2 ring-ring",
60
- className
61
- )}
62
- {...props}
63
- >
64
- {toPersianDigit(char)}
65
- {hasFakeCaret && (
66
- <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
67
- <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
68
- </div>
69
- )}
70
- </div>
71
- );
72
- });
73
- InputOTPSlot.displayName = "InputOTPSlot";
74
-
75
- const InputOTPSeparator = React.forwardRef<
76
- React.ElementRef<"div">,
77
- React.ComponentPropsWithoutRef<"div">
78
- >(({ ...props }, ref) => (
79
- <div ref={ref} role="separator" {...props}>
80
- <MinusIcon className="h-4 w-4" />
81
- </div>
82
- ));
83
- InputOTPSeparator.displayName = "InputOTPSeparator";
84
-
85
- export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -1,103 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { Upload } from "lucide-react";
4
- import { cn } from "../lib/utils";
5
-
6
- const inputVariants = cva(
7
- "flex w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
8
- {
9
- variants: {
10
- size: {
11
- sm: "h-9 px-3 text-sm",
12
- md: "h-10 px-3 py-2 text-sm",
13
- lg: "h-11 px-4 text-base",
14
- },
15
- },
16
- defaultVariants: {
17
- size: "md",
18
- },
19
- }
20
- );
21
-
22
- export interface InputProps
23
- extends
24
- Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">,
25
- VariantProps<typeof inputVariants> {}
26
-
27
- const Input = React.forwardRef<HTMLInputElement, InputProps>(
28
- ({ className, size, type, ...props }, ref) => {
29
- // Custom logic for file input to support Farsi text
30
- if (type === "file") {
31
- // eslint-disable-next-line react-hooks/rules-of-hooks
32
- const [fileName, setFileName] = React.useState<string>("");
33
- // eslint-disable-next-line react-hooks/rules-of-hooks
34
- const inputRef = React.useRef<HTMLInputElement>(null);
35
-
36
- // eslint-disable-next-line react-hooks/rules-of-hooks
37
- React.useImperativeHandle(ref, () => inputRef.current!);
38
-
39
- const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
40
- const file = e.target.files?.[0];
41
- if (file) {
42
- setFileName(file.name);
43
- } else {
44
- setFileName("");
45
- }
46
- props.onChange?.(e);
47
- };
48
-
49
- return (
50
- <div
51
- className={cn(
52
- inputVariants({ size, className }),
53
- "flex items-center gap-2 cursor-pointer",
54
- props.disabled && "cursor-not-allowed opacity-50"
55
- )}
56
- onClick={() => !props.disabled && inputRef.current?.click()}
57
- >
58
- <button
59
- type="button"
60
- disabled={props.disabled}
61
- className={cn(
62
- "flex items-center gap-2 rounded-sm bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground transition-colors",
63
- "hover:bg-secondary/80 focus:outline-none",
64
- props.disabled && "pointer-events-none"
65
- )}
66
- tabIndex={-1}
67
- >
68
- <Upload className="h-3 w-3" />
69
- <span>انتخاب فایل</span>
70
- </button>
71
- <span
72
- className={cn(
73
- "text-muted-foreground truncate flex-1 text-right text-xs",
74
- !fileName && "opacity-70"
75
- )}
76
- dir="rtl"
77
- >
78
- {fileName || props.placeholder || "فایلی انتخاب نشده"}
79
- </span>
80
- <input
81
- type="file"
82
- className="hidden"
83
- ref={inputRef}
84
- onChange={handleFileChange}
85
- {...props}
86
- />
87
- </div>
88
- );
89
- }
90
-
91
- return (
92
- <input
93
- type={type}
94
- className={cn(inputVariants({ size, className }))}
95
- ref={ref}
96
- {...props}
97
- />
98
- );
99
- }
100
- );
101
- Input.displayName = "Input";
102
-
103
- export { Input, inputVariants };
@@ -1,37 +0,0 @@
1
- import * as React from "react";
2
- import { cn } from "../lib/utils";
3
-
4
- export interface KbdProps extends React.HTMLAttributes<HTMLElement> {}
5
-
6
- const Kbd = React.forwardRef<HTMLElement, KbdProps>(
7
- ({ className, ...props }, ref) => {
8
- return (
9
- <kbd
10
- ref={ref}
11
- className={cn(
12
- "pointer-events-none inline-flex h-6 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground shadow-sm",
13
- className
14
- )}
15
- {...props}
16
- />
17
- );
18
- }
19
- );
20
- Kbd.displayName = "Kbd";
21
-
22
- export interface KbdGroupProps extends React.HTMLAttributes<HTMLDivElement> {}
23
-
24
- const KbdGroup = React.forwardRef<HTMLDivElement, KbdGroupProps>(
25
- ({ className, ...props }, ref) => {
26
- return (
27
- <div
28
- ref={ref}
29
- className={cn("inline-flex items-center gap-1", className)}
30
- {...props}
31
- />
32
- );
33
- }
34
- );
35
- KbdGroup.displayName = "KbdGroup";
36
-
37
- export { Kbd, KbdGroup };
@@ -1,23 +0,0 @@
1
- import * as React from "react";
2
- import * as LabelPrimitive from "@radix-ui/react-label";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
- import { cn } from "../lib/utils";
5
-
6
- const labelVariants = cva(
7
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
8
- );
9
-
10
- const Label = React.forwardRef<
11
- React.ElementRef<typeof LabelPrimitive.Root>,
12
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
13
- VariantProps<typeof labelVariants>
14
- >(({ className, ...props }, ref) => (
15
- <LabelPrimitive.Root
16
- ref={ref}
17
- className={cn(labelVariants(), className)}
18
- {...props}
19
- />
20
- ));
21
- Label.displayName = LabelPrimitive.Root.displayName;
22
-
23
- export { Label };
@@ -1,7 +0,0 @@
1
- import { type ClassValue, clsx } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
7
-
@@ -1,71 +0,0 @@
1
- import * as React from "react";
2
- import { ChevronDown } from "lucide-react";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
- import { cn } from "../lib/utils";
5
-
6
- const nativeSelectVariants = cva(
7
- "flex w-full appearance-none rounded-md border border-input bg-background px-3 py-1 shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 pe-8",
8
- {
9
- variants: {
10
- size: {
11
- sm: "h-9 text-sm",
12
- md: "h-10 text-sm",
13
- lg: "h-11 text-base",
14
- },
15
- },
16
- defaultVariants: {
17
- size: "sm",
18
- },
19
- }
20
- );
21
-
22
- export interface NativeSelectProps
23
- extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "size">,
24
- VariantProps<typeof nativeSelectVariants> {}
25
-
26
- const NativeSelect = React.forwardRef<HTMLSelectElement, NativeSelectProps>(
27
- ({ className, children, size, ...props }, ref) => {
28
- return (
29
- <div className="relative">
30
- <select
31
- className={cn(nativeSelectVariants({ size, className }))}
32
- ref={ref}
33
- {...props}
34
- >
35
- {children}
36
- </select>
37
- <ChevronDown className="absolute end-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground pointer-events-none opacity-50" />
38
- </div>
39
- );
40
- }
41
- );
42
- NativeSelect.displayName = "NativeSelect";
43
-
44
- export interface NativeSelectOptionProps
45
- extends React.OptionHTMLAttributes<HTMLOptionElement> {}
46
-
47
- const NativeSelectOption = React.forwardRef<
48
- HTMLOptionElement,
49
- NativeSelectOptionProps
50
- >(({ className, ...props }, ref) => {
51
- return <option className={cn("", className)} ref={ref} {...props} />;
52
- });
53
- NativeSelectOption.displayName = "NativeSelectOption";
54
-
55
- export interface NativeSelectOptGroupProps
56
- extends React.OptgroupHTMLAttributes<HTMLOptGroupElement> {}
57
-
58
- const NativeSelectOptGroup = React.forwardRef<
59
- HTMLOptGroupElement,
60
- NativeSelectOptGroupProps
61
- >(({ className, ...props }, ref) => {
62
- return <optgroup className={cn("", className)} ref={ref} {...props} />;
63
- });
64
- NativeSelectOptGroup.displayName = "NativeSelectOptGroup";
65
-
66
- export {
67
- NativeSelect,
68
- NativeSelectOption,
69
- NativeSelectOptGroup,
70
- nativeSelectVariants,
71
- };
@@ -1,43 +0,0 @@
1
- import * as React from "react";
2
- import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
3
- import { Circle } from "lucide-react";
4
- import { cn } from "../lib/utils";
5
-
6
- const RadioGroup = React.forwardRef<
7
- React.ElementRef<typeof RadioGroupPrimitive.Root>,
8
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
9
- >(({ className, ...props }, ref) => {
10
- return (
11
- <RadioGroupPrimitive.Root
12
- className={cn("grid gap-2", className)}
13
- {...props}
14
- ref={ref}
15
- />
16
- );
17
- });
18
- RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
19
-
20
- const RadioGroupItem = React.forwardRef<
21
- React.ElementRef<typeof RadioGroupPrimitive.Item>,
22
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
23
- >(({ className, ...props }, ref) => {
24
- return (
25
- <RadioGroupPrimitive.Item
26
- ref={ref}
27
- className={cn(
28
- "aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow transition-colors",
29
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
30
- "disabled:cursor-not-allowed disabled:opacity-50",
31
- className
32
- )}
33
- {...props}
34
- >
35
- <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
36
- <Circle className="h-2.5 w-2.5 fill-current text-current" />
37
- </RadioGroupPrimitive.Indicator>
38
- </RadioGroupPrimitive.Item>
39
- );
40
- });
41
- RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
42
-
43
- export { RadioGroup, RadioGroupItem };
@@ -1,29 +0,0 @@
1
- import * as React from "react";
2
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
3
- import { cn } from "../lib/utils";
4
-
5
- const Separator = React.forwardRef<
6
- React.ElementRef<typeof SeparatorPrimitive.Root>,
7
- React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
8
- >(
9
- (
10
- { className, orientation = "horizontal", decorative = true, ...props },
11
- ref
12
- ) => (
13
- <SeparatorPrimitive.Root
14
- ref={ref}
15
- decorative={decorative}
16
- orientation={orientation}
17
- className={cn(
18
- "shrink-0 bg-border",
19
- orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
20
- className
21
- )}
22
- {...props}
23
- />
24
- )
25
- );
26
-
27
- Separator.displayName = SeparatorPrimitive.Root.displayName;
28
-
29
- export { Separator };
@@ -1,15 +0,0 @@
1
- import { cn } from "../lib/utils";
2
-
3
- function Skeleton({
4
- className,
5
- ...props
6
- }: React.HTMLAttributes<HTMLDivElement>) {
7
- return (
8
- <div
9
- className={cn("animate-pulse rounded-md bg-muted", className)}
10
- {...props}
11
- />
12
- );
13
- }
14
-
15
- export { Skeleton };
@@ -1,46 +0,0 @@
1
- import * as React from "react";
2
- import * as SliderPrimitive from "@radix-ui/react-slider";
3
- import { cn } from "../lib/utils";
4
-
5
- const Slider = React.forwardRef<
6
- React.ElementRef<typeof SliderPrimitive.Root>,
7
- React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
8
- >(({ className, value, defaultValue, ...props }, ref) => {
9
- // Determine the number of thumbs based on value or defaultValue
10
- const thumbCount = React.useMemo(() => {
11
- if (value && Array.isArray(value)) {
12
- return value.length;
13
- }
14
- if (defaultValue && Array.isArray(defaultValue)) {
15
- return defaultValue.length;
16
- }
17
- return 1; // Default to single thumb
18
- }, [value, defaultValue]);
19
-
20
- return (
21
- <SliderPrimitive.Root
22
- ref={ref}
23
- className={cn(
24
- "relative flex w-full touch-none select-none items-center",
25
- className
26
- )}
27
- value={value}
28
- defaultValue={defaultValue}
29
- {...props}
30
- >
31
- <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
32
- <SliderPrimitive.Range className="absolute h-full bg-primary" />
33
- </SliderPrimitive.Track>
34
- {Array.from({ length: thumbCount }).map((_, index) => (
35
- <SliderPrimitive.Thumb
36
- key={index}
37
- className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
38
- />
39
- ))}
40
- </SliderPrimitive.Root>
41
- );
42
- });
43
-
44
- Slider.displayName = SliderPrimitive.Root.displayName;
45
-
46
- export { Slider };