smart-dropzone-react
Version:
🚀 A production-ready React dropzone component with smart defaults, drag & drop reordering, chunked uploads, resume functionality, and comprehensive provider support (Cloudinary, AWS S3, Supabase)
1 lines • 18.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/smart-dropzone.tsx"],"names":["SmartDropzone","className","theme","variant","size","showPreview","showProgress","showFileSize","showFileType","maxFiles","UPLOAD","maxFileSize","FILE_SIZE","allowedTypes","onFilesSelected","onUploadComplete","onValidationError","folder","provider","disabled","multiple","maxSize","minSize","noClick","noKeyboard","noDrag","noDragEventsBubbling","preventDropOnDocument","useFsAccessApi","autoFocus","tabIndex","options","files","isUploading","error","uploadProgress","pendingFiles","successFiles","errorFiles","hasFiles","hasPendingFiles","addFiles","removeFile","clearAll","uploadAll","retryUpload","cancelUpload","useUpload","onDrop","useCallback","acceptedFiles","result","errorMessage","onDropRejected","rejectedFiles","file","errors","e","getRootProps","getInputProps","isDragActive","useDropzone","useMemo","acc","type","category","handleUpload","results","themeClasses","baseClasses","sizeClasses","buttonClasses","jsxs","jsx","FileItem","FileProcessor","sum","f"],"mappings":"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","file":"chunk-5PW6DLXG.cjs","sourcesContent":["import React, { useCallback, useMemo } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport type { SmartDropzoneProps, UploadProvider } from \"../types\";\r\nimport { useUpload } from \"../hooks/use-upload\";\r\nimport { FileProcessor } from \"../core/file-processor\";\r\nimport { FileItem } from \"./file-item\";\r\nimport { FILE_SIZE, UPLOAD } from \"../core/config\";\r\n\r\n/**\r\n * Enhanced SmartDropzone component with provider abstraction\r\n */\r\nexport const SmartDropzone: React.FC<\r\n SmartDropzoneProps & { provider: UploadProvider }\r\n> = ({\r\n className = \"\",\r\n theme = \"light\",\r\n variant = \"outlined\",\r\n size = \"md\",\r\n showPreview = true,\r\n showProgress = true,\r\n showFileSize = true,\r\n showFileType = true,\r\n maxFiles = UPLOAD.DEFAULT_MAX_FILES,\r\n maxFileSize = FILE_SIZE.DEFAULT_MAX_SIZE,\r\n allowedTypes = [\"image/*\", \"application/pdf\", \"text/*\"],\r\n onFilesSelected,\r\n onUploadComplete,\r\n onValidationError,\r\n folder,\r\n provider,\r\n disabled = false,\r\n multiple = true,\r\n maxSize,\r\n minSize,\r\n noClick = false,\r\n noKeyboard = false,\r\n noDrag = false,\r\n noDragEventsBubbling = false,\r\n preventDropOnDocument = true,\r\n useFsAccessApi = false,\r\n autoFocus = false,\r\n tabIndex,\r\n ...options\r\n}) => {\r\n // Use the upload hook for state management\r\n const {\r\n files,\r\n isUploading,\r\n error,\r\n uploadProgress,\r\n pendingFiles,\r\n successFiles,\r\n errorFiles,\r\n hasFiles,\r\n hasPendingFiles,\r\n addFiles,\r\n removeFile,\r\n clearAll,\r\n uploadAll,\r\n retryUpload,\r\n cancelUpload,\r\n } = useUpload(provider, {\r\n maxFiles,\r\n maxFileSize,\r\n allowedTypes,\r\n folder,\r\n ...options,\r\n });\r\n\r\n // Handle file drop\r\n const onDrop = useCallback(\r\n async (acceptedFiles: readonly File[]) => {\r\n try {\r\n const result = await addFiles(acceptedFiles);\r\n\r\n if (result && result.success && result.files) {\r\n onFilesSelected?.(result.files);\r\n } else if (result && result.errors) {\r\n const errorMessage = result.errors.join(\"; \");\r\n onValidationError?.(errorMessage);\r\n }\r\n } catch (error) {\r\n const errorMessage =\r\n error instanceof Error ? error.message : \"Failed to process files\";\r\n onValidationError?.(errorMessage);\r\n }\r\n },\r\n [addFiles, onFilesSelected, onValidationError]\r\n );\r\n\r\n // Handle rejected files\r\n const onDropRejected = useCallback(\r\n (rejectedFiles: any[]) => {\r\n const errors = rejectedFiles.map(\r\n ({ file, errors }: any) =>\r\n `${file.name}: ${errors.map((e: any) => e.message).join(\", \")}`\r\n );\r\n const errorMessage = errors.join(\"; \");\r\n onValidationError?.(errorMessage);\r\n },\r\n [onValidationError]\r\n );\r\n\r\n // Configure dropzone\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n onDropRejected,\r\n maxFiles,\r\n maxSize: maxSize || maxFileSize,\r\n minSize,\r\n multiple,\r\n noClick,\r\n noKeyboard,\r\n noDrag,\r\n noDragEventsBubbling,\r\n preventDropOnDocument,\r\n useFsAccessApi,\r\n autoFocus,\r\n accept: useMemo(() => {\r\n return allowedTypes.reduce(\r\n (acc, type) => {\r\n if (type === \"*\") {\r\n acc[\"*/*\"] = [];\r\n } else if (type.endsWith(\"/*\")) {\r\n const category = type.split(\"/\")[0];\r\n acc[category] = [];\r\n } else if (type.startsWith(\".\")) {\r\n acc[\"*/*\"] = [type];\r\n } else {\r\n acc[type] = [];\r\n }\r\n return acc;\r\n },\r\n {} as Record<string, string[]>\r\n );\r\n }, [allowedTypes]),\r\n disabled,\r\n });\r\n\r\n // Handle upload\r\n const handleUpload = useCallback(async () => {\r\n if (!hasPendingFiles || isUploading) return;\r\n\r\n try {\r\n const results = await uploadAll();\r\n onUploadComplete?.(files);\r\n return results;\r\n } catch (error) {\r\n // Error is already handled in the hook\r\n console.error(\"Upload failed:\", error);\r\n }\r\n }, [hasPendingFiles, isUploading, uploadAll, files, onUploadComplete]);\r\n\r\n // Memoized theme and variant classes\r\n const themeClasses = useMemo(() => {\r\n const baseClasses =\r\n \"border-2 border-dashed rounded-lg transition-all duration-200\";\r\n\r\n if (theme === \"dark\") {\r\n return `${baseClasses} bg-gray-800 border-gray-600 text-gray-200`;\r\n }\r\n\r\n if (variant === \"filled\") {\r\n return `${baseClasses} bg-blue-50 border-blue-300 text-blue-700`;\r\n }\r\n\r\n if (variant === \"minimal\") {\r\n return `${baseClasses} border-gray-300 text-gray-600`;\r\n }\r\n\r\n return `${baseClasses} bg-white border-gray-300 text-gray-600`;\r\n }, [theme, variant]);\r\n\r\n const sizeClasses = useMemo(() => {\r\n switch (size) {\r\n case \"sm\":\r\n return \"p-4\";\r\n case \"lg\":\r\n return \"p-8\";\r\n default:\r\n return \"p-6\";\r\n }\r\n }, [size]);\r\n\r\n const buttonClasses = useMemo(() => {\r\n const baseClasses = \"px-4 py-2 rounded-lg font-medium transition-colors\";\r\n\r\n if (theme === \"dark\") {\r\n return `${baseClasses} bg-blue-600 hover:bg-blue-700 text-white`;\r\n }\r\n\r\n return `${baseClasses} bg-blue-600 hover:bg-blue-700 text-white`;\r\n }, [theme]);\r\n\r\n return (\r\n <div className={`space-y-4 ${className}`}>\r\n {/* Error Display */}\r\n {error && (\r\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\r\n <div className=\"flex items-center\">\r\n <span className=\"text-red-600 mr-2\">⚠️</span>\r\n <p className=\"text-red-800 text-sm\">{error}</p>\r\n <button\r\n onClick={() => onValidationError?.(error)}\r\n className=\"ml-auto text-red-600 hover:text-red-800\"\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Dropzone */}\r\n <div\r\n {...getRootProps()}\r\n className={`\r\n ${themeClasses}\r\n ${sizeClasses}\r\n ${isDragActive ? \"border-blue-500 bg-blue-50\" : \"\"}\r\n ${disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer hover:border-blue-400 hover:bg-blue-50\"}\r\n `}\r\n >\r\n <input {...getInputProps()} />\r\n\r\n <div className=\"text-center\">\r\n <div className=\"text-4xl mb-4\">📁</div>\r\n <p className=\"text-lg font-medium mb-2\">\r\n {isDragActive ? \"Drop files here\" : \"Drag & drop files here\"}\r\n </p>\r\n <p className=\"text-sm opacity-75\">or click to select files</p>\r\n <div className=\"mt-4 text-xs opacity-60\">\r\n <p>\r\n Max files: {maxFiles} • Max size:{\" \"}\r\n {Math.round((maxSize || maxFileSize) / FILE_SIZE.BYTES_PER_MB)}MB\r\n </p>\r\n <p>Allowed types: {allowedTypes.join(\", \")}</p>\r\n {folder && (\r\n <p className=\"mt-1 text-blue-600\">📁 Uploading to: {folder}</p>\r\n )}\r\n <p className=\"mt-1 text-gray-500\">Provider: {provider.getName()}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* File List */}\r\n {hasFiles && (\r\n <div className=\"space-y-3\">\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-medium\">\r\n Selected Files ({files.length})\r\n </h3>\r\n <div className=\"space-x-2\">\r\n <button\r\n onClick={handleUpload}\r\n disabled={!hasPendingFiles || isUploading}\r\n className={`${buttonClasses} disabled:opacity-50 disabled:cursor-not-allowed`}\r\n >\r\n {isUploading ? \"Uploading...\" : \"Upload All\"}\r\n </button>\r\n <button\r\n onClick={clearAll}\r\n className=\"px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors\"\r\n >\r\n Clear All\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n {files.map((file) => (\r\n <FileItem\r\n key={file.id}\r\n file={file}\r\n progress={uploadProgress[file.id] || 0}\r\n onRemove={removeFile}\r\n onRetry={retryUpload}\r\n onCancel={cancelUpload}\r\n showPreview={showPreview}\r\n showProgress={showProgress}\r\n showFileSize={showFileSize}\r\n showFileType={showFileType}\r\n theme={typeof theme === \"string\" ? theme : theme.mode}\r\n />\r\n ))}\r\n </div>\r\n\r\n {/* Upload Summary */}\r\n {hasFiles && (\r\n <div className=\"p-3 bg-gray-50 rounded-lg text-sm text-gray-600\">\r\n <div className=\"flex justify-between items-center\">\r\n <span>\r\n {successFiles.length} uploaded • {pendingFiles.length} pending\r\n • {errorFiles.length} failed\r\n </span>\r\n <span>\r\n Total:{\" \"}\r\n {FileProcessor.formatFileSize(\r\n files.reduce((sum, f) => sum + f.size, 0)\r\n )}\r\n </span>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n"]}