{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "slider",
  "title": "Slider",
  "description": "Range input with one or more thumbs, built on Radix.",
  "dependencies": [
    "radix-ui@^1.6.7"
  ],
  "registryDependencies": [
    "@pestoui/style",
    "@pestoui/utils"
  ],
  "files": [
    {
      "path": "pestoui/ui/slider.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Slider as SliderPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Slider({\n  className,\n  defaultValue,\n  value,\n  min = 0,\n  max = 100,\n  disabled,\n  onPointerDown,\n  \"aria-label\": ariaLabel,\n  ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\n  const _values = React.useMemo(\n    () =>\n      Array.isArray(value)\n        ? value\n        : Array.isArray(defaultValue)\n          ? defaultValue\n          : [min, max],\n    [value, defaultValue, min, max]\n  )\n\n  /* What the pointer is holding: a thumb index while a thumb is grabbed, -1\n     while the track itself is being dragged, null when idle.\n\n     Tracked in state rather than read off `:active`, though not because the\n     mouse loses it: measured in Chromium (headed and headless, real mouse),\n     the root and the thumb both keep `:active` through a drag that leaves the\n     control by 400px. State is used because the one thing that must never\n     happen here is the glide switching itself back on halfway through a\n     drag, and touch and pen were not measured — state does not depend on the\n     engine setting `:active` at all.\n\n     A disabled slider never grabs. The primitive ignores the press, but these\n     handlers run regardless, and without the guard the disabled thumb grew to\n     `scale-125` while the root shook its head (measured: thumb scale 1.188 at\n     100ms into a held press) — a \"yes\" and a \"no\" at once. */\n  const [grabbed, setGrabbed] = React.useState<number | null>(null)\n  const dragging = grabbed !== null\n\n  React.useEffect(() => {\n    if (!dragging) return\n    const release = () => setGrabbed(null)\n    window.addEventListener(\"pointerup\", release)\n    window.addEventListener(\"pointercancel\", release)\n    return () => {\n      window.removeEventListener(\"pointerup\", release)\n      window.removeEventListener(\"pointercancel\", release)\n    }\n  }, [dragging])\n\n  return (\n    <SliderPrimitive.Root\n      data-slot=\"slider\"\n      defaultValue={defaultValue}\n      value={value}\n      min={min}\n      max={max}\n      className={cn(\n        \"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col\",\n        /* A disabled slider shakes its head when pressed, the same answer the\n           Switch gives, rather than swallowing the press in silence. It sits on\n           the root because every press lands inside it. The root is a span with\n           no `disabled` attribute and no `pointer-events-none`, and although the\n           primitive default-prevents pointerdown, nothing moves focus during\n           the press, so `:active` holds: measured in headed and headless\n           Chromium with the mouse held, on the track and on the thumb, two\n           presses each, `:active` matched on every frame and `nudge` ran.\n\n           This is the only piece of the Switch's grammar the slider takes:\n           - No press lean or squeeze. Grabbing already lifts the thumb\n             (`scale-125`), which is the right press for something held and\n             dragged; a squeeze would argue with it.\n           - No overshoot. The thumb's position is the value, so a bounce past\n             it shows a number nobody chose and pulls the thumb off the end of\n             the range fill.\n           - No arrival squish. The thumb glides on the overdamped spring and\n             has no moment of arrival for a squish to land on. */\n        \"data-disabled:active:animate-nudge\",\n        /* Each thumb is positioned on a wrapper span the primitive owns, so the\n           glide has to be reached from here. Arrow keys travel; a live drag\n           opts out, or the thumb trails the pointer. */\n        !dragging &&\n          \"[&>span:has(>[data-slot=slider-thumb])]:transition-[inset] [&>span:has(>[data-slot=slider-thumb])]:duration-spring-glide [&>span:has(>[data-slot=slider-thumb])]:ease-spring-glide\",\n        className\n      )}\n      disabled={disabled}\n      {...props}\n      onPointerDown={(event) => {\n        onPointerDown?.(event)\n        if (disabled) return\n        /* A thumb's own handler runs first and wins; -1 only lands when the\n           press started on the track. */\n        setGrabbed((current) => current ?? -1)\n      }}\n    >\n      <SliderPrimitive.Track\n        data-slot=\"slider-track\"\n        className=\"relative grow overflow-hidden rounded-full bg-secondary data-horizontal:h-1.5 data-horizontal:w-full data-vertical:h-full data-vertical:w-1.5\"\n      >\n        <SliderPrimitive.Range\n          data-slot=\"slider-range\"\n          className={cn(\n            \"absolute bg-selected select-none data-horizontal:h-full data-vertical:w-full\",\n            !dragging &&\n              \"transition-[inset] duration-spring-glide ease-spring-glide\"\n          )}\n        />\n      </SliderPrimitive.Track>\n      {Array.from({ length: _values.length }, (_, index) => (\n        <SliderPrimitive.Thumb\n          data-slot=\"slider-thumb\"\n          key={index}\n          /* The thumb is the role=\"slider\" element, so the label belongs on it;\n             on the root span it named nothing. A range keeps the primitive's\n             own \"Minimum\" / \"Maximum\" per thumb unless a label is given. */\n          aria-label={\n            ariaLabel && _values.length > 1\n              ? `${ariaLabel}, ${index === 0 ? \"minimum\" : \"maximum\"}`\n              : ariaLabel\n          }\n          onPointerDown={() => {\n            if (!disabled) setGrabbed(index)\n          }}\n          className={cn(\n            \"relative block size-5 shrink-0 rounded-full border-2 border-selected bg-card shadow-soft ring-selected/40 transition-[color,box-shadow,scale] duration-base ease-out-expo select-none after:absolute after:-inset-2 hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden active:ring-4 disabled:pointer-events-none disabled:opacity-50\",\n            /* Grabbing springs out; letting go returns on the rest-state tween,\n               because these classes come off with the grab. */\n            grabbed === index &&\n              \"scale-125 ring-4 duration-spring-press ease-spring-press\"\n          )}\n        />\n      ))}\n    </SliderPrimitive.Root>\n  )\n}\n\nexport { Slider }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}