{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "range-slider",
  "title": "Range Slider",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/range-slider/RangeSlider.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport * as SliderPrimitive from '@radix-ui/react-slider'\nimport { cn } from '@/lib/utils'\n\nexport interface RangeSliderProps\n  extends Omit<\n    React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n    'value' | 'defaultValue' | 'onValueChange' | 'min' | 'max' | 'step'\n  > {\n  className?: string\n  /** The controlled value of the range slider. */\n  value?: [number, number]\n  /** The value of the range slider when initially rendered. */\n  defaultValue?: [number, number]\n  onValueChange?: (value: [number, number]) => void\n  /** When `true`, prevents the user from interacting with the range slider */\n  disabled?: boolean\n  /** Minimum value */\n  min?: number\n  /** Maximum value */\n  max?: number\n  /** Step value */\n  step?: number\n  /** Label for the range slider */\n  label?: string\n  /** Hint text for the range slider */\n  hint?: string\n  /** Error messages to display */\n  errorMessages?: string | string[]\n  /** Whether to show error state */\n  error?: boolean\n  /** Custom color for the track fill */\n  color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | string\n  /** Thumb size */\n  thumbSize?: 'sm' | 'md' | 'lg'\n  /** Track height */\n  trackHeight?: 'sm' | 'md' | 'lg'\n  /** Show ticks */\n  showTicks?: boolean\n  /** Tick interval */\n  tickInterval?: number\n  /** Show thumb labels */\n  thumbLabel?: boolean\n  /** Format thumb label */\n  thumbLabelFormat?: (value: number) => string\n}\n\n// Color classes\nconst colorClasses: Record<string, string> = {\n  primary: 'bg-primary',\n  secondary: 'bg-secondary',\n  success: 'bg-[var(--success)]',\n  warning: 'bg-[var(--warning)]',\n  error: 'bg-destructive',\n  info: 'bg-[var(--info)]',\n}\n\n// Track height classes\nconst trackHeightClasses = {\n  sm: 'h-1',\n  md: 'h-1.5',\n  lg: 'h-2',\n}\n\n// Thumb size classes\nconst thumbSizeClasses = {\n  sm: 'size-3',\n  md: 'size-4',\n  lg: 'size-5',\n}\n\nconst RangeSlider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, RangeSliderProps>(\n  (\n    {\n      className,\n      value,\n      defaultValue,\n      onValueChange,\n      disabled,\n      min = 0,\n      max = 100,\n      step = 1,\n      label,\n      hint,\n      errorMessages,\n      error,\n      color = 'primary',\n      thumbSize = 'md',\n      trackHeight = 'md',\n      showTicks,\n      tickInterval,\n      thumbLabel,\n      thumbLabelFormat,\n      ...props\n    },\n    ref,\n  ) => {\n    const isControlled = value !== undefined\n    const [internalValue, setInternalValue] = React.useState<[number, number]>(\n      defaultValue ?? [min, max],\n    )\n    const currentValue = isControlled ? value! : internalValue\n\n    const handleChange = React.useCallback(\n      (next: number[]) => {\n        const tuple = [next[0], next[1]] as [number, number]\n        if (!isControlled) setInternalValue(tuple)\n        onValueChange?.(tuple)\n      },\n      [isControlled, onValueChange],\n    )\n\n    // Generate ticks\n    const ticks = React.useMemo(() => {\n      if (!showTicks || !tickInterval) return []\n      const result: number[] = []\n      for (let i = min; i <= max; i += tickInterval) {\n        result.push(i)\n      }\n      return result\n    }, [showTicks, tickInterval, min, max])\n\n    // Build error state\n    const hasError = React.useMemo(() => {\n      if (error) return true\n      if (errorMessages && (typeof errorMessages === 'string' ? errorMessages : errorMessages.length > 0))\n        return true\n      return false\n    }, [error, errorMessages])\n\n    const thumbClass = cn(\n      'border-primary ring-ring/50 bg-background block rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',\n      thumbSizeClasses[thumbSize],\n      hasError && 'border-destructive',\n    )\n\n    return (\n      <div className=\"flex flex-col gap-2\">\n        {label && <label className=\"text-sm font-medium\">{label}</label>}\n\n        {hint && !hasError && <p className=\"text-muted-foreground text-xs\">{hint}</p>}\n\n        <div className=\"flex items-center gap-4\">\n          {/* Min value display */}\n          <div className=\"text-muted-foreground min-w-[3rem] text-sm\">{currentValue?.[0] ?? min}</div>\n\n          <SliderPrimitive.Root\n            ref={ref}\n            data-slot=\"range-slider\"\n            disabled={disabled}\n            min={min}\n            max={max}\n            step={step}\n            value={isControlled ? value : undefined}\n            defaultValue={isControlled ? undefined : (defaultValue ?? [min, max])}\n            onValueChange={handleChange}\n            className={cn('relative flex w-full touch-none items-center select-none', className)}\n            {...props}\n          >\n            <SliderPrimitive.Track\n              data-uipkge=\"\"\n              data-slot=\"slider-track\"\n              className={cn(\n                'bg-muted relative w-full overflow-hidden rounded-full',\n                trackHeightClasses[trackHeight],\n              )}\n            >\n              <SliderPrimitive.Range\n                data-uipkge=\"\"\n                data-slot=\"slider-range\"\n                className={cn('absolute h-full', colorClasses[color as string] || colorClasses.primary)}\n              />\n            </SliderPrimitive.Track>\n\n            {/* Ticks */}\n            {showTicks && ticks.length > 0 && (\n              <div className=\"pointer-events-none absolute top-1/2 right-0 left-0 flex -translate-y-1/2 justify-between\">\n                {ticks.map((tick) => (\n                  <div key={tick} className=\"bg-muted-foreground/30 h-2 w-0.5 rounded-full\" />\n                ))}\n              </div>\n            )}\n\n            {/* Start Thumb (Min) */}\n            <SliderPrimitive.Thumb data-uipkge=\"\" data-slot=\"slider-thumb\" className={thumbClass}>\n              {thumbLabel && (\n                <span className=\"bg-background absolute -top-6 left-1/2 -translate-x-1/2 rounded px-1 text-xs whitespace-nowrap\">\n                  {thumbLabelFormat\n                    ? thumbLabelFormat(currentValue?.[0] ?? 0)\n                    : (currentValue?.[0] ?? 0)}\n                </span>\n              )}\n            </SliderPrimitive.Thumb>\n\n            {/* End Thumb (Max) */}\n            <SliderPrimitive.Thumb data-uipkge=\"\" data-slot=\"slider-thumb\" className={thumbClass}>\n              {thumbLabel && (\n                <span className=\"bg-background absolute -top-6 left-1/2 -translate-x-1/2 rounded px-1 text-xs whitespace-nowrap\">\n                  {thumbLabelFormat\n                    ? thumbLabelFormat(currentValue?.[1] ?? 0)\n                    : (currentValue?.[1] ?? 0)}\n                </span>\n              )}\n            </SliderPrimitive.Thumb>\n          </SliderPrimitive.Root>\n\n          {/* Max value display */}\n          <div className=\"text-muted-foreground min-w-[3rem] text-sm\">{currentValue?.[1] ?? max}</div>\n        </div>\n\n        {/* Tick labels */}\n        {showTicks && ticks.length > 0 && (\n          <div className=\"text-muted-foreground flex justify-between px-1 text-xs\">\n            <span>{min}</span>\n            <span>{max}</span>\n          </div>\n        )}\n\n        {hasError && (\n          <div className=\"flex flex-col gap-0.5\">\n            {typeof errorMessages === 'string' ? (\n              <p className=\"text-destructive text-xs\">{errorMessages}</p>\n            ) : (\n              errorMessages?.map((msg, i) => (\n                <p key={i} className=\"text-destructive text-xs\">\n                  {msg}\n                </p>\n              ))\n            )}\n          </div>\n        )}\n      </div>\n    )\n  },\n)\nRangeSlider.displayName = 'RangeSlider'\n\nexport { RangeSlider }\n",
      "type": "registry:ui",
      "target": "~/components/ui/range-slider/RangeSlider.tsx"
    },
    {
      "path": "packages/registry-react/components/range-slider/index.ts",
      "content": "export { RangeSlider, type RangeSliderProps } from './RangeSlider'\n",
      "type": "registry:ui",
      "target": "~/components/ui/range-slider/index.ts"
    }
  ],
  "dependencies": [
    "@radix-ui/react-slider"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Two-thumb range slider for \"between X and Y\" inputs — price filters, age ranges, time windows. Built on @radix-ui/react-slider with proper keyboard handling and aria-valuetext.",
  "categories": [
    "form"
  ]
}