{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "input-group-unit",
  "title": "Group-unit input",
  "description": "Styled input: the Group-unit set. 5 decorative input variations (UnitGroup, CurrencyGroup, PercentGroup, SelectUnitGroup, StepperGroup) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/input-group-unit.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Minus, Percent, Plus } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Unit input group family: 5 fields with a unit/currency attached. unit (a fixed\n   unit chip on the right), currency (a currency chip on the left), percent (a\n   percent icon on the right), selectUnit (a unit selector on the right), stepper (a\n   REALLY working +/- stepper for a number field; the value is held in local state\n   and clamped to min/max). Color comes ONLY from tokens, via alpha color-mix. No\n   motion. Every field has an accessible label and every icon button an\n   aria-label. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst height: Record<StyledSize, string> = {\n  sm: \"h-8 text-sm\",\n  md: \"h-9 text-sm\",\n  lg: \"h-10 text-base\",\n  xl: \"h-12 text-base\",\n}\n\nconst rootBase =\n  \"group inline-flex w-64 max-w-full items-center overflow-hidden rounded-lg border border-field-border bg-transparent transition-colors duration-(--motion-base) focus-within:border-primary focus-within:ring-[3px] focus-within:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst fieldBase =\n  \"h-full w-full min-w-0 bg-transparent px-3 text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n\nconst addonBase =\n  \"flex h-full shrink-0 select-none items-center gap-1.5 bg-surface-2 px-3 text-muted-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst stepBtn =\n  \"flex h-full w-9 shrink-0 items-center justify-center bg-surface-2 text-muted-foreground outline-none transition-colors hover:bg-surface-3 hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50\"\n\ntype Props = Omit<React.ComponentProps<\"input\">, \"size\"> & { size?: StyledSize }\n\n/* Unit: a fixed unit chip on the right (for example \"px\"). */\nexport function UnitGroup({ className, size = \"md\", ...props }: Props) {\n  const id = React.useId()\n  return (\n    <div data-slot=\"styled-input-group\" className={cn(rootBase, height[size], className)}>\n      <label htmlFor={id} className=\"sr-only\">\n        Length in pixels\n      </label>\n      <input id={id} type=\"number\" placeholder=\"0\" {...props} className={cn(fieldBase, \"pr-2\")} />\n      <span className={cn(addonBase, \"border-l border-field-border\")}>px</span>\n    </div>\n  )\n}\n\n/* Currency: a currency chip on the left, the code on the right. */\nexport function CurrencyGroup({ className, size = \"md\", ...props }: Props) {\n  const id = React.useId()\n  return (\n    <div data-slot=\"styled-input-group\" className={cn(rootBase, height[size], className)}>\n      <span className={cn(addonBase, \"border-r border-field-border\")}>$</span>\n      <label htmlFor={id} className=\"sr-only\">\n        Amount in dollars\n      </label>\n      <input id={id} type=\"number\" placeholder=\"0.00\" {...props} className={cn(fieldBase, \"px-2\")} />\n      <span className=\"mr-3 shrink-0 select-none text-xs text-muted-foreground\">USD</span>\n    </div>\n  )\n}\n\n/* Percent: sagda yuzde ikonu tasiyan oran alani. */\nexport function PercentGroup({ className, size = \"md\", ...props }: Props) {\n  const id = React.useId()\n  return (\n    <div data-slot=\"styled-input-group\" className={cn(rootBase, height[size], className)}>\n      <label htmlFor={id} className=\"sr-only\">\n        Percentage\n      </label>\n      <input id={id} type=\"number\" placeholder=\"0\" {...props} className={cn(fieldBase, \"pr-2\")} />\n      <span className={cn(addonBase, \"border-l border-field-border\")}>\n        <Percent />\n      </span>\n    </div>\n  )\n}\n\n/* SelectUnit: sagda gercek bir birim secimi. */\nexport function SelectUnitGroup({ className, size = \"md\", ...props }: Props) {\n  const id = React.useId()\n  return (\n    <div data-slot=\"styled-input-group\" className={cn(rootBase, height[size], className)}>\n      <label htmlFor={id} className=\"sr-only\">\n        Size value\n      </label>\n      <input id={id} type=\"number\" placeholder=\"0\" {...props} className={cn(fieldBase, \"pr-2\")} />\n      <select\n        aria-label=\"Unit\"\n        className=\"h-full shrink-0 select-none border-l border-field-border bg-surface-2 pl-3 pr-2 text-muted-foreground outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n      >\n        <option value=\"px\">px</option>\n        <option value=\"rem\">rem</option>\n        <option value=\"%\">%</option>\n      </select>\n    </div>\n  )\n}\n\n/* Stepper: a REAL working +/- stepper. The value lives in local state (a controlled number input), clamped between 0 and 100; the buttons disable at the limits. */\nexport function StepperGroup({ className, size = \"md\", ...props }: Props) {\n  const id = React.useId()\n  const MIN = 0\n  const MAX = 100\n  const [value, setValue] = React.useState(1)\n\n  const clamp = (n: number) => Math.min(MAX, Math.max(MIN, n))\n\n  return (\n    <div data-slot=\"styled-input-group\" className={cn(rootBase, height[size], className)}>\n      <button\n        type=\"button\"\n        aria-label=\"Decrease value\"\n        disabled={value <= MIN}\n        className={cn(stepBtn, \"border-r border-field-border\")}\n        onClick={() => setValue((v) => clamp(v - 1))}\n      >\n        <Minus />\n      </button>\n      <label htmlFor={id} className=\"sr-only\">\n        Quantity\n      </label>\n      <input\n        id={id}\n        type=\"number\"\n        min={MIN}\n        max={MAX}\n        {...props}\n        value={value}\n        onChange={(e) => {\n          const next = Number(e.target.value)\n          setValue(Number.isFinite(next) ? clamp(next) : MIN)\n        }}\n        className={cn(fieldBase, \"text-center [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none\")}\n      />\n      <button\n        type=\"button\"\n        aria-label=\"Increase value\"\n        disabled={value >= MAX}\n        className={cn(stepBtn, \"border-l border-field-border\")}\n        onClick={() => setValue((v) => clamp(v + 1))}\n      >\n        <Plus />\n      </button>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/input-group-unit.tsx"
    }
  ],
  "categories": [
    "styled",
    "input"
  ],
  "type": "registry:component"
}