54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
import * as React from "react";
|
|
import { cn } from "@/lib/utils";
|
|
import { Slider as SliderPrimitive } from "radix-ui";
|
|
|
|
function Slider({
|
|
className,
|
|
defaultValue,
|
|
value,
|
|
min = 0,
|
|
max = 100,
|
|
...props
|
|
}: React.ComponentProps<typeof SliderPrimitive.Root>) {
|
|
const thumbs = React.useMemo(
|
|
() => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]),
|
|
[value, defaultValue, min, max],
|
|
);
|
|
// radix 的可访问 slider 角色在 Thumb 上,aria-label 提到 Root 传不进去——改下沉到每个 Thumb。
|
|
const { "aria-label": ariaLabel, ...rootProps } = props;
|
|
return (
|
|
<SliderPrimitive.Root
|
|
data-slot="slider"
|
|
defaultValue={defaultValue}
|
|
value={value}
|
|
min={min}
|
|
max={max}
|
|
className={cn(
|
|
"relative flex w-full touch-none select-none items-center data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
className,
|
|
)}
|
|
{...rootProps}
|
|
>
|
|
<SliderPrimitive.Track
|
|
data-slot="slider-track"
|
|
className="relative w-full grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
|
|
>
|
|
<SliderPrimitive.Range
|
|
data-slot="slider-range"
|
|
className="absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=horizontal]:top-0 data-[orientation=vertical]:w-full"
|
|
/>
|
|
</SliderPrimitive.Track>
|
|
{thumbs.map((_, i) => (
|
|
<SliderPrimitive.Thumb
|
|
key={i}
|
|
data-slot="slider-thumb"
|
|
aria-label={Array.isArray(ariaLabel) ? ariaLabel[i] : ariaLabel}
|
|
className="block size-4 shrink-0 rounded-full border border-primary/50 bg-background shadow transition-[color,box-shadow] hover:ring-4 hover:ring-ring/30 focus-visible:ring-4 focus-visible:ring-ring/50 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
|
|
/>
|
|
))}
|
|
</SliderPrimitive.Root>
|
|
);
|
|
}
|
|
|
|
export { Slider };
|