{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "prompt-input",
  "type": "registry:ui",
  "title": "Prompt input",
  "description": "An AI chat composer that grows with its content, sends on Enter, adds a newline on Shift Enter and has attach, toolbar and send controls. Built for React.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/prompt-input.tsx",
      "type": "registry:ui",
      "target": "components/ui/prompt-input.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { ArrowUpIcon, PaperclipIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * PromptInput — the composer. Grows with content, submits on Enter,\n * Shift+Enter for a newline. The whole shell takes the focus halo.\n */\nfunction PromptInput({\n  value,\n  onChange,\n  onSubmit,\n  disabled,\n  className,\n  placeholder = \"Message…\",\n  toolbar,\n}: {\n  value?: string\n  onChange?: (v: string) => void\n  onSubmit?: () => void\n  disabled?: boolean\n  className?: string\n  placeholder?: string\n  /** Optional left-side toolbar content (model picker, chips…). */\n  toolbar?: React.ReactNode\n}) {\n  const ref = React.useRef<HTMLTextAreaElement>(null)\n  React.useLayoutEffect(() => {\n    const el = ref.current\n    if (!el) return\n    el.style.height = \"0px\"\n    el.style.height = Math.min(el.scrollHeight, 240) + \"px\"\n  }, [value])\n  const canSend = !disabled && !!value?.trim()\n  return (\n    <div\n      data-slot=\"prompt-input\"\n      className={cn(\n        \"group/prompt rounded-2xl border border-border bg-surface shadow-md\",\n        \"transition-[border-color,box-shadow] duration-[140ms] ease-hairline\",\n        \"focus-within:border-accent focus-within:shadow-[0_0_0_3px_var(--accent-soft),var(--sh-md)]\",\n        disabled && \"opacity-60\",\n        className\n      )}\n    >\n      <textarea\n        ref={ref}\n        aria-label=\"Prompt\"\n        rows={1}\n        value={value}\n        disabled={disabled}\n        placeholder={placeholder}\n        className=\"block max-h-60 min-h-[52px] w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-[0.9375rem] leading-[1.55] text-fg outline-none placeholder:text-fg-subtle\"\n        onChange={(e) => onChange?.(e.target.value)}\n        onKeyDown={(e) => {\n          if (e.key === \"Enter\" && !e.shiftKey) {\n            e.preventDefault()\n            if (canSend) onSubmit?.()\n          }\n        }}\n      />\n      <div className=\"flex items-center justify-between gap-2 px-2.5 pb-2.5\">\n        <div className=\"flex min-w-0 items-center gap-1\">\n          <button\n            type=\"button\"\n            aria-label=\"Attach file\"\n            className=\"inline-flex size-8 items-center justify-center rounded-lg text-fg-subtle outline-none transition-colors hover:bg-sunken hover:text-fg focus-visible:ring-2 focus-visible:ring-accent\"\n          >\n            <PaperclipIcon className=\"size-4\" />\n          </button>\n          {toolbar}\n        </div>\n        <button\n          type=\"button\"\n          aria-label=\"Send\"\n          disabled={!canSend}\n          onClick={onSubmit}\n          className={cn(\n            \"inline-flex size-8 items-center justify-center rounded-full outline-none\",\n            \"transition-[background-color,color,transform,box-shadow] duration-[140ms] ease-hairline\",\n            \"focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface\",\n            canSend ? \"bg-ink text-on-ink shadow-ink hover:bg-ink-hover active:translate-y-[0.5px]\" : \"bg-sunken text-fg-subtle\"\n          )}\n        >\n          <ArrowUpIcon className=\"size-4\" />\n        </button>\n      </div>\n    </div>\n  )\n}\nexport { PromptInput }\n"
    }
  ]
}
