{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "claude-chat-input", "type": "registry:ui", "title": "Claude Chat Input", "description": "Multi-modal chat input with file uploads, model selector, extended thinking toggle, and spring-timed interactions.", "dependencies": [ "lucide-react" ], "registryDependencies": [ "button", "textarea", "popover", "separator", "switch", "badge" ], "files": [ { "path": "registry/ruixenui/claude-chat-input.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n Plus,\n ChevronDown,\n ChevronRight,\n ArrowUp,\n X,\n FileText,\n Loader2,\n Check,\n Archive,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Badge } from \"@/components/ui/badge\";\n\n/* ------------------------------------------------------------------ */\n/* utility */\n/* ------------------------------------------------------------------ */\nconst formatFileSize = (bytes: number) => {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + \" \" + sizes[i];\n};\n\n/* ------------------------------------------------------------------ */\n/* types */\n/* ------------------------------------------------------------------ */\nexport interface AttachedFile {\n id: string;\n file: File;\n type: string;\n preview: string | null;\n uploadStatus: \"pending\" | \"uploading\" | \"complete\";\n}\n\nexport interface PastedContent {\n id: string;\n content: string;\n timestamp: Date;\n}\n\nexport interface ModelOption {\n id: string;\n name: string;\n description?: string;\n}\n\nexport interface SuggestionChip {\n icon: React.ReactNode;\n label?: string;\n onClick?: () => void;\n}\n\nexport interface ClaudeChatInputProps {\n onSubmit?: (data: {\n message: string;\n files: AttachedFile[];\n pastedContent: PastedContent[];\n model: string;\n thinking: boolean;\n }) => void;\n placeholder?: string;\n models?: ModelOption[];\n defaultModel?: string;\n suggestions?: SuggestionChip[];\n greeting?: string;\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* file preview card */\n/* ------------------------------------------------------------------ */\nconst FilePreviewCard: React.FC<{\n file: AttachedFile;\n onRemove: (id: string) => void;\n}> = ({ file, onRemove }) => {\n const isImage = file.type.startsWith(\"image/\") && file.preview;\n\n return (\n
\n {file.file.name}\n
\n\n {formatFileSize(file.file.size)}\n
\n\n {content.content}\n
\n\n Drop files to upload\n
\n