{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "r-slider",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["@radix-ui/react-slider", "motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "r-slider.tsx",
      "content": "\"use client\";\n\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport {\n  animate,\n  type MotionValue,\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useTransform,\n} from \"motion/react\";\nimport {\n  forwardRef,\n  type ReactNode,\n  useCallback,\n  useEffect,\n  useId,\n  useRef,\n  useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst componentThemeClassName =\n  \"[--ic-background:#ffffff] [--ic-foreground:#111111] [--ic-primary:#111111] [--ic-secondary:#646b75] [--ic-surface-border:#e9edf2] [--ic-border:#e3e7ec] [--ic-card:#ffffff] [--ic-card-foreground:#111111] [--ic-muted:#f5f7fa] [--ic-muted-foreground:#6d7480] [--ic-accent:#f3f5f8] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--ic-accent-foreground:#111111] [--ic-input:#e3e7ec] [--ic-ring:rgba(17,17,17,0.16)] [--ic-destructive:#dc2626] [--ic-paper:#fcfcfd] [--ic-popover-foreground:#111111] [--ic-brand:#0ea5e9] [--ic-brand-soft:#bae6fd] [--ic-shadow-soft:0_18px_38px_-24px_rgba(15,23,42,0.35)] [--ic-chart-1:oklch(0.52_0.19_254)] [--ic-chart-2:oklch(0.74_0.11_232)] [--ic-chart-3:oklch(0.42_0.16_262)] [--ic-chart-4:oklch(0.84_0.07_228)] [--ic-chart-5:oklch(0.62_0.14_240)] [--color-background:var(--ic-background)] [--color-foreground:var(--ic-foreground)] [--color-primary:var(--ic-primary)] [--color-secondary:var(--ic-secondary)] [--color-border:var(--ic-border)] [--color-card:var(--ic-card)] [--color-card-foreground:var(--ic-card-foreground)] [--color-muted:var(--ic-muted)] [--color-muted-foreground:var(--ic-muted-foreground)] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--color-input:var(--ic-input)] [--color-ring:var(--ic-ring)] [--color-destructive:var(--ic-destructive)] [--color-paper:var(--ic-paper)] [--color-popover-foreground:var(--ic-popover-foreground)] [--color-brand:var(--ic-brand)] [--color-brand-soft:var(--ic-brand-soft)] [--color-chart-1:var(--ic-chart-1)] [--color-chart-2:var(--ic-chart-2)] [--color-chart-3:var(--ic-chart-3)] [--color-chart-4:var(--ic-chart-4)] [--color-chart-5:var(--ic-chart-5)] dark:[--ic-background:#111111] dark:[--ic-foreground:#f6f3ec] dark:[--ic-primary:#f6f3ec] dark:[--ic-secondary:#cbc6bb] dark:[--ic-surface-border:#2a2a25] dark:[--ic-border:#2b2a25] dark:[--ic-card:#111111] dark:[--ic-card-foreground:#f6f3ec] dark:[--ic-muted:#171716] dark:[--ic-muted-foreground:#9a958a] dark:[--ic-accent:#1a1a18] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] dark:[--ic-accent-foreground:#f6f3ec] dark:[--ic-input:#2b2a25] dark:[--ic-ring:rgba(246,243,236,0.18)] dark:[--ic-destructive:#f87171] dark:[--ic-paper:#171716] dark:[--ic-popover-foreground:#f6f3ec] dark:[--ic-brand:#38bdf8] dark:[--ic-brand-soft:#0c4a6e] dark:[--ic-shadow-soft:0_20px_44px_-28px_rgba(0,0,0,0.6)] dark:[--ic-chart-1:oklch(0.68_0.17_250)] dark:[--ic-chart-2:oklch(0.82_0.09_225)] dark:[--ic-chart-3:oklch(0.58_0.15_260)] dark:[--ic-chart-4:oklch(0.75_0.12_235)] dark:[--ic-chart-5:oklch(0.88_0.06_220)]\";\n\nexport interface SliderMark {\n  value: number;\n  label?: string;\n}\n\nexport type SliderSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface SliderProps {\n  value?: number | [number, number];\n  defaultValue?: number | [number, number];\n  min?: number;\n  max?: number;\n  step?: number;\n  onChange?: (value: number | [number, number]) => void;\n  onValueCommit?: (value: number | [number, number]) => void;\n  showValue?: boolean;\n  valueDecimals?: number;\n  formatValue?: (value: number) => string;\n  label?: string;\n  ariaLabel?: string;\n  ariaLabelledBy?: string;\n  marks?: SliderMark[];\n  className?: string;\n  disabled?: boolean;\n  readOnly?: boolean;\n  description?: ReactNode;\n  errorMessage?: ReactNode;\n  invalid?: boolean;\n  ariaDescribedBy?: string;\n  marksInteractive?: boolean;\n  size?: SliderSize;\n  inverted?: boolean;\n  name?: string;\n  id?: string;\n  range?: boolean;\n}\n\nexport const sliderSizeClasses = {\n  sm: {\n    hitAreaHorizontal: \"h-9\",\n    thumb: \"h-3 w-3\",\n    thumbBorder: \"border\",\n    trackInactive: 3,\n    trackActive: 5,\n  },\n  md: {\n    hitAreaHorizontal: \"h-11\",\n    thumb: \"h-4 w-4\",\n    thumbBorder: \"border-[1.5px]\",\n    trackInactive: 4,\n    trackActive: 6,\n  },\n  lg: {\n    hitAreaHorizontal: \"h-14\",\n    thumb: \"h-5 w-5\",\n    thumbBorder: \"border-2\",\n    trackInactive: 5,\n    trackActive: 7,\n  },\n} as const satisfies Record<\n  SliderSize,\n  {\n    hitAreaHorizontal: string;\n    thumb: string;\n    thumbBorder: string;\n    trackInactive: number;\n    trackActive: number;\n  }\n>;\n\nfunction clamp(value: number, min: number, max: number) {\n  return Math.min(Math.max(value, min), max);\n}\n\nfunction getPrecision(value: number) {\n  if (!Number.isFinite(value)) {\n    return 0;\n  }\n\n  const normalized = value.toString().toLowerCase();\n\n  if (normalized.includes(\"e-\")) {\n    const [base, exponent] = normalized.split(\"e-\");\n    return (base.split(\".\")[1]?.length ?? 0) + Number(exponent);\n  }\n\n  return normalized.split(\".\")[1]?.length ?? 0;\n}\n\nfunction snapValue(raw: number, min: number, max: number, step: number) {\n  const safeStep = step > 0 ? step : 1;\n  const precision = Math.max(\n    getPrecision(safeStep),\n    getPrecision(min),\n    getPrecision(max)\n  );\n  const stepped = min + Math.round((raw - min) / safeStep) * safeStep;\n  return clamp(Number(stepped.toFixed(precision)), min, max);\n}\n\nfunction snapRangeValue(\n  raw: readonly [number, number] | number[],\n  min: number,\n  max: number,\n  step: number\n): [number, number] {\n  const first = snapValue(raw[0] ?? min, min, max, step);\n  const second = snapValue(raw[1] ?? max, min, max, step);\n  return first <= second ? [first, second] : [second, first];\n}\n\nfunction formatSliderDisplayValue(\n  value: number | [number, number],\n  options: {\n    formatValue?: (value: number) => string;\n    range?: boolean;\n    valueDecimals?: number;\n  }\n) {\n  const { formatValue, range = false, valueDecimals = 0 } = options;\n\n  if (range && Array.isArray(value)) {\n    const [low, high] = value;\n    const lowText = formatValue ? formatValue(low) : low.toFixed(valueDecimals);\n    const highText = formatValue\n      ? formatValue(high)\n      : high.toFixed(valueDecimals);\n    return `${lowText} – ${highText}`;\n  }\n\n  const numericValue = Array.isArray(value) ? (value[0] ?? 0) : value;\n  return formatValue\n    ? formatValue(numericValue)\n    : numericValue.toFixed(valueDecimals);\n}\n\nfunction resolveSliderAccessibleName({\n  ariaLabel,\n  ariaLabelledBy,\n  label,\n  labelId,\n}: {\n  ariaLabel?: string;\n  ariaLabelledBy?: string;\n  label?: string;\n  labelId?: string;\n}) {\n  if (ariaLabelledBy || label) {\n    return {\n      ariaLabel: undefined,\n      ariaLabelledBy: ariaLabelledBy ?? labelId,\n    };\n  }\n\n  return {\n    ariaLabel: ariaLabel ?? \"Slider\",\n    ariaLabelledBy: undefined,\n  };\n}\n\nfunction resolveSliderFieldMeta({\n  ariaDescribedByProp,\n  description,\n  errorMessage,\n  generatedId,\n  id,\n  invalid,\n}: {\n  ariaDescribedByProp?: string;\n  description?: ReactNode;\n  errorMessage?: ReactNode;\n  generatedId: string;\n  id?: string;\n  invalid?: boolean;\n}) {\n  const sliderId = id ?? generatedId;\n  const descriptionId = description ? `${sliderId}-description` : undefined;\n  const errorId = errorMessage ? `${sliderId}-error` : undefined;\n  const showInvalid = Boolean(invalid) || Boolean(errorMessage);\n\n  return {\n    describedBy: [ariaDescribedByProp, descriptionId, errorId]\n      .filter(Boolean)\n      .join(\" \"),\n    descriptionId,\n    errorId,\n    showInvalid,\n    sliderId,\n  };\n}\n\nfunction resolveBlurTarget(\n  currentTarget: EventTarget & HTMLSpanElement,\n  relatedTarget: EventTarget | null\n) {\n  return !currentTarget.contains(relatedTarget as Node | null);\n}\n\nfunction isDocumentRtl() {\n  if (typeof document === \"undefined\") {\n    return false;\n  }\n\n  return document.documentElement.dir === \"rtl\";\n}\n\nfunction valueToProgress(\n  currentValue: number,\n  resolvedMin: number,\n  resolvedMax: number\n) {\n  const span = resolvedMax - resolvedMin;\n  return span === 0 ? 0 : ((currentValue - resolvedMin) / span) * 100;\n}\n\nfunction progressToValue(\n  progress: number,\n  resolvedMin: number,\n  resolvedMax: number,\n  safeStep: number\n) {\n  const span = resolvedMax - resolvedMin;\n  const raw = resolvedMin + (progress / 100) * span;\n  return snapValue(raw, resolvedMin, resolvedMax, safeStep);\n}\n\nfunction resolveRadixChangeValue(\n  nextValues: readonly number[],\n  isRange: boolean,\n  inverted: boolean,\n  resolvedMin: number,\n  resolvedMax: number,\n  safeStep: number\n): number | [number, number] {\n  return fromPrimitiveValue(\n    nextValues,\n    isRange,\n    inverted,\n    resolvedMin,\n    resolvedMax,\n    safeStep\n  );\n}\n\nfunction invertSliderValue(\n  value: number,\n  resolvedMin: number,\n  resolvedMax: number\n) {\n  return resolvedMin + resolvedMax - value;\n}\n\nfunction toPrimitiveValue(\n  value: number | [number, number],\n  isRange: boolean,\n  inverted: boolean,\n  resolvedMin: number,\n  resolvedMax: number\n): number | [number, number] {\n  if (!inverted) {\n    return value;\n  }\n\n  if (isRange) {\n    const [low, high] = value as [number, number];\n    return [\n      invertSliderValue(high, resolvedMin, resolvedMax),\n      invertSliderValue(low, resolvedMin, resolvedMax),\n    ];\n  }\n\n  return invertSliderValue(value as number, resolvedMin, resolvedMax);\n}\n\nfunction fromPrimitiveValue(\n  nextValue: number | readonly number[],\n  isRange: boolean,\n  inverted: boolean,\n  resolvedMin: number,\n  resolvedMax: number,\n  safeStep: number\n): number | [number, number] {\n  if (!inverted) {\n    if (isRange) {\n      const tuple = Array.isArray(nextValue)\n        ? nextValue\n        : [nextValue, nextValue];\n      return snapRangeValue(tuple, resolvedMin, resolvedMax, safeStep);\n    }\n\n    return snapValue(\n      Array.isArray(nextValue) ? (nextValue[0] ?? resolvedMin) : nextValue,\n      resolvedMin,\n      resolvedMax,\n      safeStep\n    );\n  }\n\n  if (isRange) {\n    const tuple = Array.isArray(nextValue) ? nextValue : [nextValue, nextValue];\n    const low = invertSliderValue(\n      tuple[1] ?? resolvedMax,\n      resolvedMin,\n      resolvedMax\n    );\n    const high = invertSliderValue(\n      tuple[0] ?? resolvedMin,\n      resolvedMin,\n      resolvedMax\n    );\n    return snapRangeValue([low, high], resolvedMin, resolvedMax, safeStep);\n  }\n\n  const numeric = Array.isArray(nextValue)\n    ? (nextValue[0] ?? resolvedMin)\n    : nextValue;\n  return snapValue(\n    invertSliderValue(numeric, resolvedMin, resolvedMax),\n    resolvedMin,\n    resolvedMax,\n    safeStep\n  );\n}\n\nfunction toRadixValue(\n  value: number | [number, number],\n  isRange: boolean,\n  inverted: boolean,\n  resolvedMin: number,\n  resolvedMax: number\n): number[] {\n  const primitive = toPrimitiveValue(\n    value,\n    isRange,\n    inverted,\n    resolvedMin,\n    resolvedMax\n  );\n\n  if (isRange) {\n    const tuple = primitive as [number, number];\n    return [tuple[0], tuple[1]];\n  }\n\n  return [primitive as number];\n}\n\nfunction resolveInitialSliderValue(\n  controlledValue: number | [number, number] | undefined,\n  defaultValue: number | [number, number] | undefined,\n  range: boolean,\n  resolvedMin: number,\n  resolvedMax: number,\n  safeStep: number,\n  rangeSpan: number\n) {\n  const initial = controlledValue ?? defaultValue ?? (range ? [25, 75] : 50);\n\n  if (range) {\n    const tuple = Array.isArray(initial)\n      ? initial\n      : [resolvedMin + rangeSpan * 0.25, resolvedMin + rangeSpan * 0.75];\n    return snapRangeValue(tuple, resolvedMin, resolvedMax, safeStep);\n  }\n\n  const numeric = Array.isArray(initial) ? (initial[0] ?? 50) : initial;\n  return snapValue(numeric, resolvedMin, resolvedMax, safeStep);\n}\n\nfunction resolveControlledSliderValue(\n  controlledValue: number | [number, number] | undefined,\n  internalValue: number | [number, number],\n  range: boolean,\n  resolvedMin: number,\n  resolvedMax: number,\n  safeStep: number\n) {\n  if (controlledValue === undefined) {\n    return internalValue;\n  }\n\n  if (range) {\n    return snapRangeValue(\n      Array.isArray(controlledValue)\n        ? controlledValue\n        : [controlledValue, controlledValue],\n      resolvedMin,\n      resolvedMax,\n      safeStep\n    );\n  }\n\n  return snapValue(\n    Array.isArray(controlledValue)\n      ? (controlledValue[0] ?? resolvedMin)\n      : controlledValue,\n    resolvedMin,\n    resolvedMax,\n    safeStep\n  );\n}\n\nfunction sliderValuesEqual(\n  current: number | [number, number],\n  next: number | [number, number],\n  range: boolean\n) {\n  if (range) {\n    const currentTuple = Array.isArray(current) ? current : [current, current];\n    const nextTuple = Array.isArray(next) ? next : [next, next];\n    return currentTuple[0] === nextTuple[0] && currentTuple[1] === nextTuple[1];\n  }\n\n  const currentValue = Array.isArray(current) ? (current[0] ?? 0) : current;\n  const nextValue = Array.isArray(next) ? (next[0] ?? 0) : next;\n  return currentValue === nextValue;\n}\n\nfunction resolveThumbAccessibleLabel(\n  accessibleName: ReturnType<typeof resolveSliderAccessibleName>,\n  thumbIndex: number,\n  isRange: boolean\n) {\n  if (accessibleName.ariaLabelledBy) {\n    return undefined;\n  }\n\n  const baseLabel = accessibleName.ariaLabel ?? \"Slider\";\n\n  if (!isRange) {\n    return baseLabel;\n  }\n\n  return thumbIndex === 0 ? `${baseLabel}, minimum` : `${baseLabel}, maximum`;\n}\n\nfunction SliderVisualShell({\n  active,\n  activeThumbIndex,\n  fillLeftPercent,\n  fillSizePercent,\n  isDragging,\n  isHovered,\n  isRange,\n  sizeClasses,\n  thumbPercents,\n}: {\n  active: boolean;\n  activeThumbIndex: number;\n  fillLeftPercent: MotionValue<string>;\n  fillSizePercent: MotionValue<string>;\n  isDragging: boolean;\n  isHovered: boolean;\n  isRange: boolean;\n  sizeClasses: (typeof sliderSizeClasses)[SliderSize];\n  thumbPercents: MotionValue<string>[];\n}) {\n  const trackInactive = sizeClasses.trackInactive;\n  const trackActive = sizeClasses.trackActive;\n  const trackSize = active ? trackActive : trackInactive;\n  const springTransition = {\n    type: \"spring\" as const,\n    stiffness: 200,\n    damping: 28,\n    mass: 0.8,\n  };\n  const thumbSpringTransition = {\n    type: \"spring\" as const,\n    stiffness: 220,\n    damping: 22,\n    mass: 0.7,\n  };\n\n  return (\n    <div aria-hidden className=\"pointer-events-none absolute inset-0\">\n      <motion.div\n        animate={{ height: trackSize }}\n        className=\"absolute top-1/2 right-0 left-0 -translate-y-1/2 overflow-hidden rounded-full bg-foreground/15\"\n        transition={springTransition}\n      />\n\n      <motion.div\n        animate={{ height: trackSize }}\n        className=\"absolute top-1/2 left-0 origin-left -translate-y-1/2 overflow-hidden rounded-full bg-foreground\"\n        style={{ left: fillLeftPercent, width: fillSizePercent }}\n        transition={springTransition}\n      />\n\n      {thumbPercents.map((thumbPercent, index) => {\n        const isActiveThumb = isDragging && activeThumbIndex === index;\n\n        return (\n          <motion.div\n            animate={{\n              scale: isActiveThumb ? 1.15 : isHovered ? 1.08 : 1,\n            }}\n            className=\"absolute top-1/2 -translate-x-1/2 -translate-y-1/2\"\n            key={isRange ? `thumb-${index}` : \"thumb\"}\n            style={{ left: thumbPercent }}\n            transition={thumbSpringTransition}\n          >\n            <div\n              className={cn(\n                \"relative rounded-full border-foreground bg-background shadow-sm\",\n                sizeClasses.thumb,\n                sizeClasses.thumbBorder\n              )}\n            />\n          </motion.div>\n        );\n      })}\n    </div>\n  );\n}\n\nfunction SliderMarks({\n  disabled,\n  inverted,\n  isRtl,\n  marks,\n  marksInteractive,\n  onMarkActivate,\n  rangeSpan,\n  readOnly,\n  resolvedMin,\n}: {\n  disabled?: boolean;\n  inverted: boolean;\n  isRtl: boolean;\n  marks: SliderMark[];\n  marksInteractive?: boolean;\n  onMarkActivate: (value: number) => void;\n  rangeSpan: number;\n  readOnly?: boolean;\n  resolvedMin: number;\n}) {\n  if (marks.length === 0) {\n    return null;\n  }\n\n  const hasMarkLabels = marks.some((mark) => mark.label);\n  const interactive = marksInteractive && !disabled && !readOnly;\n\n  return (\n    <div\n      aria-hidden={!interactive}\n      className={cn(\n        \"relative mt-2\",\n        hasMarkLabels ? \"h-8\" : \"h-3\",\n        interactive ? \"\" : \"pointer-events-none\"\n      )}\n    >\n      {marks.map((mark) => {\n        let progress =\n          rangeSpan === 0 ? 0 : ((mark.value - resolvedMin) / rangeSpan) * 100;\n\n        if (isRtl) {\n          progress = 100 - progress;\n        }\n\n        if (inverted) {\n          progress = 100 - progress;\n        }\n\n        const positionStyle = { left: `${progress}%` };\n\n        const content = (\n          <>\n            <span className=\"mx-auto block h-2 w-px rounded-full bg-foreground/25\" />\n            {mark.label ? (\n              <span className=\"mt-1 block whitespace-nowrap font-medium text-[11px] text-muted-foreground\">\n                {mark.label}\n              </span>\n            ) : null}\n          </>\n        );\n\n        if (interactive) {\n          return (\n            <button\n              className=\"absolute top-0 -translate-x-1/2 text-center outline-none focus-visible:outline-2 focus-visible:outline-foreground/35 focus-visible:outline-offset-2\"\n              key={`${mark.value}-${mark.label ?? \"tick\"}`}\n              onClick={() => {\n                onMarkActivate(mark.value);\n              }}\n              style={positionStyle}\n              type=\"button\"\n            >\n              {content}\n            </button>\n          );\n        }\n\n        return (\n          <div\n            className=\"absolute top-0 -translate-x-1/2 text-center\"\n            key={`${mark.value}-${mark.label ?? \"tick\"}`}\n            style={positionStyle}\n          >\n            {content}\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n\nfunction SliderFieldMessages({\n  description,\n  descriptionId,\n  errorId,\n  errorMessage,\n}: {\n  description?: ReactNode;\n  descriptionId?: string;\n  errorId?: string;\n  errorMessage?: ReactNode;\n}) {\n  if (!(description || errorMessage)) {\n    return null;\n  }\n\n  return (\n    <div className=\"mt-2 space-y-1\">\n      {description ? (\n        <p\n          className=\"text-muted-foreground text-xs leading-snug\"\n          id={descriptionId}\n        >\n          {description}\n        </p>\n      ) : null}\n      {errorMessage ? (\n        <p\n          aria-live=\"polite\"\n          className=\"text-destructive text-xs leading-snug\"\n          id={errorId}\n          role=\"alert\"\n        >\n          {errorMessage}\n        </p>\n      ) : null}\n    </div>\n  );\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: slider shell coordinates motion, range, pointer, and keyboard state in one place.\nexport const Slider = forwardRef<HTMLSpanElement, SliderProps>(function Slider(\n  {\n    value: controlledValue,\n    defaultValue,\n    min = 0,\n    max = 100,\n    step = 1,\n    onChange,\n    onValueCommit,\n    showValue = true,\n    valueDecimals = 0,\n    formatValue,\n    label,\n    ariaLabel,\n    ariaLabelledBy,\n    marks,\n    className,\n    disabled = false,\n    readOnly = false,\n    description,\n    errorMessage,\n    invalid = false,\n    ariaDescribedBy,\n    marksInteractive = false,\n    size = \"md\",\n    inverted = false,\n    name,\n    id,\n    range = false,\n  },\n  ref\n) {\n  const generatedId = useId();\n  const labelId = useId();\n  const activeThumbIndexRef = useRef(0);\n  const resolvedMin = Math.min(min, max);\n  const resolvedMax = Math.max(min, max);\n  const safeStep = step > 0 ? step : 1;\n  const safeValueDecimals = Math.max(0, valueDecimals);\n  const rangeSpan = resolvedMax - resolvedMin;\n  const sizeClasses = sliderSizeClasses[size];\n  const prefersReducedMotion = useReducedMotion() === true;\n  const [isRtl, setIsRtl] = useState(false);\n  const [internalValue, setInternalValue] = useState<number | [number, number]>(\n    () =>\n      resolveInitialSliderValue(\n        controlledValue,\n        defaultValue,\n        range,\n        resolvedMin,\n        resolvedMax,\n        safeStep,\n        rangeSpan\n      )\n  );\n  const [isDragging, setIsDragging] = useState(false);\n  const [isHovered, setIsHovered] = useState(false);\n  const [isFocused, setIsFocused] = useState(false);\n  const [activeThumbIndex, setActiveThumbIndex] = useState(0);\n\n  const fieldMeta = resolveSliderFieldMeta({\n    ariaDescribedByProp: ariaDescribedBy,\n    description,\n    errorMessage,\n    generatedId,\n    id,\n    invalid,\n  });\n  const accessibleName = resolveSliderAccessibleName({\n    ariaLabel,\n    ariaLabelledBy,\n    label,\n    labelId,\n  });\n\n  useEffect(() => {\n    setIsRtl(isDocumentRtl());\n  }, []);\n\n  useEffect(() => {\n    if (controlledValue !== undefined) {\n      return;\n    }\n\n    setInternalValue((current) => {\n      if (range) {\n        const tuple = Array.isArray(current)\n          ? current\n          : [resolvedMin, resolvedMax];\n        const next = snapRangeValue(tuple, resolvedMin, resolvedMax, safeStep);\n        return next[0] === tuple[0] && next[1] === tuple[1] ? current : next;\n      }\n\n      const numeric = Array.isArray(current)\n        ? (current[0] ?? resolvedMin)\n        : current;\n      const next = snapValue(numeric, resolvedMin, resolvedMax, safeStep);\n      return current === next ? current : next;\n    });\n  }, [controlledValue, range, resolvedMin, resolvedMax, safeStep]);\n\n  const value = resolveControlledSliderValue(\n    controlledValue,\n    internalValue,\n    range,\n    resolvedMin,\n    resolvedMax,\n    safeStep\n  );\n\n  const values: [number, number] = range\n    ? (value as [number, number])\n    : [value as number, value as number];\n  const [lowValue, highValue] = values;\n  const lowProgress = valueToProgress(lowValue, resolvedMin, resolvedMax);\n  const highProgress = valueToProgress(highValue, resolvedMin, resolvedMax);\n  const singleProgress = range\n    ? lowProgress\n    : valueToProgress(value as number, resolvedMin, resolvedMax);\n  const fillStartProgress = range ? lowProgress : 0;\n  const fillEndProgress = range ? highProgress : singleProgress;\n\n  const lowProgressMV = useMotionValue(lowProgress);\n  const highProgressMV = useMotionValue(highProgress);\n  const singleProgressMV = useMotionValue(singleProgress);\n  const fillStartMV = useMotionValue(fillStartProgress);\n  const fillEndMV = useMotionValue(fillEndProgress);\n\n  const lowThumbPercent = useTransform(\n    lowProgressMV,\n    (progress) => `${progress}%`\n  );\n  const highThumbPercent = useTransform(\n    highProgressMV,\n    (progress) => `${progress}%`\n  );\n  const singleThumbPercent = useTransform(\n    singleProgressMV,\n    (progress) => `${progress}%`\n  );\n  const thumbPercents = range\n    ? [lowThumbPercent, highThumbPercent]\n    : [singleThumbPercent];\n\n  const fillLeftPercent = useTransform(\n    fillStartMV,\n    (progress) => `${progress}%`\n  );\n  const fillSizePercent = useTransform(\n    [fillStartMV, fillEndMV],\n    ([start, end]: number[]) => `${Math.max(0, end - start)}%`\n  );\n\n  const singleDisplayValue = useTransform(singleProgressMV, (progress) => {\n    const resolved = progressToValue(\n      progress,\n      resolvedMin,\n      resolvedMax,\n      safeStep\n    );\n\n    return formatSliderDisplayValue(resolved, {\n      formatValue,\n      valueDecimals: safeValueDecimals,\n    });\n  });\n  const rangeDisplayValue = useTransform(\n    [lowProgressMV, highProgressMV],\n    ([low, high]: number[]) => {\n      const lowResolved = progressToValue(\n        low,\n        resolvedMin,\n        resolvedMax,\n        safeStep\n      );\n      const highResolved = progressToValue(\n        high,\n        resolvedMin,\n        resolvedMax,\n        safeStep\n      );\n\n      return formatSliderDisplayValue([lowResolved, highResolved], {\n        formatValue,\n        range: true,\n        valueDecimals: safeValueDecimals,\n      });\n    }\n  );\n\n  const progressSpring = prefersReducedMotion\n    ? { duration: 0 }\n    : {\n        type: \"spring\" as const,\n        stiffness: 180,\n        damping: 26,\n        mass: 0.9,\n        restDelta: 0.001,\n      };\n\n  useEffect(() => {\n    activeThumbIndexRef.current = activeThumbIndex;\n  }, [activeThumbIndex]);\n\n  useEffect(() => {\n    const controls = [\n      animate(lowProgressMV, lowProgress, progressSpring),\n      animate(highProgressMV, highProgress, progressSpring),\n      animate(singleProgressMV, singleProgress, progressSpring),\n      animate(fillStartMV, fillStartProgress, progressSpring),\n      animate(fillEndMV, fillEndProgress, progressSpring),\n    ];\n\n    return () => {\n      for (const control of controls) {\n        control.stop();\n      }\n    };\n  }, [\n    fillEndProgress,\n    fillStartProgress,\n    highProgress,\n    highProgressMV,\n    lowProgress,\n    lowProgressMV,\n    progressSpring,\n    singleProgress,\n    singleProgressMV,\n    fillEndMV,\n    fillStartMV,\n  ]);\n\n  const formattedValueText = formatSliderDisplayValue(value, {\n    formatValue,\n    range,\n    valueDecimals: safeValueDecimals,\n  });\n  const lowValueText = formatSliderDisplayValue(lowValue, {\n    formatValue,\n    valueDecimals: safeValueDecimals,\n  });\n  const highValueText = formatSliderDisplayValue(highValue, {\n    formatValue,\n    valueDecimals: safeValueDecimals,\n  });\n\n  const radixValue = toRadixValue(\n    value,\n    range,\n    inverted,\n    resolvedMin,\n    resolvedMax\n  );\n\n  const applyResolvedValue = useCallback(\n    (\n      normalized: number | [number, number],\n      commit?: (resolved: number | [number, number]) => void\n    ) => {\n      if (sliderValuesEqual(value, normalized, range)) {\n        return false;\n      }\n\n      if (controlledValue === undefined) {\n        setInternalValue(normalized);\n      }\n\n      onChange?.(normalized);\n      commit?.(normalized);\n      return true;\n    },\n    [controlledValue, onChange, range, value]\n  );\n\n  const updateValue = useCallback(\n    (nextValue: number | [number, number]) => {\n      if (disabled || readOnly) {\n        return false;\n      }\n\n      const normalized = range\n        ? snapRangeValue(\n            Array.isArray(nextValue) ? nextValue : [nextValue, nextValue],\n            resolvedMin,\n            resolvedMax,\n            safeStep\n          )\n        : snapValue(\n            Array.isArray(nextValue)\n              ? (nextValue[0] ?? resolvedMin)\n              : nextValue,\n            resolvedMin,\n            resolvedMax,\n            safeStep\n          );\n\n      return applyResolvedValue(normalized);\n    },\n    [\n      applyResolvedValue,\n      disabled,\n      range,\n      readOnly,\n      resolvedMax,\n      resolvedMin,\n      safeStep,\n    ]\n  );\n\n  const updateRangeThumb = useCallback(\n    (thumbIndex: number, nextThumbValue: number) => {\n      const current = range\n        ? ((controlledValue === undefined ? internalValue : value) as [\n            number,\n            number,\n          ])\n        : [value as number, value as number];\n      const tuple = [...current] as [number, number];\n      tuple[thumbIndex] = snapValue(\n        nextThumbValue,\n        resolvedMin,\n        resolvedMax,\n        safeStep\n      );\n\n      if (tuple[0] > tuple[1]) {\n        if (thumbIndex === 0) {\n          tuple[0] = tuple[1];\n        } else {\n          tuple[1] = tuple[0];\n        }\n      }\n\n      return updateValue(tuple);\n    },\n    [\n      controlledValue,\n      internalValue,\n      range,\n      resolvedMax,\n      resolvedMin,\n      safeStep,\n      updateValue,\n      value,\n    ]\n  );\n\n  const handleValueChange = useCallback(\n    (nextValues: number[]) => {\n      if (disabled || readOnly) {\n        return;\n      }\n\n      const normalized = resolveRadixChangeValue(\n        nextValues,\n        range,\n        inverted,\n        resolvedMin,\n        resolvedMax,\n        safeStep\n      );\n\n      applyResolvedValue(normalized);\n    },\n    [\n      applyResolvedValue,\n      disabled,\n      inverted,\n      range,\n      readOnly,\n      resolvedMax,\n      resolvedMin,\n      safeStep,\n    ]\n  );\n\n  const handleValueCommit = useCallback(\n    (nextValues: number[]) => {\n      if (disabled || readOnly) {\n        return;\n      }\n\n      const normalized = resolveRadixChangeValue(\n        nextValues,\n        range,\n        inverted,\n        resolvedMin,\n        resolvedMax,\n        safeStep\n      );\n\n      onValueCommit?.(normalized);\n    },\n    [\n      disabled,\n      inverted,\n      onValueCommit,\n      range,\n      readOnly,\n      resolvedMax,\n      resolvedMin,\n      safeStep,\n    ]\n  );\n\n  const handleMarkActivate = useCallback(\n    (markValue: number) => {\n      if (disabled || readOnly) {\n        return;\n      }\n\n      if (range) {\n        const current = value as [number, number];\n        const lowDistance = Math.abs(current[0] - markValue);\n        const highDistance = Math.abs(current[1] - markValue);\n        const thumbIndex = lowDistance <= highDistance ? 0 : 1;\n        setActiveThumbIndex(thumbIndex);\n        activeThumbIndexRef.current = thumbIndex;\n\n        if (updateRangeThumb(thumbIndex, markValue)) {\n          onValueCommit?.(\n            snapRangeValue(\n              (() => {\n                const tuple = [...current] as [number, number];\n                tuple[thumbIndex] = snapValue(\n                  markValue,\n                  resolvedMin,\n                  resolvedMax,\n                  safeStep\n                );\n                return tuple;\n              })(),\n              resolvedMin,\n              resolvedMax,\n              safeStep\n            )\n          );\n        }\n\n        return;\n      }\n\n      if (updateValue(markValue)) {\n        onValueCommit?.(\n          snapValue(markValue, resolvedMin, resolvedMax, safeStep)\n        );\n      }\n    },\n    [\n      disabled,\n      onValueCommit,\n      range,\n      readOnly,\n      resolvedMax,\n      resolvedMin,\n      safeStep,\n      updateRangeThumb,\n      updateValue,\n      value,\n    ]\n  );\n\n  const normalizedMarks = (marks ?? [])\n    .map((mark) => ({\n      ...mark,\n      value: clamp(mark.value, resolvedMin, resolvedMax),\n    }))\n    .sort((firstMark, secondMark) => firstMark.value - secondMark.value);\n  const active = isDragging || isHovered || isFocused;\n\n  const thumbClassName = cn(\"block opacity-0 outline-none\", sizeClasses.thumb);\n\n  const getThumbProps = (thumbIndex: number, valueText: string) => ({\n    \"aria-describedby\": fieldMeta.describedBy || undefined,\n    \"aria-invalid\": fieldMeta.showInvalid || undefined,\n    ...(accessibleName.ariaLabelledBy\n      ? { \"aria-labelledby\": accessibleName.ariaLabelledBy }\n      : {\n          \"aria-label\":\n            resolveThumbAccessibleLabel(accessibleName, thumbIndex, range) ??\n            \"Slider\",\n        }),\n    \"aria-readonly\": readOnly || undefined,\n    \"aria-valuetext\": valueText,\n  });\n\n  return (\n    <div\n      className={cn(\n        componentThemeClassName,\n        \"w-full select-none\",\n        disabled && \"cursor-not-allowed opacity-50\",\n        className\n      )}\n    >\n      {(label || showValue) && (\n        <div className=\"mb-3 flex items-baseline justify-between\">\n          {label ? (\n            <span\n              className=\"font-medium text-muted-foreground text-sm tracking-wide\"\n              id={labelId}\n            >\n              {label}\n            </span>\n          ) : null}\n          {showValue ? (\n            <motion.span className=\"font-semibold text-foreground text-sm tabular-nums\">\n              {range ? rangeDisplayValue : singleDisplayValue}\n            </motion.span>\n          ) : null}\n        </div>\n      )}\n\n      <div className=\"relative\">\n        <SliderPrimitive.Root\n          aria-label={\n            accessibleName.ariaLabelledBy ? undefined : accessibleName.ariaLabel\n          }\n          aria-labelledby={accessibleName.ariaLabelledBy}\n          className={cn(\n            \"relative flex w-full cursor-pointer items-center rounded-full outline-none focus-within:outline-2 focus-within:outline-foreground/35 focus-within:outline-offset-4\",\n            sizeClasses.hitAreaHorizontal,\n            (disabled || readOnly) && \"cursor-not-allowed\"\n          )}\n          disabled={disabled}\n          id={fieldMeta.sliderId}\n          max={resolvedMax}\n          min={resolvedMin}\n          minStepsBetweenThumbs={range ? safeStep : undefined}\n          onBlurCapture={(event) => {\n            if (resolveBlurTarget(event.currentTarget, event.relatedTarget)) {\n              setIsFocused(false);\n            }\n          }}\n          onFocusCapture={() => {\n            setIsFocused(true);\n          }}\n          onMouseEnter={() => {\n            setIsHovered(true);\n          }}\n          onMouseLeave={() => {\n            setIsHovered(false);\n          }}\n          onPointerCancelCapture={() => {\n            setIsDragging(false);\n          }}\n          onPointerDownCapture={() => {\n            setIsDragging(true);\n          }}\n          onPointerUpCapture={() => {\n            setIsDragging(false);\n          }}\n          onValueChange={handleValueChange}\n          onValueCommit={handleValueCommit}\n          ref={ref}\n          step={safeStep}\n          style={{ touchAction: \"pan-y\" }}\n          value={radixValue}\n        >\n          <SliderPrimitive.Track className=\"absolute top-1/2 right-0 left-0 h-4 -translate-y-1/2 opacity-0\">\n            <SliderPrimitive.Range className=\"absolute inset-0\" />\n          </SliderPrimitive.Track>\n\n          {range ? (\n            <>\n              <SliderPrimitive.Thumb\n                className={thumbClassName}\n                onPointerDownCapture={() => {\n                  setActiveThumbIndex(0);\n                  activeThumbIndexRef.current = 0;\n                }}\n                {...getThumbProps(0, lowValueText)}\n              />\n              <SliderPrimitive.Thumb\n                className={thumbClassName}\n                onPointerDownCapture={() => {\n                  setActiveThumbIndex(1);\n                  activeThumbIndexRef.current = 1;\n                }}\n                {...getThumbProps(1, highValueText)}\n              />\n            </>\n          ) : (\n            <SliderPrimitive.Thumb\n              className={thumbClassName}\n              {...getThumbProps(0, formattedValueText)}\n            />\n          )}\n\n          <SliderVisualShell\n            active={active}\n            activeThumbIndex={activeThumbIndex}\n            fillLeftPercent={fillLeftPercent}\n            fillSizePercent={fillSizePercent}\n            isDragging={isDragging}\n            isHovered={isHovered}\n            isRange={range}\n            sizeClasses={sizeClasses}\n            thumbPercents={thumbPercents}\n          />\n        </SliderPrimitive.Root>\n\n        {name ? (\n          range ? (\n            <>\n              <input\n                aria-hidden\n                name={`${name}[0]`}\n                tabIndex={-1}\n                type=\"hidden\"\n                value={lowValue}\n              />\n              <input\n                aria-hidden\n                name={`${name}[1]`}\n                tabIndex={-1}\n                type=\"hidden\"\n                value={highValue}\n              />\n            </>\n          ) : (\n            <input\n              aria-hidden\n              name={name}\n              tabIndex={-1}\n              type=\"hidden\"\n              value={value as number}\n            />\n          )\n        ) : null}\n\n        <SliderMarks\n          disabled={disabled}\n          inverted={inverted}\n          isRtl={isRtl}\n          marks={normalizedMarks}\n          marksInteractive={marksInteractive}\n          onMarkActivate={handleMarkActivate}\n          rangeSpan={rangeSpan}\n          readOnly={readOnly}\n          resolvedMin={resolvedMin}\n        />\n      </div>\n\n      <SliderFieldMessages\n        description={description}\n        descriptionId={fieldMeta.descriptionId}\n        errorId={fieldMeta.errorId}\n        errorMessage={errorMessage}\n      />\n    </div>\n  );\n});\n\nexport { Slider as slider };\n",
      "type": "registry:ui"
    }
  ],
  "title": "Slider (Radix UI)",
  "description": "Slider with the same Iconiq API layered over Radix UI primitives, preserving the original spring-settled fill, active track height, and thumb scale motion."
}
