123 lines
2.7 KiB
TypeScript
123 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import clsx from "clsx";
|
|
|
|
interface CustomSliderProps {
|
|
label?: string;
|
|
value: number;
|
|
min?: number;
|
|
max?: number;
|
|
step?: number;
|
|
|
|
onChange?: (value: number) => void;
|
|
|
|
showValue?: boolean;
|
|
disabled?: boolean;
|
|
|
|
className?: string;
|
|
labelClassName?: string;
|
|
sliderClassName?: string;
|
|
thumbClassName?: string;
|
|
trackClassName?: string;
|
|
|
|
color?: string;
|
|
trackColor?: string;
|
|
|
|
renderValue?: (value: number) => React.ReactNode;
|
|
}
|
|
|
|
const CustomSlider = ({
|
|
label,
|
|
value,
|
|
min = 0,
|
|
max = 1,
|
|
step = 0.01,
|
|
|
|
onChange,
|
|
|
|
showValue = true,
|
|
disabled = false,
|
|
|
|
className,
|
|
labelClassName,
|
|
sliderClassName,
|
|
|
|
color = "#2563eb",
|
|
trackColor = "#e5e7eb",
|
|
|
|
renderValue,
|
|
}: CustomSliderProps) => {
|
|
const percentage = ((value - min) / (max - min)) * 100;
|
|
|
|
return (
|
|
<div className={clsx("w-full space-y-3", className)}>
|
|
{/* Header */}
|
|
{(label || showValue) && (
|
|
<div
|
|
className={clsx("flex items-center justify-between", labelClassName)}
|
|
>
|
|
{label && (
|
|
<span className="text-sm font-medium text-gray-700">{label}</span>
|
|
)}
|
|
|
|
{showValue && (
|
|
<span className="text-sm font-semibold text-gray-900">
|
|
{renderValue ? renderValue(value) : value}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Slider */}
|
|
<input
|
|
type="range"
|
|
min={min}
|
|
max={max}
|
|
step={step}
|
|
disabled={disabled}
|
|
value={value}
|
|
onChange={(e) => onChange?.(Number(e.target.value))}
|
|
className={clsx(
|
|
`
|
|
w-full
|
|
appearance-none
|
|
bg-transparent
|
|
cursor-pointer
|
|
|
|
disabled:opacity-50
|
|
disabled:cursor-not-allowed
|
|
|
|
[&::-webkit-slider-runnable-track]:h-2
|
|
[&::-webkit-slider-runnable-track]:rounded-full
|
|
|
|
[&::-webkit-slider-thumb]:appearance-none
|
|
[&::-webkit-slider-thumb]:h-6
|
|
[&::-webkit-slider-thumb]:w-6
|
|
[&::-webkit-slider-thumb]:rounded-full
|
|
[&::-webkit-slider-thumb]:bg-white
|
|
[&::-webkit-slider-thumb]:border-4
|
|
[&::-webkit-slider-thumb]:shadow-md
|
|
[&::-webkit-slider-thumb]:-mt-2
|
|
|
|
[&::-moz-range-track]:h-2
|
|
[&::-moz-range-track]:rounded-full
|
|
|
|
[&::-moz-range-thumb]:h-6
|
|
[&::-moz-range-thumb]:w-6
|
|
[&::-moz-range-thumb]:rounded-full
|
|
[&::-moz-range-thumb]:bg-white
|
|
[&::-moz-range-thumb]:border-4
|
|
`,
|
|
sliderClassName,
|
|
)}
|
|
style={{
|
|
background: `linear-gradient(to right, ${color} ${percentage}%, ${trackColor} ${percentage}%)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CustomSlider;
|