{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "input",
  "type": "registry:component",
  "title": "Input",
  "description": "A single line to type into, with icons, units and buttons set inside its box.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/panelui/input.tsx",
      "type": "registry:component",
      "target": "@components/panelui/input.tsx",
      "content": "'use client';\n\n/**\n * Input — a single line to type into.\n *\n * ```tsx\n * <Input placeholder=\"you@example.com\" type=\"email\" />\n *\n * <Input.Group>\n *   <Input.Addon><SearchIcon /></Input.Addon>\n *   <Input placeholder=\"Search\" />\n *   <Input.Addon align=\"end\"><kbd>⌘K</kbd></Input.Addon>\n * </Input.Group>\n * ```\n *\n * ## The group owns the box\n *\n * On its own, the input draws its border, background and focus ring. Inside\n * `Input.Group`, it drops all three and the group draws them around the input\n * and its addons together, so an icon or a unit reads as part of the field and\n * the ring goes round the whole of it. Pressing an addon that is not a button\n * moves focus into the input.\n *\n * ## Inside a Field\n *\n * Put in a `Field`, the input takes the field's label, description and error\n * without ids passed by hand, and turns invalid when the field does.\n */\nimport { Input as BaseInput } from '@base-ui/react/input';\nimport type { ComponentProps, MouseEvent, Ref } from 'react';\nimport { tv } from 'tailwind-variants';\nimport { mergeProps } from '@base-ui/react/merge-props';\nimport { useRender } from '@base-ui/react/use-render';\nimport type { ElementType as RenderElementType } from 'react';\n\n/** Draws a part as another element, or composes it with a component: `render={<a href=\"/\" />}`. */\ntype RenderProp<Tag extends RenderElementType> = { render?: useRender.ComponentProps<Tag>['render'] };\n\nconst inputVariants = tv({\n  slots: {\n    input: [\n      'w-full min-w-0 bg-transparent text-foreground outline-none',\n      'placeholder:text-muted-foreground/80 selection:bg-primary selection:text-primary-foreground',\n      'file:me-3 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground',\n      'disabled:cursor-not-allowed disabled:opacity-50',\n      // Alone, it is the box. In a group, the group is.\n      'not-in-data-[slot=input-group]:rounded-lg not-in-data-[slot=input-group]:border not-in-data-[slot=input-group]:border-input',\n      'not-in-data-[slot=input-group]:bg-background not-in-data-[slot=input-group]:shadow-xs dark:not-in-data-[slot=input-group]:bg-input/30',\n      'not-in-data-[slot=input-group]:transition-[border-color,box-shadow]',\n      'not-in-data-[slot=input-group]:focus-visible:border-ring not-in-data-[slot=input-group]:focus-visible:ring-[3px] not-in-data-[slot=input-group]:focus-visible:ring-ring/30',\n      'aria-invalid:not-in-data-[slot=input-group]:border-destructive aria-invalid:not-in-data-[slot=input-group]:ring-destructive/20',\n    ],\n    group: [\n      'group/input flex w-full min-w-0 items-center rounded-lg border border-input bg-background shadow-xs transition-[border-color,box-shadow] dark:bg-input/30',\n      'has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-[3px] has-[input:focus-visible]:ring-ring/30',\n      'has-[input[aria-invalid=true]]:border-destructive has-[input[aria-invalid=true]]:ring-destructive/20',\n      'has-[input:disabled]:opacity-50',\n    ],\n    addon: [\n      'flex shrink-0 cursor-text items-center gap-1.5 text-sm text-muted-foreground select-none',\n      '[&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4',\n      '[&_kbd]:rounded [&_kbd]:border [&_kbd]:bg-muted [&_kbd]:px-1.5 [&_kbd]:font-sans [&_kbd]:text-xs',\n      // Padded to the group's size, read from the group so it is set once.\n      'px-3 group-data-[size=sm]/input:px-2.5 group-data-[size=lg]/input:px-3.5',\n    ],\n  },\n  variants: {\n    size: {\n      sm: { input: 'h-8 px-2.5 text-[0.8125rem]', group: 'h-8' },\n      md: { input: 'h-9 px-3 text-sm', group: 'h-9' },\n      lg: { input: 'h-11 px-3.5 text-[0.9375rem]', group: 'h-11 rounded-xl' },\n    },\n    align: {\n      // An addon sits closer to the text it belongs to than to the edge.\n      start: { addon: 'order-first -me-1.5' },\n      end: { addon: 'order-last -ms-1.5' },\n    },\n  },\n  compoundVariants: [\n    // In a group the input's own height is the group's, minus its border.\n    // Its text and padding follow the group's size too, so the size is set once.\n    {\n      size: ['sm', 'md', 'lg'],\n      className: {\n        input:\n          'in-data-[slot=input-group]:h-full group-data-[size=sm]/input:px-2.5 group-data-[size=sm]/input:text-[0.8125rem] group-data-[size=lg]/input:px-3.5 group-data-[size=lg]/input:text-[0.9375rem]',\n      },\n    },\n  ],\n  defaultVariants: { size: 'md', align: 'start' },\n});\n\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputProps extends Omit<ComponentProps<'input'>, 'size'> {\n  /** Its height and text size. Inside a group, set it on the group instead. Default `md`. */\n  size?: InputSize;\n}\n\n/** A single-line field. Every attribute of `<input>` passes through. */\nfunction InputRoot({ size, className, type = 'text', ref, ...props }: InputProps) {\n  return (\n    <BaseInput\n      type={type}\n      data-slot=\"input\"\n      ref={ref as Ref<HTMLElement>}\n      className={inputVariants({ size }).input({ className })}\n      {...props}\n    />\n  );\n}\nInputRoot.displayName = 'Input';\n\nexport interface InputGroupProps extends ComponentProps<'div'> {\n  /** The height of the input and its addons together. Default `md`. */\n  size?: InputSize;\n}\n\n/** Draws one box round an input and its addons. */\nfunction InputGroup({ size, className, render, ...props }: InputGroupProps & RenderProp<'div'>) {\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps(\n      {\n        role: 'group',\n        'data-slot': 'input-group',\n        'data-size': size ?? 'md',\n        className: inputVariants({ size }).group({ className }),\n      },\n      props\n    ),\n  });\n}\nInputGroup.displayName = 'Input.Group';\n\nexport interface InputAddonProps extends ComponentProps<'div'> {\n  /** Which side of the input it sits on, whatever its place in the markup. Default `start`. */\n  align?: 'start' | 'end';\n}\n\n/** An icon, unit, shortcut or button beside the input, inside its box. */\nfunction InputAddon({ align, className, onMouseDown, render, ...props }: InputAddonProps & RenderProp<'div'>) {\n  // A press on the addon's own surface is a press on the field. A button or\n  // link inside it is left to do what it does.\n  const focusField = (event: MouseEvent<HTMLDivElement>) => {\n    onMouseDown?.(event);\n    if (event.defaultPrevented) return;\n    if ((event.target as HTMLElement).closest('button, a, input, select, textarea')) return;\n    const input = event.currentTarget.parentElement?.querySelector('input');\n    if (!input) return;\n    event.preventDefault();\n    input.focus();\n  };\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps(\n      {\n        'data-slot': 'input-addon',\n        'data-align': align ?? 'start',\n        className: inputVariants({ align }).addon({ className }),\n        onMouseDown: focusField,\n      },\n      props\n    ),\n  });\n}\nInputAddon.displayName = 'Input.Addon';\n\nexport const Input = Object.assign(InputRoot, {\n  Group: InputGroup,\n  Addon: InputAddon,\n});\n\nexport { InputGroup, InputAddon };\n"
    }
  ]
}
