{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "elements-mobile-composer",
  "type": "registry:component",
  "title": "Mobile composer",
  "description": "The bottom sheet: keyboard-aware, quick actions above, thumb-sized targets.",
  "registryDependencies": [
    "https://r.assistant-ui.com/elements-surfaces.json"
  ],
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/elements/mobile-composer.tsx",
      "sourcePath": "packages/ui/src/components/react/assistant-ui/elements/mobile-composer.tsx",
      "content": "\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { ArrowUpIcon, MicIcon, PlusIcon, SquareIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { field, ghostButton, inkButton, mono } from \"./surfaces\";\n\nexport function MobileComposer({\n  value,\n  keyboardOpen,\n  running,\n  actions,\n  onAction,\n  onAttach,\n  onValueChange,\n  onSend,\n  onStop,\n  onFocus,\n  className,\n  ...props\n}: Omit<\n  ComponentProps<\"div\">,\n  | \"children\"\n  | \"value\"\n  | \"keyboardOpen\"\n  | \"running\"\n  | \"actions\"\n  | \"onAction\"\n  | \"onAttach\"\n  | \"onValueChange\"\n  | \"onSend\"\n  | \"onStop\"\n  | \"onFocus\"\n> & {\n  value: string;\n  keyboardOpen: boolean;\n  running: boolean;\n  actions: readonly string[];\n  onAction?: (action: string) => void;\n  onAttach?: () => void;\n  onValueChange?: (value: string) => void;\n  onSend?: () => void;\n  onStop?: () => void;\n  onFocus?: () => void;\n}) {\n  return (\n    <div\n      data-slot=\"mobile-composer\"\n      className={cn(\n        \"bg-background border-foreground/[0.07] flex w-full max-w-[19rem] flex-col gap-2.5 rounded-t-[20px] border-t px-3 pt-3\",\n        keyboardOpen ? \"pb-3\" : \"pb-6\",\n        className,\n      )}\n\n      {...props}\n    >\n      {!keyboardOpen && (\n        <div className=\"fade-in animate-in -mx-3 flex gap-1.5 overflow-x-auto px-3 pb-0.5 duration-200\">\n          {actions.map((action) => (\n            <button\n              key={action}\n              type=\"button\"\n              onClick={() => onAction?.(action)}\n              disabled={!onAction}\n              className={cn(\n                \"disabled:pointer-events-none\",\n                field,\n                \"text-foreground/60 shrink-0 rounded-full px-3 py-1.5 text-xs whitespace-nowrap\",\n              )}\n            >\n              {action}\n            </button>\n          ))}\n        </div>\n      )}\n\n      <div className=\"flex items-end gap-2\">\n        <button\n          type=\"button\"\n          aria-label=\"Add an attachment\"\n          onClick={onAttach}\n          disabled={!onAttach}\n          className={cn(\n            ghostButton,\n            field,\n            \"size-9 shrink-0 disabled:pointer-events-none disabled:opacity-30\",\n          )}\n        >\n          <PlusIcon className=\"size-4\" />\n        </button>\n\n        <div\n          className={cn(\n            field,\n            \"flex min-w-0 flex-1 items-center gap-2 rounded-[18px] px-3 py-2\",\n          )}\n        >\n          <input\n            value={value}\n            onChange={(event) => onValueChange?.(event.target.value)}\n            onFocus={onFocus}\n            onKeyDown={(event) => {\n              if (event.key !== \"Enter\" || event.shiftKey) return;\n              if (event.nativeEvent.isComposing) return;\n              event.preventDefault();\n              if (!running && value !== \"\") onSend?.();\n            }}\n            placeholder=\"Message\"\n            aria-label=\"Message\"\n            className=\"text-foreground/85 placeholder:text-foreground/30 min-w-0 flex-1 bg-transparent text-[16px] outline-none\"\n          />\n          {value === \"\" && (\n            <MicIcon className=\"text-foreground/35 size-4 shrink-0\" />\n          )}\n        </div>\n\n        <button\n          type=\"button\"\n          aria-label={running ? \"Stop\" : \"Send\"}\n          onClick={running ? onStop : onSend}\n          disabled={!running && value === \"\"}\n          className={cn(\n            inkButton,\n            \"flex size-9 shrink-0 items-center justify-center rounded-full disabled:pointer-events-none disabled:opacity-25\",\n          )}\n        >\n          {running ? (\n            <SquareIcon className=\"size-3 fill-current\" />\n          ) : (\n            <ArrowUpIcon className=\"size-4\" />\n          )}\n        </button>\n      </div>\n\n      {!keyboardOpen && (\n        <span\n          aria-hidden\n          className=\"bg-foreground/15 mx-auto h-1 w-28 rounded-full\"\n        />\n      )}\n\n      {keyboardOpen && (\n        <span className={cn(mono, \"text-foreground/25 text-center\")}>\n          return to send\n        </span>\n      )}\n    </div>\n  );\n}\n"
    }
  ]
}