{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "elastic-slider",
  "type": "registry:ui",
  "title": "Elastic slider",
  "description": "A slider that stretches like rubber past its ends, with a swaying value tag and detents the thumb clicks into.",
  "categories": [
    "inputs"
  ],
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://irisui.dev/r/foundation.json",
    "https://irisui.dev/r/motion-tokens.json",
    "https://irisui.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "src/registry/components/elastic-slider/elastic-slider.tsx",
      "content": "\"use client\";\n\nimport {\n  useEffect,\n  useId,\n  useLayoutEffect,\n  useRef,\n  useState,\n  type KeyboardEvent,\n  type PointerEvent,\n  type ReactNode,\n} from \"react\";\nimport {\n  AnimatePresence,\n  animate,\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n  useTransform,\n  useVelocity,\n  type MotionStyle,\n} from \"motion/react\";\nimport { motionTokens } from \"../lib/motion-tokens\";\nimport { cn } from \"../lib/utils\";\n\nexport interface ElasticSliderMark {\n  value: number;\n  label?: string;\n}\n\nexport interface ElasticSliderProps {\n  /** Visible label; it also names the thumb. */\n  label: string;\n  value?: number;\n  defaultValue?: number;\n  onValueChange?: (value: number) => void;\n  /** Runs once a drag is released or a key changes the value. */\n  onValueCommit?: (value: number) => void;\n  min?: number;\n  max?: number;\n  step?: number;\n  /** PageUp, PageDown, and Shift with an arrow move this far. Defaults to a tenth of the range. */\n  largeStep?: number;\n  /** Detents. A dragged thumb clicks into each one and holds for a few pixels before letting go. Labels print under the track. */\n  marks?: (number | ElasticSliderMark)[];\n  /** Formats the readout, the bubble, and the spoken value. */\n  format?: (value: number) => string;\n  /** Show the value beside the label. The bubble over the thumb still appears while dragging or using keys. */\n  showValue?: boolean;\n  /** Icons at either end. The one on the side being pulled past its limit is pushed outward with the track. */\n  startIcon?: ReactNode;\n  endIcon?: ReactNode;\n  /** Submits the value with a form. */\n  name?: string;\n  disabled?: boolean;\n  className?: string;\n}\n\ntype Drag = {\n  pointer: number;\n  grab: number;\n  samples: { t: number; p: number }[];\n  detent: number | null;\n  edge: number;\n  type: string;\n};\n\nconst { spring, duration, blur } = motionTokens;\nconst enterEase = [...motionTokens.ease.enter] as [number, number, number, number];\nconst exitEase = [...motionTokens.ease.standard] as [number, number, number, number];\n/** Motion drops velocity on time-defined springs, so anything a gesture hands off to runs the same spring written as stiffness and damping. */\nconst physical = ({ visualDuration, bounce }: { visualDuration: number; bounce: number }, restDelta = 0.002) => {\n  const root = (2 * Math.PI) / (visualDuration * 1.2);\n  return {\n    type: \"spring\" as const,\n    stiffness: root * root,\n    damping: 2 * (1 - bounce) * root,\n    restDelta,\n    restSpeed: restDelta * 10,\n  };\n};\nconst thumbSpring = physical(spring.snappy);\n/** The stretch lets go with more life than anything else here: it is the one thing the user threw. */\nconst snapBack = physical({ visualDuration: 0.5, bounce: 0.42 }, 0.05);\n/** Pixels the track may stretch past a limit, the pixel reach of a detent, and the speed a key press at a limit hits the wall with. */\nconst STRETCH = 26,\n  DETENT_PX = 7,\n  BUMP_PX = 260;\n/** Rubber-band resistance, as in overscroll: each pixel past the limit gives less, and never more than `limit`. */\nconst rubber = (distance: number, limit = STRETCH) =>\n  Math.sign(distance) * (1 - 1 / ((Math.abs(distance) * 0.55) / limit + 1)) * limit;\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\nconst decimalsOf = (value: number) => (String(value).split(\".\")[1] ?? \"\").length;\n\nconst bubbleIn = { opacity: 0, scale: 0.7, y: 6, filter: `blur(${blur.subtle}px)` };\nconst bubbleRest = { opacity: 1, scale: 1, y: 0, filter: \"blur(0px)\", transitionEnd: { filter: \"none\" } };\nconst bubbleOut = {\n  opacity: 0,\n  scale: 0.85,\n  y: 4,\n  filter: `blur(${blur.subtle}px)`,\n  transition: { duration: duration.instant, ease: exitEase },\n};\nconst bubbleEnter = {\n  ...spring.snappy,\n  opacity: { duration: duration.fast, ease: enterEase },\n  filter: { duration: duration.fast, ease: enterEase },\n};\n\n/**\n * A single value slider made of something that gives. The thumb swells under the finger, the track stretches like rubber past either\n * end and springs back with the release velocity, a value tag hangs off the thumb and sways with its speed, and marks act as detents\n * the thumb clicks into. Arrows, Shift+arrows, PageUp, PageDown, Home, and End work as in a native range input.\n * Set `--elastic-thumb` and `--elastic-track` on the root to resize. While the tag rides the thumb it carries the value, so the readout\n * beside the label steps back.\n */\nexport function ElasticSlider({\n  label,\n  value,\n  defaultValue,\n  onValueChange,\n  onValueCommit,\n  min = 0,\n  max = 100,\n  step: stepProp = 1,\n  largeStep,\n  marks,\n  format,\n  showValue = true,\n  startIcon,\n  endIcon,\n  name,\n  disabled,\n  className,\n}: ElasticSliderProps) {\n  const reduced = useReducedMotion() ?? false;\n  const labelId = useId();\n  const step = stepProp > 0 ? stepProp : 1;\n  const span = max - min || 1;\n  const decimals = Math.max(decimalsOf(step), decimalsOf(min));\n  const [internal, setInternal] = useState(() => clamp(defaultValue ?? min, min, max));\n  const current = value === undefined ? internal : clamp(value, min, max);\n  const formatValue =\n    format ??\n    ((input: number) =>\n      input.toLocaleString(\"en-US\", { minimumFractionDigits: decimals, maximumFractionDigits: decimals }));\n  const pct = (input: number) => ((input - min) / span) * 100;\n  const valueAt = (percent: number) => min + (percent / 100) * span;\n  const snap = (input: number) =>\n    clamp(Number((min + Math.round((input - min) / step) * step).toFixed(decimals)), min, max);\n  const markList = (marks ?? [])\n    .map((mark) => (typeof mark === \"number\" ? ({ value: mark } as ElasticSliderMark) : mark))\n    .filter((mark) => mark.value >= min && mark.value <= max);\n\n  const trackRef = useRef<HTMLDivElement>(null);\n  const thumbRef = useRef<HTMLDivElement>(null);\n  const tickRefs = useRef(new Map<number, HTMLSpanElement>());\n  const latest = useRef(current);\n  const goal = useRef(pct(current));\n  const drag = useRef<Drag | null>(null);\n  const width = useRef(1);\n  const lingerTimer = useRef<number | undefined>(undefined);\n  const [dragging, setDragging] = useState(false);\n  const [keyed, setKeyed] = useState(false);\n  const [linger, setLinger] = useState(false);\n\n  // The thumb is a committed position plus a catch-up offset, so it can glide into a detent or to a pressed spot while the pointer\n  // keeps moving the position 1:1. `over` is the rubber-band stretch in pixels, signed by side.\n  const pos = useMotionValue(pct(current));\n  const lag = useMotionValue(0);\n  const over = useMotionValue(0);\n  const press = useMotionValue(0);\n  const shown = useTransform(() => pos.get() + lag.get());\n  const thumbX = useTransform(shown, (at) => `${at - 100}%`);\n  const clipPath = useTransform(shown, (at) => `inset(0 ${(100 - clamp(at, 0, 100)).toFixed(3)}% 0 0 round 999px)`);\n  // Stretch: the track grows away from its anchored end and thins as it does, like a band pulled tight. A press thickens it a little.\n  const scaleX = useTransform(over, (px) => 1 + Math.abs(px) / width.current);\n  const originX = useTransform(over, (px) => (px < 0 ? 1 : 0));\n  const scaleY = useTransform(() => (1 + press.get() * 0.45) * (1 - (Math.abs(over.get()) / STRETCH) * 0.32));\n  const startShift = useTransform(over, (px) => Math.min(0, px));\n  const endShift = useTransform(over, (px) => Math.max(0, px));\n  // The tag trails the thumb on a soft spring, so it lags more the faster the thumb moves, and swings on its tail with that speed.\n  const trailed = useSpring(shown, { stiffness: 420, damping: 30, mass: 0.7 });\n  const bubbleAt = reduced ? shown : trailed;\n  const bubbleX = useTransform(bubbleAt, (at) => `${at - 100}%`);\n  const speed = useVelocity(trailed);\n  const rotate = useTransform(speed, (velocity) =>\n    reduced ? 0 : clamp((-velocity / 100) * width.current * 0.009, -11, 11),\n  );\n\n  const emit = (next: number) => {\n    if (latest.current === next) return;\n    latest.current = next;\n    if (value === undefined) setInternal(next);\n    onValueChange?.(next);\n  };\n\n  // Values from outside a drag (keys, props) spring the thumb to their place from wherever it is on screen.\n  useLayoutEffect(() => {\n    latest.current = current;\n    const target = pct(current);\n    if (drag.current || goal.current === target) return;\n    goal.current = target;\n    const from = pos.get() + lag.get();\n    lag.jump(0);\n    pos.jump(from);\n    if (reduced) pos.jump(target);\n    else animate(pos, target, thumbSpring);\n  });\n  useEffect(() => {\n    const node = trackRef.current;\n    if (!node || typeof ResizeObserver === \"undefined\") return;\n    const observer = new ResizeObserver(([entry]) => {\n      if (entry) width.current = entry.contentRect.width || 1;\n    });\n    observer.observe(node);\n    return () => observer.disconnect();\n  }, []);\n  useEffect(() => () => window.clearTimeout(lingerTimer.current), []);\n\n  /** A detent answers with a small pop of its tick and, where the device supports it, a short tap of vibration. */\n  function pulse(mark: number, haptic: boolean) {\n    const node = tickRefs.current.get(mark);\n    if (node && !reduced) animate(node, { scale: [1, 2.1, 1] }, { duration: 0.34, ease: enterEase });\n    if (haptic && typeof navigator !== \"undefined\" && \"vibrate\" in navigator) navigator.vibrate?.(6);\n  }\n  /** Moves the thumb to a new resting spot through a spring on the catch-up offset, so the jump reads as travel. */\n  function glide(placed: number) {\n    const from = pos.get() + lag.get();\n    pos.set(placed);\n    if (reduced) {\n      lag.jump(0);\n      return;\n    }\n    lag.jump(from - placed);\n    animate(lag, 0, thumbSpring);\n  }\n  const detentAt = (percent: number) => {\n    let best: number | null = null,\n      gap = DETENT_PX + 1;\n    for (const mark of markList) {\n      const distance = Math.abs(((percent - pct(mark.value)) / 100) * width.current);\n      if (distance <= DETENT_PX && distance < gap) {\n        best = mark.value;\n        gap = distance;\n      }\n    }\n    return best;\n  };\n\n  function follow(state: Drag, at: number, time: number, first = false) {\n    const raw = at - state.grab;\n    const edge = clamp(raw, 0, 100);\n    over.set(reduced ? 0 : rubber(((raw - edge) / 100) * width.current));\n    const detent = detentAt(edge);\n    const placed = detent === null ? edge : pct(detent);\n    if (first || detent !== state.detent) {\n      if (detent !== null && !first) pulse(detent, state.type === \"touch\");\n      glide(placed);\n    } else pos.set(placed);\n    state.detent = detent;\n    state.edge = edge;\n    state.samples.push({ t: time, p: placed });\n    if (state.samples.length > 6) state.samples.shift();\n    emit(detent ?? snap(valueAt(edge)));\n  }\n\n  function onPointerDown(event: PointerEvent<HTMLDivElement>) {\n    if (disabled || event.button !== 0 || !event.isPrimary) return;\n    const rect = trackRef.current?.getBoundingClientRect();\n    if (!rect) return;\n    width.current = rect.width || 1;\n    const at = ((event.clientX - rect.left) / width.current) * 100;\n    const grabbed = !!(event.target as HTMLElement).closest(\"[data-thumb]\");\n    event.currentTarget.setPointerCapture(event.pointerId);\n    const from = pos.get() + lag.get();\n    lag.jump(0);\n    pos.jump(from);\n    const state: Drag = {\n      pointer: event.pointerId,\n      grab: grabbed ? at - from : 0,\n      samples: [],\n      detent: null,\n      edge: from,\n      type: event.pointerType,\n    };\n    drag.current = state;\n    setDragging(true);\n    window.clearTimeout(lingerTimer.current);\n    setLinger(false);\n    thumbRef.current?.focus({ preventScroll: true });\n    if (reduced) press.jump(1);\n    else animate(press, 1, spring.snappy);\n    // A grabbed thumb stays put under the finger; a pressed track pulls the thumb over on a spring.\n    follow(state, grabbed ? from + state.grab : at, event.timeStamp, true);\n  }\n  function onPointerMove(event: PointerEvent<HTMLDivElement>) {\n    const state = drag.current;\n    if (!state || state.pointer !== event.pointerId) return;\n    const rect = trackRef.current?.getBoundingClientRect();\n    if (!rect) return;\n    follow(state, ((event.clientX - rect.left) / (rect.width || 1)) * 100, event.timeStamp);\n  }\n  function onPointerEnd(event: PointerEvent<HTMLDivElement>) {\n    const state = drag.current;\n    if (!state || state.pointer !== event.pointerId) return;\n    drag.current = null;\n    const samples = state.samples,\n      first = samples[0],\n      last = samples[samples.length - 1];\n    const elapsed = last && first ? (last.t - first.t) / 1000 : 0;\n    const velocity =\n      (elapsed > 0.008 && event.timeStamp - last!.t < 60 ? (last!.p - first!.p) / elapsed : 0) + lag.getVelocity();\n    const next = state.detent ?? snap(valueAt(state.edge));\n    const from = pos.get() + lag.get(),\n      target = pct(next);\n    lag.jump(0);\n    pos.jump(from);\n    goal.current = target;\n    if (reduced) {\n      pos.jump(target);\n      over.jump(0);\n      press.jump(0);\n    } else {\n      animate(pos, target, { ...thumbSpring, velocity });\n      animate(over, 0, { ...snapBack, velocity: over.getVelocity() });\n      animate(press, 0, spring.snappy);\n    }\n    emit(next);\n    setDragging(false);\n    setLinger(true);\n    lingerTimer.current = window.setTimeout(() => setLinger(false), 700);\n    onValueCommit?.(next);\n  }\n\n  function onKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n    if (disabled) return;\n    const now = latest.current;\n    const large = largeStep ?? Math.max(step, snap(min + span / 10) - min);\n    const moves: Record<string, number> = {\n      ArrowRight: step,\n      ArrowUp: step,\n      ArrowLeft: -step,\n      ArrowDown: -step,\n      PageUp: large,\n      PageDown: -large,\n    };\n    let wanted: number;\n    if (event.key === \"Home\") wanted = min;\n    else if (event.key === \"End\") wanted = max;\n    else if (event.key in moves)\n      wanted =\n        now +\n        (event.shiftKey && event.key.startsWith(\"Arrow\") ? Math.sign(moves[event.key]!) * large : moves[event.key]!);\n    else return;\n    event.preventDefault();\n    setKeyed(true);\n    const next = snap(wanted);\n    // At a limit the track still stretches toward the press and snaps back, so the key visibly lands on something.\n    if (next === now) {\n      const toward = Math.sign(wanted - now);\n      if (toward && !reduced) animate(over, 0, { ...snapBack, velocity: toward * BUMP_PX });\n      return;\n    }\n    emit(next);\n    if (markList.some((mark) => mark.value === next)) pulse(next, false);\n    onValueCommit?.(next);\n  }\n\n  const text = formatValue(current);\n  const labelled = markList.filter((mark) => mark.label);\n  const bubble = dragging || keyed || linger;\n\n  return (\n    <div\n      className={cn(\n        \"group/elastic grid w-full min-w-0 gap-2 text-sm leading-body tracking-body text-ink select-none [--elastic-thumb:24px] [--elastic-track:8px] data-disabled:opacity-50 data-dragging:cursor-grabbing\",\n        className,\n      )}\n      data-disabled={disabled || undefined}\n      data-dragging={dragging || undefined}\n      data-tag={bubble || undefined}\n      data-marks={labelled.length > 0 || undefined}\n    >\n      <div className=\"flex min-w-0 items-baseline justify-between gap-4\">\n        <span id={labelId} className=\"min-w-0 font-medium\">\n          {label}\n        </span>\n        {showValue && (\n          <span\n            className=\"flex-none whitespace-nowrap text-ink-2 tabular-nums transition-opacity duration-fast ease-standard group-data-tag/elastic:opacity-0\"\n            aria-hidden=\"true\"\n          >\n            {text}\n          </span>\n        )}\n      </div>\n      <div className=\"grid grid-cols-[auto_minmax(0,1fr)_auto] items-center\">\n        {startIcon && (\n          <motion.span\n            className=\"mr-3 flex text-ink-3 will-change-transform [grid-area:1/1]\"\n            style={{ x: startShift }}\n            aria-hidden=\"true\"\n          >\n            {startIcon}\n          </motion.span>\n        )}\n        {/* oxlint-disable-next-line jsx-a11y/no-static-element-interactions -- the pointer surface around the track; keyboard access lives on the role=\"slider\" thumb */}\n        <div\n          className=\"relative h-control-md cursor-pointer touch-pan-y [grid-area:1/2] [-webkit-tap-highlight-color:transparent] group-data-dragging/elastic:cursor-grabbing group-data-disabled/elastic:cursor-not-allowed\"\n          onPointerDown={onPointerDown}\n          onPointerMove={onPointerMove}\n          onPointerUp={onPointerEnd}\n          onPointerCancel={onPointerEnd}\n          onLostPointerCapture={onPointerEnd}\n          onMouseDown={(event) => event.preventDefault()}\n        >\n          <div\n            ref={trackRef}\n            className=\"absolute top-1/2 right-[calc(var(--elastic-thumb)/2)] left-[calc(var(--elastic-thumb)/2)] mt-[calc(var(--elastic-track)/-2)] h-(--elastic-track)\"\n          >\n            <motion.div\n              className=\"absolute inset-0 rounded-full bg-control-track will-change-transform\"\n              style={{ scaleX, scaleY, originX }}\n            >\n              <motion.div className=\"absolute inset-0 rounded-[inherit] bg-control-fill\" style={{ clipPath }} />\n            </motion.div>\n            {markList\n              .filter((mark) => mark.value > min && mark.value < max)\n              .map((mark) => (\n                <span\n                  key={mark.value}\n                  ref={(node) => {\n                    if (node) tickRefs.current.set(mark.value, node);\n                    else tickRefs.current.delete(mark.value);\n                  }}\n                  className=\"pointer-events-none absolute top-1/2 -mt-0.5 -ml-0.5 size-1 rounded-full bg-[color-mix(in_oklab,var(--ink)_32%,transparent)] transition-[background-color] duration-fast ease-standard data-on:bg-[color-mix(in_oklab,var(--control-glyph)_60%,transparent)] motion-reduce:transition-none\"\n                  data-on={mark.value <= current || undefined}\n                  style={{ left: `${pct(mark.value)}%` }}\n                />\n              ))}\n          </div>\n          <div className=\"pointer-events-none absolute inset-x-[calc(var(--elastic-thumb)/2)] inset-y-0 @container\">\n            <motion.div className=\"absolute inset-0\" style={{ x: bubbleX }}>\n              {/* The tag centers on the thumb until it would pass the component's edge, then holds there; it hangs from its bottom edge, so a swing pivots on the thumb. */}\n              <motion.span\n                className=\"pointer-events-none absolute right-0 bottom-[calc(50%_+_var(--elastic-thumb)/2_+_10px)] flex [--edge:calc(var(--elastic-thumb)/2)] [--x:calc(var(--at,0)*1cqw)] [translate:clamp(calc(100%_-_var(--edge)_-_var(--x)),50%,calc(100cqw_+_var(--edge)_-_var(--x)))_0] pointer-coarse:bottom-[calc(50%_+_var(--elastic-thumb)/2_+_20px)]\"\n                style={{ x: over, \"--at\": bubbleAt } as MotionStyle}\n              >\n                <AnimatePresence>\n                  {bubble && (\n                    <motion.span\n                      key=\"bubble\"\n                      className=\"inline-flex min-h-7 origin-[50%_130%] items-center rounded-full bg-ink px-3 text-sm/[inherit] font-medium whitespace-nowrap text-page tabular-nums shadow-raised\"\n                      aria-hidden=\"true\"\n                      style={{ rotate }}\n                      initial={reduced ? { opacity: 0 } : bubbleIn}\n                      animate={bubbleRest}\n                      exit={reduced ? { opacity: 0, transition: { duration: duration.instant } } : bubbleOut}\n                      transition={reduced ? { duration: 0.15 } : bubbleEnter}\n                    >\n                      {text}\n                    </motion.span>\n                  )}\n                </AnimatePresence>\n              </motion.span>\n            </motion.div>\n            <motion.div className=\"absolute inset-0\" style={{ x: thumbX }}>\n              <motion.div className=\"absolute inset-0\" style={{ x: over }}>\n                <motion.div\n                  ref={thumbRef}\n                  role=\"slider\"\n                  data-thumb=\"\"\n                  className=\"pointer-events-auto absolute top-1/2 right-0 box-border size-(--elastic-thumb) cursor-grab rounded-full border-0 bg-control-thumb shadow-thumb outline-none transition-shadow duration-fast ease-standard [translate:50%_-50%] group-data-dragging/elastic:cursor-grabbing group-data-disabled/elastic:cursor-not-allowed motion-reduce:transition-none after:absolute after:-inset-3 after:rounded-[inherit] after:content-['']\"\n                  tabIndex={disabled ? -1 : 0}\n                  aria-labelledby={labelId}\n                  aria-valuemin={min}\n                  aria-valuemax={max}\n                  aria-valuenow={current}\n                  aria-valuetext={text}\n                  aria-orientation=\"horizontal\"\n                  aria-disabled={disabled || undefined}\n                  initial={false}\n                  animate={{ scale: dragging ? 1.28 : 1 }}\n                  transition={reduced ? { duration: 0 } : spring.snappy}\n                  onKeyDown={onKeyDown}\n                  onBlur={() => setKeyed(false)}\n                />\n              </motion.div>\n            </motion.div>\n          </div>\n        </div>\n        {endIcon && (\n          <motion.span\n            className=\"ml-3 flex text-ink-3 will-change-transform [grid-area:1/3]\"\n            style={{ x: endShift }}\n            aria-hidden=\"true\"\n          >\n            {endIcon}\n          </motion.span>\n        )}\n        {labelled.length > 0 && (\n          <div\n            className=\"relative mx-[calc(var(--elastic-thumb)/2)] h-5 text-xs/[inherit] text-ink-3 tabular-nums [grid-area:2/2]\"\n            aria-hidden=\"true\"\n          >\n            {labelled.map((mark) => (\n              // oxlint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- mark labels are aria-hidden pointer shortcuts; keys reach every value through the thumb\n              <span\n                key={mark.value}\n                className=\"absolute top-0 cursor-pointer whitespace-nowrap transition-[color] duration-fast ease-standard [translate:-50%_0] hover:text-ink data-on:text-ink data-[edge=end]:[translate:min(-50%,calc(-100%_+_var(--elastic-thumb)/2))_0] data-[edge=start]:[translate:max(-50%,calc(var(--elastic-thumb)/-2))_0] group-data-disabled/elastic:cursor-not-allowed motion-reduce:transition-none\"\n                data-on={mark.value === current || undefined}\n                data-edge={mark.value === min ? \"start\" : mark.value === max ? \"end\" : undefined}\n                style={{ left: `${pct(mark.value)}%` }}\n                onClick={() => {\n                  if (disabled || mark.value === latest.current) return;\n                  emit(mark.value);\n                  pulse(mark.value, false);\n                  onValueCommit?.(mark.value);\n                }}\n              >\n                {mark.label}\n              </span>\n            ))}\n          </div>\n        )}\n      </div>\n      {name && <input type=\"hidden\" name={name} value={current} disabled={disabled} />}\n    </div>\n  );\n}\n\nexport default ElasticSlider;\n",
      "type": "registry:component",
      "target": "@components/iris/elastic-slider/elastic-slider.tsx"
    }
  ],
  "docs": "Docs and live preview: https://irisui.dev/components/elastic-slider",
  "meta": {
    "kind": "component",
    "group": "Inputs",
    "export": "ElasticSlider",
    "tags": [
      "inputs",
      "new"
    ],
    "docs": "https://irisui.dev/components/elastic-slider"
  }
}
