{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "motion-number-input",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "./registry/components/motion-number/motion-number-input.tsx",
      "content": "'use client';\nimport { cn } from '@/lib/utils';\nimport NumberFlow from '@number-flow/react';\nimport { Minus, Plus } from 'lucide-react';\nimport * as React from 'react';\n\ntype Props = {\n  value?: number;\n  min?: number;\n  max?: number;\n  onChange?: (value: number) => void;\n};\n\nexport function Input({\n  value = 0,\n  min = Number.NEGATIVE_INFINITY,\n  max = Number.POSITIVE_INFINITY,\n  onChange,\n}: Props) {\n  const defaultValue = React.useRef(value);\n  const inputRef = React.useRef<HTMLInputElement>(null);\n  const [animated, setAnimated] = React.useState(true);\n  // Hide the caret during transitions so you can't see it shifting around:\n  const [showCaret, setShowCaret] = React.useState(true);\n\n  const handleInput: React.ChangeEventHandler<HTMLInputElement> = ({ currentTarget: el }) => {\n    setAnimated(false);\n    if (el.value === '') {\n      onChange?.(defaultValue.current);\n      return;\n    }\n    const num = Number.parseInt(el.value);\n    if (isNaN(num) || (min != null && num < min) || (max != null && num > max)) {\n      // Revert input's value:\n      el.value = String(value);\n    } else {\n      // Manually update value in case they e.g. start with a \"0\" or end with a \".\"\n      // which won't trigger a DOM update (because the number is the same):\n      el.value = String(num);\n      onChange?.(num);\n    }\n  };\n\n  const handlePointerDown = (diff: number) => (event: React.PointerEvent<HTMLButtonElement>) => {\n    setAnimated(true);\n    if (event.pointerType === 'mouse') {\n      event?.preventDefault();\n      inputRef.current?.focus();\n    }\n    const newVal = Math.min(Math.max(value + diff, min), max);\n    onChange?.(newVal);\n  };\n\n  return (\n    <div className='group flex items-stretch rounded-md text-3xl font-semibold border w-fit mx-auto dark:bg-neutral-950 bg-neutral-50'>\n      <button\n        aria-hidden\n        tabIndex={-1}\n        className='flex items-center pl-[.5em] pr-[.325em]'\n        disabled={min != null && value <= min}\n        onPointerDown={handlePointerDown(-1)}\n      >\n        <Minus className='size-4' absoluteStrokeWidth strokeWidth={3.5} />\n      </button>\n      <div className=\"relative grid items-center justify-items-center text-center [grid-template-areas:'overlap'] *:[grid-area:overlap]\">\n        <input\n          ref={inputRef}\n          className={cn(\n            showCaret ? 'caret-primary' : 'caret-transparent',\n            'spin-hide w-[1.5em] bg-transparent py-2 text-center font-[inherit] text-transparent outline-hidden appearance-none'\n          )}\n          // Make sure to disable kerning, to match NumberFlow:\n          style={{ fontKerning: 'none' }}\n          type='number'\n          min={min}\n          step={1}\n          autoComplete='off'\n          inputMode='numeric'\n          max={max}\n          value={value}\n          onInput={handleInput}\n        />\n        <NumberFlow\n          value={value}\n          format={{ useGrouping: false }}\n          aria-hidden\n          animated={animated}\n          onAnimationsStart={() => setShowCaret(false)}\n          onAnimationsFinish={() => setShowCaret(true)}\n          className='pointer-events-none'\n          willChange\n        />\n      </div>\n      <button\n        aria-hidden\n        tabIndex={-1}\n        className='flex items-center pl-[.325em] pr-[.5em]'\n        disabled={max != null && value >= max}\n        onPointerDown={handlePointerDown(1)}\n      >\n        <Plus className='size-4' absoluteStrokeWidth strokeWidth={3.5} />\n      </button>\n    </div>\n  );\n}\n\nexport default function MotionNumberInput() {\n  const [value, setValue] = React.useState(0);\n  return (\n    <>\n      <Input value={value} min={0} max={99} onChange={setValue} />\n    </>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}