{"name":"upload-dropzone","title":"Upload Dropzone","type":"registry:ui","dependencies":["@better-upload/client","lucide-react","react-dropzone"],"registryDependencies":[],"files":[{"path":"ui/upload-dropzone.tsx","type":"registry:ui","content":"import { cn } from '@/lib/utils';\nimport type { UploadHookControl } from '@better-upload/client';\nimport { Loader2, Upload } from 'lucide-react';\nimport { useId } from 'react';\nimport { useDropzone } from 'react-dropzone';\n\ntype UploadDropzoneProps = {\n  control: UploadHookControl<true>;\n  id?: string;\n  accept?: string;\n  metadata?: Record<string, unknown>;\n  description?:\n    | {\n        fileTypes?: string;\n        maxFileSize?: string;\n        maxFiles?: number;\n      }\n    | string;\n  uploadOverride?: (\n    ...args: Parameters<UploadHookControl<true>['upload']>\n  ) => void;\n\n  // Add any additional props you need.\n};\n\nexport function UploadDropzone({\n  control: { upload, isPending },\n  id: _id,\n  accept,\n  metadata,\n  description,\n  uploadOverride,\n}: UploadDropzoneProps) {\n  const id = useId();\n\n  const { getRootProps, getInputProps, isDragActive, inputRef } = useDropzone({\n    onDrop: (files) => {\n      if (files.length > 0 && !isPending) {\n        if (uploadOverride) {\n          uploadOverride(files, { metadata });\n        } else {\n          upload(files, { metadata });\n        }\n      }\n      inputRef.current.value = '';\n    },\n    noClick: true,\n  });\n\n  return (\n    <div\n      className={cn(\n        'border-input text-foreground relative rounded-lg border border-dashed transition-colors',\n        {\n          'border-primary/80': isDragActive,\n        }\n      )}\n    >\n      <label\n        {...getRootProps()}\n        className={cn(\n          'dark:bg-input/10 flex w-full min-w-72 cursor-pointer flex-col items-center justify-center rounded-lg bg-transparent px-2 py-6 transition-colors',\n          {\n            'text-muted-foreground cursor-not-allowed': isPending,\n            'hover:bg-accent dark:hover:bg-accent/40': !isPending,\n            'opacity-0': isDragActive,\n          }\n        )}\n        htmlFor={_id || id}\n      >\n        <div className=\"my-2\">\n          {isPending ? (\n            <Loader2 className=\"size-6 animate-spin\" />\n          ) : (\n            <Upload className=\"size-6\" />\n          )}\n        </div>\n\n        <div className=\"mt-3 space-y-1 text-center\">\n          <p className=\"text-sm font-semibold\">Drag and drop files here</p>\n\n          <p className=\"text-muted-foreground max-w-64 text-xs\">\n            {typeof description === 'string' ? (\n              description\n            ) : (\n              <>\n                {description?.maxFiles &&\n                  `You can upload ${description.maxFiles} file${description.maxFiles !== 1 ? 's' : ''}.`}{' '}\n                {description?.maxFileSize &&\n                  `${description.maxFiles !== 1 ? 'Each u' : 'U'}p to ${description.maxFileSize}.`}{' '}\n                {description?.fileTypes && `Accepted ${description.fileTypes}.`}\n              </>\n            )}\n          </p>\n        </div>\n\n        <input\n          {...getInputProps()}\n          type=\"file\"\n          multiple\n          id={_id || id}\n          accept={accept}\n          disabled={isPending}\n        />\n      </label>\n\n      {isDragActive && (\n        <div className=\"pointer-events-none absolute inset-0 rounded-lg\">\n          <div className=\"dark:bg-accent/40 bg-accent flex size-full flex-col items-center justify-center rounded-lg\">\n            <div className=\"my-2\">\n              <Upload className=\"size-6\" />\n            </div>\n\n            <p className=\"mt-3 text-sm font-semibold\">Drop files here</p>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n"}]}