mirror of
https://github.com/cosscom/coss.git
synced 2026-09-14 20:06:50 +08:00
9302c06311
* update biome config + resolve issues * improve the ui:sync command to run organizeImports on packages * reformat * build registry * exclude base-ui stuff * fix useExportsLast * further improvements * silence errors * exclude examples app * update biome + reformat * format all the other files * include examples app * improve copyable-field * remove unwanted comment * remove a few unneeded biome comments * avoid nested ternary * refactored some shared components * upgrade base ui to 1.2.0 * fix
132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { Slider as SliderPrimitive } from "radix-ui";
|
|
import * as React from "react";
|
|
import { cn } from "@/registry/default/lib/utils";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from "@/registry/default/ui/tooltip";
|
|
|
|
function Slider({
|
|
className,
|
|
defaultValue,
|
|
value,
|
|
min = 0,
|
|
max = 100,
|
|
showTooltip = false,
|
|
tooltipContent,
|
|
...props
|
|
}: React.ComponentProps<typeof SliderPrimitive.Root> & {
|
|
showTooltip?: boolean;
|
|
tooltipContent?: (value: number) => React.ReactNode;
|
|
}) {
|
|
const [internalValues, setInternalValues] = React.useState<number[]>(
|
|
Array.isArray(value)
|
|
? value
|
|
: Array.isArray(defaultValue)
|
|
? defaultValue
|
|
: [min, max],
|
|
);
|
|
|
|
React.useEffect(() => {
|
|
if (value !== undefined) {
|
|
setInternalValues(Array.isArray(value) ? value : [value]);
|
|
}
|
|
}, [value]);
|
|
|
|
const handleValueChange = (newValue: number[]) => {
|
|
setInternalValues(newValue);
|
|
props.onValueChange?.(newValue);
|
|
};
|
|
|
|
const [showTooltipState, setShowTooltipState] = React.useState(false);
|
|
|
|
const handlePointerDown = () => {
|
|
if (showTooltip) {
|
|
setShowTooltipState(true);
|
|
}
|
|
};
|
|
|
|
const handlePointerUp = React.useCallback(() => {
|
|
if (showTooltip) {
|
|
setShowTooltipState(false);
|
|
}
|
|
}, [showTooltip]);
|
|
|
|
React.useEffect(() => {
|
|
if (showTooltip) {
|
|
document.addEventListener("pointerup", handlePointerUp);
|
|
return () => {
|
|
document.removeEventListener("pointerup", handlePointerUp);
|
|
};
|
|
}
|
|
}, [showTooltip, handlePointerUp]);
|
|
|
|
const renderThumb = (value: number) => {
|
|
const thumb = (
|
|
<SliderPrimitive.Thumb
|
|
className="block size-4 shrink-0 rounded-full border border-primary bg-background shadow-sm outline-none ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50"
|
|
data-slot="slider-thumb"
|
|
onPointerDown={handlePointerDown}
|
|
/>
|
|
);
|
|
|
|
if (!showTooltip) return thumb;
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<Tooltip open={showTooltipState}>
|
|
<TooltipTrigger asChild>{thumb}</TooltipTrigger>
|
|
<TooltipContent
|
|
className="px-2 py-1 text-xs"
|
|
side={props.orientation === "vertical" ? "right" : "top"}
|
|
sideOffset={8}
|
|
>
|
|
<p>{tooltipContent ? tooltipContent(value) : value}</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<SliderPrimitive.Root
|
|
className={cn(
|
|
"relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-[disabled]:opacity-50",
|
|
className,
|
|
)}
|
|
data-slot="slider"
|
|
defaultValue={defaultValue}
|
|
max={max}
|
|
min={min}
|
|
onValueChange={handleValueChange}
|
|
value={value}
|
|
{...props}
|
|
>
|
|
<SliderPrimitive.Track
|
|
className={cn(
|
|
"relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-1.5",
|
|
)}
|
|
data-slot="slider-track"
|
|
>
|
|
<SliderPrimitive.Range
|
|
className={cn(
|
|
"absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
|
|
)}
|
|
data-slot="slider-range"
|
|
/>
|
|
</SliderPrimitive.Track>
|
|
{Array.from({ length: internalValues.length }, (_, index) => (
|
|
<React.Fragment key={String(index)}>
|
|
{renderThumb(internalValues[index])}
|
|
</React.Fragment>
|
|
))}
|
|
</SliderPrimitive.Root>
|
|
);
|
|
}
|
|
|
|
export { Slider };
|