{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "ai-chat-interface-shadcnui", "type": "registry:component", "title": "AI Chat Interface", "description": "Chat input with attachments, model selector, and accessible controls", "registryDependencies": [ "button" ], "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/components/chat/ai-chat-interface.tsx", "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n ArrowUpRight,\n ChevronDown,\n Clock,\n Link2,\n Mail,\n MessageSquare,\n Share2,\n Sparkles,\n Star,\n Zap,\n} from \"lucide-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ntype DropdownType = \"share\" | \"quick\" | \"history\" | \"magic\" | \"model\" | null;\n\ntype ActionOption = {\n icon: typeof Link2;\n label: string;\n action: string;\n};\n\nconst shareOptions: ActionOption[] = [\n { icon: Link2, label: \"Copy link\", action: \"copy-link\" },\n { icon: Mail, label: \"Email\", action: \"email\" },\n { icon: MessageSquare, label: \"Slack\", action: \"slack\" },\n];\n\nconst quickOptions: ActionOption[] = [\n { icon: Sparkles, label: \"Summarize\", action: \"summarize\" },\n { icon: Sparkles, label: \"Improve\", action: \"improve\" },\n { icon: Sparkles, label: \"Translate\", action: \"translate\" },\n];\n\nconst historyOptions: ActionOption[] = [\n { icon: Clock, label: \"Last hour\", action: \"history-1h\" },\n { icon: Clock, label: \"Today\", action: \"history-today\" },\n { icon: Clock, label: \"This week\", action: \"history-week\" },\n];\n\nconst magicOptions: ActionOption[] = [\n { icon: Sparkles, label: \"Auto-complete\", action: \"magic-complete\" },\n { icon: Sparkles, label: \"Storyboard\", action: \"magic-storyboard\" },\n { icon: Sparkles, label: \"Rephrase\", action: \"magic-rephrase\" },\n];\n\nconst models = [\"GPT 5.0\", \"GPT 4.5 Turbo\", \"GPT 4.0\", \"Claude 3.5 Sonnet\"];\n\nexport function AIChatInterface() {\n const [inputValue, setInputValue] = useState(\"\");\n const [isFocused, setIsFocused] = useState(false);\n const [activeDropdown, setActiveDropdown] = useState(null);\n const [selectedModel, setSelectedModel] = useState(models[0]);\n const prefersReducedMotion = useReducedMotion();\n const textareaRef = useRef(null);\n const dropdownRef = useRef(null);\n\n const shouldAnimate = !prefersReducedMotion;\n\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setActiveDropdown(null);\n }\n }\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n const handleTextareaChange = (\n event: React.ChangeEvent\n ) => {\n setInputValue(event.target.value);\n\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;\n }\n };\n\n const renderDropdown = (\n type: DropdownType,\n options: ActionOption[],\n align: \"left\" | \"right\" = \"left\"\n ) => (\n \n {activeDropdown === type && (\n \n {options.map((option) => (\n {\n console.log(`Action: ${option.action}`);\n setActiveDropdown(null);\n }}\n className=\"flex w-full justify-start items-center gap-3 px-4 py-2 text-sm text-foreground/85 transition-all hover:bg-foreground/[0.05] hover:text-foreground\"\n role=\"menuitem\"\n type=\"button\"\n variant=\"ghost\"\n >\n \n {option.label}\n \n ))}\n \n )}\n \n );\n\n return (\n \n
\n \n
\n
\n
\n \n Prompt\n \n

\n Share goals, context, tone, and desired output.\n

\n
\n \n setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n rows={1}\n aria-label=\"Chat input\"\n />\n\n \n
\n \n setActiveDropdown(\n activeDropdown === \"share\" ? null : \"share\"\n )\n }\n className=\"group rounded-xl p-2 bg-background/80 transition-all hover:bg-foreground/[0.05] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/40\"\n aria-label=\"Share options\"\n aria-expanded={activeDropdown === \"share\"}\n aria-haspopup=\"menu\"\n type=\"button\"\n >\n \n \n {renderDropdown(\"share\", shareOptions)}\n
\n\n
\n \n setActiveDropdown(\n activeDropdown === \"quick\" ? null : \"quick\"\n )\n }\n className=\"group rounded-xl p-2 bg-background/80 transition-all hover:bg-foreground/[0.05] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/40\"\n aria-label=\"Quick actions\"\n aria-expanded={activeDropdown === \"quick\"}\n aria-haspopup=\"menu\"\n type=\"button\"\n >\n \n \n {renderDropdown(\"quick\", quickOptions)}\n
\n\n
\n \n setActiveDropdown(\n activeDropdown === \"history\" ? null : \"history\"\n )\n }\n className=\"group rounded-xl p-2 bg-background/80 transition-all hover:bg-foreground/[0.05] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/40\"\n aria-label=\"History\"\n aria-expanded={activeDropdown === \"history\"}\n aria-haspopup=\"menu\"\n type=\"button\"\n >\n \n \n {renderDropdown(\"history\", historyOptions)}\n
\n\n
\n \n setActiveDropdown(\n activeDropdown === \"magic\" ? null : \"magic\"\n )\n }\n className=\"group rounded-xl p-2 bg-background/80 transition-all hover:bg-foreground/[0.05] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/40\"\n aria-label=\"Magic options\"\n aria-expanded={activeDropdown === \"magic\"}\n aria-haspopup=\"menu\"\n type=\"button\"\n >\n \n \n {renderDropdown(\"magic\", magicOptions)}\n
\n\n
\n \n setActiveDropdown(\n activeDropdown === \"model\" ? null : \"model\"\n )\n }\n className=\"flex items-center gap-2 rounded-xl border border-border/30 bg-background/80 px-3 py-1.5 text-sm font-medium text-foreground/80 transition hover:border-border/40 hover:bg-background/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/40\"\n aria-label=\"Select AI model\"\n aria-expanded={activeDropdown === \"model\"}\n aria-haspopup=\"listbox\"\n type=\"button\"\n >\n {selectedModel}\n \n \n\n \n {activeDropdown === \"model\" && (\n \n {models.map((model) => (\n {\n setSelectedModel(model);\n setActiveDropdown(null);\n }}\n className={`flex w-full items-center justify-between px-4 py-2 text-sm transition-all ${\n selectedModel === model\n ? \"bg-primary/15 font-medium text-primary hover:bg-primary/20\"\n : \"text-foreground/80 hover:bg-foreground/[0.05]\"\n }`}\n role=\"option\"\n aria-selected={selectedModel === model}\n type=\"button\"\n variant={\n selectedModel === model ? \"default\" : \"ghost\"\n }\n >\n {model}\n {selectedModel === model && (\n \n )}\n \n ))}\n \n )}\n \n
\n\n console.log(\"Action: send-message\")}\n >\n Send\n \n \n
\n
\n
\n \n \n );\n}\n", "type": "registry:component", "target": "components/uitripled/ai-chat-interface-shadcnui.tsx" } ] }