{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"prompt-input","title":"Prompt Input","description":"Composable chat input with auto-resizing textarea and action slots","dependencies":["@radix-ui/react-slot"],"registryDependencies":["textarea","scroll-area","tooltip","kbd"],"files":[{"path":"components/nexus-ui/prompt-input.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nimport { mergeRefs } from \"@/lib/merge-refs\";\nimport { cn } from \"@/lib/utils\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { ScrollArea, ScrollViewport } from \"@/components/ui/scroll-area\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { Kbd } from \"@/components/ui/kbd\";\n\ntype PromptInputContextValue = {\n  setTextareaNode: (node: HTMLTextAreaElement | null) => void;\n  onSubmit?: (value: string) => void;\n};\n\nconst PromptInputContext = React.createContext<PromptInputContextValue | null>(\n  null,\n);\n\ntype PromptInputProps = Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"onSubmit\"\n> & {\n  /**\n   * Called when Enter is pressed in the textarea (without Shift). Use with\n   * value/onChange on PromptInputTextarea for controlled mode. Shift+Enter\n   * inserts a new line.\n   */\n  onSubmit?: (value: string) => void;\n};\n\nfunction PromptInput({\n  className,\n  role: _role,\n  \"aria-label\": _ariaLabel,\n  onClick,\n  onSubmit,\n  ...props\n}: PromptInputProps) {\n  const textareaRef = React.useRef<HTMLTextAreaElement | null>(null);\n\n  const handleClick = React.useCallback(\n    (e: React.MouseEvent<HTMLDivElement>) => {\n      const target = e.target as HTMLElement;\n      if (\n        !target.closest(\n          'button, a, input, textarea, [role=\"button\"], [role=\"tab\"]',\n        )\n      ) {\n        textareaRef.current?.focus();\n      }\n      onClick?.(e);\n    },\n    [onClick],\n  );\n\n  const contextValue = React.useMemo<PromptInputContextValue>(\n    () => ({\n      setTextareaNode: (node) => {\n        textareaRef.current = node;\n      },\n      onSubmit,\n    }),\n    [onSubmit],\n  );\n\n  return (\n    <TooltipProvider delayDuration={100}>\n      <PromptInputContext.Provider value={contextValue}>\n        <div\n          role=\"group\"\n          aria-label=\"Chat input\"\n          className={cn(\n            \"relative flex h-auto w-full cursor-text flex-col gap-0 overflow-hidden rounded-3xl border border-border bg-card dark:border-border/50 dark:bg-input/30\",\n            className,\n          )}\n          onClick={handleClick}\n          {...props}\n        />\n      </PromptInputContext.Provider>\n    </TooltipProvider>\n  );\n}\n\ntype PromptInputTextareaProps = React.ComponentProps<typeof Textarea>;\n\nconst PromptInputTextarea = React.forwardRef<\n  HTMLTextAreaElement,\n  PromptInputTextareaProps\n>(function PromptInputTextarea(\n  { className, \"aria-label\": _ariaLabel, onKeyDown, ...props },\n  ref,\n) {\n  const context = React.useContext(PromptInputContext);\n  const setTextareaNode = context?.setTextareaNode;\n  const onSubmit = context?.onSubmit;\n  const handleTextareaRef = React.useCallback(\n    (node: HTMLTextAreaElement | null) => {\n      mergeRefs<HTMLTextAreaElement>(setTextareaNode, ref)(node);\n    },\n    [setTextareaNode, ref],\n  );\n\n  const handleKeyDown = React.useCallback(\n    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n      if (e.key === \"Enter\" && !e.shiftKey && onSubmit) {\n        e.preventDefault();\n        onSubmit(e.currentTarget.value);\n      }\n      onKeyDown?.(e);\n    },\n    [onSubmit, onKeyDown],\n  );\n\n  return (\n    <ScrollArea className=\"max-h-40\">\n      <ScrollViewport>\n        <Textarea\n          ref={handleTextareaRef}\n          aria-label=\"Message input\"\n          placeholder=\"How can I help you today?\"\n          className={cn(\n            \"min-h-14 w-full resize-none border-0 bg-transparent px-4 py-4 text-sm leading-6 font-normal text-primary shadow-none outline-none placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0 dark:bg-transparent\",\n            className,\n          )}\n          onKeyDown={handleKeyDown}\n          {...props}\n        />\n      </ScrollViewport>\n    </ScrollArea>\n  );\n});\n\ntype PromptInputActionsProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction PromptInputActions({\n  className,\n  role: _role,\n  \"aria-label\": _ariaLabel,\n  ...props\n}: PromptInputActionsProps) {\n  return (\n    <div\n      role=\"group\"\n      aria-label=\"Input actions\"\n      className={cn(\n        \"flex w-full shrink-0 items-center justify-between px-2 py-2\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\ntype PromptInputActionGroupProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction PromptInputActionGroup({\n  className,\n  ...props\n}: PromptInputActionGroupProps) {\n  return <div className={cn(\"flex gap-2\", className)} {...props} />;\n}\n\ntype PromptInputActionProps = React.HTMLAttributes<HTMLDivElement> & {\n  asChild?: boolean;\n  tooltip?:\n    | string\n    | {\n        content?: string;\n        side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n        shortcut?: string;\n      };\n};\n\nfunction PromptInputAction({\n  asChild = false,\n  tooltip,\n  ...props\n}: PromptInputActionProps) {\n  const Comp = asChild ? Slot : \"div\";\n  const { content, side, shortcut } =\n    typeof tooltip === \"string\" ? { content: tooltip } : (tooltip ?? {});\n\n  if (!content) {\n    return <Comp {...props} />;\n  }\n\n  return (\n    <Tooltip>\n      <TooltipTrigger asChild>\n        <Comp {...props} />\n      </TooltipTrigger>\n      <TooltipContent className=\"rounded-full\" side={side}>\n        {content}\n        {shortcut ? <Kbd className=\"rounded-md!\">{shortcut}</Kbd> : null}\n      </TooltipContent>\n    </Tooltip>\n  );\n}\n\nexport {\n  PromptInput,\n  PromptInputTextarea,\n  PromptInputActions,\n  PromptInputActionGroup,\n  PromptInputAction,\n};\n","type":"registry:file","target":"~/components/nexus-ui/prompt-input.tsx"}],"type":"registry:ui"}