{ "name": "ai-prompt", "type": "registry:component", "dependencies": [ "lucide-react", "motion" ], "registryDependencies": [ "textarea", "button", "dropdown-menu" ], "files": [ { "type": "registry:component", "content": "\"use client\";\n\n/**\n * @author: @kokonutui\n * @description: AI Prompt Input\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport { ArrowRight, Bot, Check, ChevronDown, Paperclip } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { useState } from \"react\";\nimport Anthropic from \"@/components/icons/anthropic\";\nimport AnthropicDark from \"@/components/icons/anthropic-dark\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { useAutoResizeTextarea } from \"@/hooks/use-auto-resize-textarea\";\nimport { cn } from \"@/lib/utils\";\n\nconst OPENAI_SVG = (\n
\n \n OpenAI Icon Light\n \n \n \n OpenAI Icon Dark\n \n \n
\n);\n\ninterface AIPromptProps {\n models?: string[];\n defaultModel?: string;\n placeholder?: string;\n headerText?: string;\n headerAction?: string;\n onSubmit?: (value: string, model: string) => void;\n className?: string;\n}\n\nconst DEFAULT_MODELS = [\n \"Gemini 3\",\n \"GPT-5-mini\",\n \"Claude 4.5 Sonnet\",\n \"GPT-5-1 Mini\",\n \"GPT-5-1\",\n];\n\nexport default function AI_Prompt({\n models = DEFAULT_MODELS,\n defaultModel = \"Claude 4.5 Sonnet\",\n placeholder = \"What can I do for you?\",\n headerText = \"is free this weekend!\",\n headerAction = \"Ship Now!\",\n onSubmit,\n className,\n}: AIPromptProps) {\n const [value, setValue] = useState(\"\");\n const { textareaRef, adjustHeight } = useAutoResizeTextarea({\n minHeight: 72,\n maxHeight: 300,\n });\n const [selectedModel, setSelectedModel] = useState(defaultModel);\n\n const MODEL_ICONS: Record = {\n \"GPT-5-mini\": OPENAI_SVG,\n \"Gemini 3\": (\n \n Gemini\n \n \n \n \n \n \n \n \n \n ),\n \"Claude 4.5 Sonnet\": (\n
\n \n Anthropic Icon Light\n \n \n \n Anthropic Icon Dark\n \n \n
\n ),\n \"GPT-5-1 Mini\": OPENAI_SVG,\n \"GPT-5-1\": OPENAI_SVG,\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n onSubmit?.(value, selectedModel);\n setValue(\"\");\n adjustHeight(true);\n }\n };\n\n return (\n
\n
\n
\n
\n \n \n

\n {headerText}\n

\n
\n

\n {headerAction}\n

\n
\n
\n
\n
\n {\n setValue(e.target.value);\n adjustHeight();\n }}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n ref={textareaRef}\n value={value}\n />\n
\n\n
\n
\n
\n \n \n \n \n \n {MODEL_ICONS[selectedModel]}\n {selectedModel}\n \n \n \n \n \n \n {models.map((model) => (\n setSelectedModel(model)}\n >\n
\n {MODEL_ICONS[model] || (\n \n )}{\" \"}\n {/* Use mapped SVG or fallback */}\n {model}\n
\n {selectedModel === model && (\n \n )}\n \n ))}\n \n
\n
\n \n \n \n \n
\n \n \n \n
\n
\n
\n
\n
\n
\n );\n}\n", "path": "/components/kokonutui/ai-prompt.tsx", "target": "components/kokonutui/ai-prompt.tsx" }, { "type": "registry:hook", "content": "import { useCallback, useEffect, useRef } from \"react\";\n\ninterface UseAutoResizeTextareaProps {\n minHeight: number;\n maxHeight?: number;\n}\n\nexport function useAutoResizeTextarea({\n minHeight,\n maxHeight,\n}: UseAutoResizeTextareaProps) {\n const textareaRef = useRef(null);\n\n const adjustHeight = useCallback(\n (reset?: boolean) => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n if (reset) {\n textarea.style.height = `${minHeight}px`;\n return;\n }\n\n // Temporarily shrink to get the right scrollHeight\n textarea.style.height = `${minHeight}px`;\n\n // Calculate new height\n const newHeight = Math.max(\n minHeight,\n Math.min(textarea.scrollHeight, maxHeight ?? Number.POSITIVE_INFINITY)\n );\n\n textarea.style.height = `${newHeight}px`;\n },\n [minHeight, maxHeight]\n );\n\n useEffect(() => {\n // Set initial height\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = `${minHeight}px`;\n }\n }, [minHeight]);\n\n // Adjust height on window resize\n useEffect(() => {\n const handleResize = () => adjustHeight();\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, [adjustHeight]);\n\n return { textareaRef, adjustHeight };\n}\n", "path": "/hooks/use-auto-resize-textarea.ts", "target": "hooks/use-auto-resize-textarea.ts" }, { "type": "registry:component", "content": "const Anthropic = (props: React.SVGProps) => (\n \n {\"Anthropic\"}\n \n \n);\nexport default Anthropic;\n", "path": "/components/icons/anthropic.tsx", "target": "components/kokonutui/anthropic.tsx" }, { "type": "registry:component", "content": "import type { SVGProps } from \"react\";\n\nconst AnthropicDark = (props: SVGProps) => (\n \n {\"Anthropic\"}\n \n \n);\nexport default AnthropicDark;\n", "path": "/components/icons/anthropic-dark.tsx", "target": "components/kokonutui/anthropic-dark.tsx" } ] }