import * as RxSlider from '@radix-ui/react-slider' import clsx from 'clsx' import {ReactNode, useEffect, useState} from 'react' const colors = { green: ['bg-teal-400', 'focus:outline-teal-600/30 bg-teal-600'], 'light-green': [ 'bg-emerald-200/50 dark:bg-emerald-800/50', 'focus:outline-emerald-200/20 bg-emerald-200 dark:bg-teal-200', ], red: ['bg-scarlet-400', 'focus:outline-scarlet-600/30 bg-scarlet-600'], indigo: ['bg-primary-300', 'focus:outline-primary-500/30 bg-primary-500'], // light: ['primary-200', 'primary-300'] } as const export type Mark = {value: number; label: string} export function Slider(props: { amount: number onChange: (newAmount: number) => void min?: number max?: number step?: number marks?: Mark[] color?: keyof typeof colors className?: string disabled?: boolean inverted?: boolean }) { const { amount, onChange, min = 0, max = 100, step, marks, className, disabled, color = 'indigo', inverted, } = props const [trackClasses, thumbClasses] = colors[color] return ( onChange(val)} min={min} max={max} step={step} disabled={disabled} inverted={inverted} >
{marks?.map(({value, label}) => (
= value ? trackClasses : 'bg-ink-400', 'h-2 w-2 rounded-full', )} /> {label}
))}
) } export function RangeSlider(props: { lowValue: number highValue: number setValues: (low: number, high: number) => void min?: number max?: number disabled?: boolean step?: number color?: keyof typeof colors handleSize?: number className?: string marks?: Mark[] }) { const { lowValue, highValue, setValues, min, max, step, disabled, color = 'indigo', className, marks, } = props const [trackClasses, thumbClasses] = colors[color] const [dragValues, setDragValues] = useState<[number, number]>([lowValue, highValue]) // keep local drag state in sync with external values useEffect(() => { setDragValues([lowValue, highValue]) }, [lowValue, highValue]) // debounce parent updates while dragging to avoid excessive re-renders/queries useEffect(() => { const [low, high] = dragValues const t = setTimeout(() => { setValues(low, high) }, 200) return () => clearTimeout(t) }, [dragValues]) return ( setDragValues([vals[0], vals[1]])} // update continuously for UI feedback min={min} max={max} disabled={disabled} >
{marks?.map(({value, label}) => (
{label}
))}
) } const Track = (props: {className: string; children?: ReactNode}) => { const {className, children} = props return ( {children} ) } const Thumb = (props: {className: string}) => ( )