{
  "name": "file-upload-chat-input-demo",
  "type": "registry:example",
  "dependencies": [
    "sonner",
    "uploadthing",
    "@uploadthing/react"
  ],
  "registryDependencies": [
    "button",
    "file-upload",
    "textarea"
  ],
  "files": [
    {
      "path": "examples/file-upload-chat-input-demo.tsx",
      "type": "registry:example",
      "content": "\"use client\";\n\nimport { ArrowUp, Paperclip, Upload, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport { toast } from \"sonner\";\n\nimport { Button } from \"@/registry/bases/radix/ui/button\";\nimport {\n  FileUpload,\n  FileUploadDropzone,\n  FileUploadItem,\n  FileUploadItemDelete,\n  FileUploadItemMetadata,\n  FileUploadItemPreview,\n  FileUploadItemProgress,\n  FileUploadList,\n  type FileUploadProps,\n  FileUploadTrigger,\n} from \"@/registry/bases/radix/ui/file-upload\";\nimport { Textarea } from \"@/registry/bases/radix/ui/textarea\";\n\nexport default function FileUploadChatInputDemo() {\n  const [input, setInput] = React.useState(\"\");\n  const [files, setFiles] = React.useState<File[]>([]);\n  const [isUploading, setIsUploading] = React.useState(false);\n\n  const onInputChange = React.useCallback(\n    (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n      setInput(event.target.value);\n    },\n    [],\n  );\n\n  const onUpload: NonNullable<FileUploadProps[\"onUpload\"]> = React.useCallback(\n    async (files, { onProgress, onSuccess, onError }) => {\n      try {\n        setIsUploading(true);\n        // Process each file individually\n        const uploadPromises = files.map(async (file) => {\n          try {\n            // Simulate file upload with progress\n            const totalChunks = 10;\n            let uploadedChunks = 0;\n\n            // Simulate chunk upload with delays\n            for (let i = 0; i < totalChunks; i++) {\n              // Simulate network delay (100-300ms per chunk)\n              await new Promise((resolve) =>\n                setTimeout(resolve, Math.random() * 200 + 100),\n              );\n\n              // Update progress for this specific file\n              uploadedChunks++;\n              const progress = (uploadedChunks / totalChunks) * 100;\n              onProgress(file, progress);\n            }\n\n            // Simulate server processing delay\n            await new Promise((resolve) => setTimeout(resolve, 500));\n            onSuccess(file);\n          } catch (error) {\n            onError(\n              file,\n              error instanceof Error ? error : new Error(\"Upload failed\"),\n            );\n          } finally {\n            setIsUploading(false);\n          }\n        });\n\n        // Wait for all uploads to complete\n        await Promise.all(uploadPromises);\n      } catch (error) {\n        // This handles any error that might occur outside the individual upload processes\n        console.error(\"Unexpected error during upload:\", error);\n      }\n    },\n    [],\n  );\n\n  const onFileReject = React.useCallback((file: File, message: string) => {\n    toast(message, {\n      description: `\"${file.name.length > 20 ? `${file.name.slice(0, 20)}...` : file.name}\" has been rejected`,\n    });\n  }, []);\n\n  const onSubmit = React.useCallback(\n    (event: React.FormEvent<HTMLFormElement>) => {\n      event.preventDefault();\n      setInput(\"\");\n      setFiles([]);\n    },\n    [],\n  );\n\n  return (\n    <FileUpload\n      value={files}\n      onValueChange={setFiles}\n      onUpload={onUpload}\n      onFileReject={onFileReject}\n      maxFiles={10}\n      maxSize={5 * 1024 * 1024}\n      className=\"relative h-[400px] w-full items-center p-8\"\n      multiple\n      disabled={isUploading}\n    >\n      <FileUploadDropzone\n        tabIndex={-1}\n        // Prevents the dropzone from triggering on click\n        onClick={(event) => event.preventDefault()}\n        className=\"absolute top-0 left-0 z-0 flex size-full items-center justify-center rounded-none border-none bg-background/50 p-0 opacity-0 backdrop-blur transition-opacity duration-200 ease-out data-dragging:z-10 data-dragging:opacity-100\"\n      >\n        <div className=\"flex flex-col items-center gap-1 text-center\">\n          <div className=\"flex items-center justify-center rounded-full border p-2.5\">\n            <Upload className=\"size-6 text-muted-foreground\" />\n          </div>\n          <p className=\"text-sm font-medium\">Drag & drop files here</p>\n          <p className=\"text-xs text-muted-foreground\">\n            Upload max 5 files each up to 5MB\n          </p>\n        </div>\n      </FileUploadDropzone>\n      <form\n        onSubmit={onSubmit}\n        className=\"relative flex w-full max-w-md flex-col gap-2.5 rounded-md border border-input px-3 py-2 outline-none focus-within:ring-1 focus-within:ring-ring/50\"\n      >\n        <FileUploadList\n          orientation=\"horizontal\"\n          className=\"overflow-x-auto px-0 py-1\"\n        >\n          {files.map((file, index) => (\n            <FileUploadItem key={index} value={file} className=\"max-w-52 p-1.5\">\n              <FileUploadItemPreview className=\"size-8 [&>svg]:size-5\">\n                <FileUploadItemProgress variant=\"fill\" />\n              </FileUploadItemPreview>\n              <FileUploadItemMetadata size=\"sm\" />\n              <FileUploadItemDelete asChild>\n                <Button\n                  variant=\"secondary\"\n                  size=\"icon\"\n                  className=\"absolute -top-1 -right-1 size-4 shrink-0 cursor-pointer rounded-full\"\n                >\n                  <X className=\"size-2.5\" />\n                </Button>\n              </FileUploadItemDelete>\n            </FileUploadItem>\n          ))}\n        </FileUploadList>\n        <Textarea\n          value={input}\n          onChange={onInputChange}\n          placeholder=\"Type your message here...\"\n          className=\"field-sizing-content min-h-10 w-full resize-none border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 dark:bg-transparent\"\n          disabled={isUploading}\n        />\n        <div className=\"flex items-center justify-end gap-1.5\">\n          <FileUploadTrigger asChild>\n            <Button\n              type=\"button\"\n              size=\"icon\"\n              variant=\"ghost\"\n              className=\"size-7 rounded-sm\"\n            >\n              <Paperclip className=\"size-3.5\" />\n              <span className=\"sr-only\">Attach file</span>\n            </Button>\n          </FileUploadTrigger>\n          <Button\n            size=\"icon\"\n            className=\"size-7 rounded-sm\"\n            disabled={!input.trim() || isUploading}\n          >\n            <ArrowUp className=\"size-3.5\" />\n            <span className=\"sr-only\">Send message</span>\n          </Button>\n        </div>\n      </form>\n    </FileUpload>\n  );\n}\n",
      "target": ""
    }
  ]
}