{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "number-input",
  "title": "Number Input",
  "description": "Numeric input with increment and decrement buttons and min/max/step.",
  "dependencies": [
    "lucide-react@^1.48.0"
  ],
  "registryDependencies": [
    "https://rdf.dev.360online.com/r/input-group.json"
  ],
  "files": [
    {
      "path": "registry/rapid/ui/number-input/number-input.tsx",
      "content": "'use client'\n\nimport { MinusIcon, PlusIcon } from 'lucide-react'\nimport * as React from 'react'\nimport { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'\nimport { cn } from '@/lib/utils'\n\nexport interface NumberInputProps\n\textends Omit<React.ComponentProps<'input'>, 'onChange' | 'defaultValue' | 'value' | 'min' | 'max'> {\n\tvalue?: number\n\tonChange?: (value: number) => void\n\tmin?: number\n\tmax?: number\n\tdefaultValue?: number | string\n}\n\nfunction NumberInput({\n\tclassName,\n\tonChange,\n\tvalue,\n\tmin = 0,\n\tmax = 10,\n\tdefaultValue = 0,\n\tdisabled = false,\n\tonKeyDown,\n\t...props\n}: Readonly<NumberInputProps>) {\n\tconst [internalValue, setInternalValue] = React.useState<number>(Number(defaultValue))\n\tconst currentValue = value ?? internalValue\n\n\tconst commit = (next: number) => {\n\t\tonChange?.(next)\n\t\tsetInternalValue(next)\n\t}\n\n\tconst handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst parsed = event.target.value === '' ? 0 : Number.parseInt(event.target.value, 10)\n\t\tconst next = Number.isNaN(parsed) ? 0 : parsed\n\t\tcommit(Math.min(max, Math.max(min, next)))\n\t}\n\n\tconst increment = () => {\n\t\tconst next = currentValue + 1\n\t\tif (next > max) return\n\t\tcommit(next)\n\t}\n\n\tconst decrement = () => {\n\t\tconst next = currentValue - 1\n\t\tif (next < min) return\n\t\tcommit(next)\n\t}\n\n\treturn (\n\t\t<InputGroup\n\t\t\tdata-slot=\"number-input\"\n\t\t\tdata-disabled={disabled || undefined}\n\t\t\t// The steppers disable themselves at min/max; only dim the group when the whole input is disabled.\n\t\t\tclassName=\"has-[[data-slot=input-group-control]:read-only]:border-solid has-[[data-slot=input-group-control]:read-only]:bg-transparent has-disabled:bg-transparent has-disabled:opacity-100 data-disabled:opacity-50 dark:bg-transparent dark:has-disabled:bg-transparent\"\n\t\t>\n\t\t\t<InputGroupAddon align=\"inline-start\">\n\t\t\t\t<InputGroupButton\n\t\t\t\t\tsize=\"icon-xs\"\n\t\t\t\t\tonClick={decrement}\n\t\t\t\t\tdisabled={currentValue <= min || disabled}\n\t\t\t\t\taria-label=\"Decrease value\"\n\t\t\t\t\tdata-testid=\"decrement-button\"\n\t\t\t\t>\n\t\t\t\t\t<span className=\"sr-only\">Decrement number button</span>\n\t\t\t\t\t<MinusIcon />\n\t\t\t\t</InputGroupButton>\n\t\t\t</InputGroupAddon>\n\t\t\t<InputGroupInput\n\t\t\t\ttype=\"text\"\n\t\t\t\tinputMode=\"numeric\"\n\t\t\t\tvalue={currentValue}\n\t\t\t\tonChange={handleInputChange}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tonKeyDown?.(event)\n\t\t\t\t\tif (event.defaultPrevented) return\n\t\t\t\t\tif (event.key === 'ArrowUp') {\n\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\tincrement()\n\t\t\t\t\t} else if (event.key === 'ArrowDown') {\n\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\tdecrement()\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tclassName={cn('text-center tabular-nums', className)}\n\t\t\t\taria-label=\"Number input\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\tpattern=\"\\d*\"\n\t\t\t\tdata-testid=\"number-input\"\n\t\t\t\taria-valuemin={min}\n\t\t\t\taria-valuemax={max}\n\t\t\t\taria-valuenow={currentValue}\n\t\t\t\trole=\"spinbutton\"\n\t\t\t\treadOnly\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t\t<InputGroupAddon align=\"inline-end\">\n\t\t\t\t<InputGroupButton\n\t\t\t\t\tsize=\"icon-xs\"\n\t\t\t\t\tonClick={increment}\n\t\t\t\t\tdisabled={currentValue >= max || disabled}\n\t\t\t\t\taria-label=\"Increase value\"\n\t\t\t\t\tdata-testid=\"increment-button\"\n\t\t\t\t>\n\t\t\t\t\t<span className=\"sr-only\">Increment number button</span>\n\t\t\t\t\t<PlusIcon />\n\t\t\t\t</InputGroupButton>\n\t\t\t</InputGroupAddon>\n\t\t</InputGroup>\n\t)\n}\n\nexport { NumberInput }\n",
      "type": "registry:ui",
      "target": "components/ui/number-input.tsx"
    }
  ],
  "type": "registry:ui"
}