{ "name": "ai-input-search", "type": "registry:component", "dependencies": [ "motion" ], "registryDependencies": [ "textarea" ], "files": [ { "type": "registry:component", "content": "\"use client\";\n\n/**\n * @author: @kokonutui\n * @description: AI Input Search\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 { Globe, Paperclip, Send } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { useState } from \"react\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { useAutoResizeTextarea } from \"@/hooks/use-auto-resize-textarea\";\nimport { cn } from \"@/lib/utils\";\n\ninterface AIInputSearchProps {\n placeholder?: string;\n searchLabel?: string;\n onSubmit?: (value: string) => void;\n className?: string;\n}\n\nexport default function AI_Input_Search({\n placeholder = \"Search the web...\",\n searchLabel = \"Search\",\n onSubmit,\n className,\n}: AIInputSearchProps) {\n const [value, setValue] = useState(\"\");\n const { textareaRef, adjustHeight } = useAutoResizeTextarea({\n minHeight: 52,\n maxHeight: 200,\n });\n const [showSearch, setShowSearch] = useState(true);\n const [isFocused, setIsFocused] = useState(false);\n\n const handleSubmit = () => {\n onSubmit?.(value);\n setValue(\"\");\n adjustHeight(true);\n };\n\n const handleFocus = () => {\n setIsFocused(true);\n };\n\n const handleBlur = () => {\n setIsFocused(false);\n };\n\n const handleContainerClick = () => {\n if (textareaRef.current) {\n textareaRef.current.focus();\n }\n };\n\n return (\n
\n
\n {\n if (e.key === \"Enter\" || e.key === \" \") {\n handleContainerClick();\n }\n }}\n role=\"textbox\"\n tabIndex={0}\n >\n
\n {\n setValue(e.target.value);\n adjustHeight();\n }}\n onFocus={handleFocus}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n }}\n placeholder={placeholder}\n ref={textareaRef}\n value={value}\n />\n
\n\n
\n
\n \n {\n setShowSearch(!showSearch);\n }}\n type=\"button\"\n >\n
\n \n \n \n
\n \n {showSearch && (\n \n {searchLabel}\n \n )}\n \n \n
\n
\n \n \n \n
\n
\n
\n
\n \n );\n}\n", "path": "/components/kokonutui/ai-input-search.tsx", "target": "components/kokonutui/ai-input-search.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" } ] }