handleDrag(e, field.fileKey, true)}
- onDragLeave={(e) => handleDrag(e, field.fileKey, false)}
- onDrop={(e) => handleDrop(e, field)}
- className={cn(
- "group relative flex items-center gap-4 rounded-lg border p-4 transition-all",
- isDragOver
- ? "border-2 border-dashed border-primary bg-primary/5 dark:bg-primary/10"
- : "border-emerald-300/70 bg-emerald-50/60 dark:border-emerald-500/30 dark:bg-emerald-500/10",
- disabled &&
- "opacity-50 pointer-events-none cursor-not-allowed",
- )}
- >
-
handleFileSelect(e, field)}
- id={`file-input-${field.fileKey}`}
- className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
- aria-label={`Replace ${field.fileLabel}`}
+ className="absolute inset-0 z-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed"
+ aria-label={`Add files to ${field.fileLabel}`}
/>
+ )}
-
-
- {isDragOver ? "Drop to replace" : "Document uploaded"}
-
- {existingForField.length > 0 ? (
-
- {existingForField.map((f, idx) => (
+ {(existingForField.length > 0 || currentFiles.length > 0) && (
+
+ {/* Already-saved (server) files — view/download only */}
+ {existingForField.map((f, idx) => (
+
- ) : (
-
- {isDragOver
- ? "Release to replace the document on file."
- : "Saved to your application. Drag a new file here or click to replace it."}
-
+ ))}
+
+ {/* Just-added (in-memory) files */}
+ {currentFiles.map((fileObj, idx) => (
+
+
+
+
+ {fileObj.name}
+
+
+ {formatBytes(fileObj.size)}
+
+
+
+ Ready
+
+
removeFile(field.fileKey, idx)}
+ className={cn(
+ "rounded-md p-1 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
+ disabled && "pointer-events-none opacity-50",
+ )}
+ aria-label={`Remove file ${fileObj.name}`}
+ >
+
+
+
+
+ ))}
+
+ )}
+
+ {reachedLimit ? (
+
+
+ Maximum of {maxFiles} files reached
+
+ ) : (
+
0 || currentFiles.length > 0
+ ? "py-1"
+ : "py-6",
)}
-
-
-
-
- Replace
-
-
- ) : (
-
handleDrag(e, field.fileKey, true)}
- onDragLeave={(e) => handleDrag(e, field.fileKey, false)}
- onDrop={(e) => handleDrop(e, field)}
- className={cn(
- "relative border-2 border-dashed rounded-lg p-6 flex flex-col items-center justify-center text-center transition-all bg-card/50",
- isDragOver
- ? "border-primary bg-primary/5 dark:bg-primary/10"
- : "border-border hover:border-primary/50 hover:bg-muted/10",
- fieldError &&
- "border-destructive hover:border-destructive/80",
- disabled &&
- "opacity-50 pointer-events-none cursor-not-allowed",
- )}
- >
-
handleFileSelect(e, field)}
- id={`file-input-${field.fileKey}`}
- className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
- />
-
-
-
+ 0 || currentFiles.length > 0
+ ? "p-1.5"
+ : "p-3",
)}
- />
+ >
+ 0 ||
+ currentFiles.length > 0
+ ? "h-4 w-4"
+ : "h-6 w-6",
+ isDragOver && "animate-bounce text-primary",
+ )}
+ />
+
+
+ {isDragOver
+ ? "Drop your files here"
+ : existingForField.length > 0 ||
+ currentFiles.length > 0
+ ? "Add more files, or "
+ : "Drag & drop your files here, or "}
+ {!isDragOver && (
+ browse
+ )}
+
+
+ {field.allowedExtensions.join(", ").toUpperCase() ||
+ "All formats"}
+ {" • "}
+ {currentFiles.length}/{maxFiles} added
+
+ )}
+
+ ) : (
+ <>
+ {/* Selected Files List */}
+ {currentFiles.length > 0 && (
+
+ {currentFiles.map((fileObj, idx) => (
+ removeFile(field.fileKey, idx)}
+ />
+ ))}
+
+ )}
-
- Drag & drop your file here, or{" "}
-
- browse
-
-
+ {/* Dropzone area */}
+ {!reachedLimit &&
+ (variant === "minimal" ? (
+
+
+ fileInputRefs.current[field.fileKey]?.click()
+ }
+ className="gap-1.5 cursor-pointer"
+ >
+
+
+ {isUploaded ? "Replace File" : "Upload File"}
+
+
+
{
+ if (fileInputRefs.current) {
+ fileInputRefs.current[field.fileKey] = el;
+ }
+ }}
+ multiple={field.isMultiple}
+ accept={acceptString}
+ disabled={disabled}
+ onChange={(e) => handleFileSelect(e, field)}
+ className="hidden"
+ />
+
+ Accepts:{" "}
+ {field.allowedExtensions.join(", ").toUpperCase() ||
+ "All"}
+
+ {existingForField.length > 0 && (
+
+ {existingForField.map((f, idx) => (
+
+ ))}
+
+ )}
+
+ ) : isUploaded ? (
+ // Uploaded state: a solid success panel that still doubles as a
+ // replace target (click anywhere or drag a new file onto it).
+
handleDrag(e, field.fileKey, true)}
+ onDragLeave={(e) => handleDrag(e, field.fileKey, false)}
+ onDrop={(e) => handleDrop(e, field)}
+ className={cn(
+ "group relative flex items-center gap-4 rounded-lg border p-4 transition-all",
+ isDragOver
+ ? "border-2 border-dashed border-primary bg-primary/5 dark:bg-primary/10"
+ : "border-emerald-300/70 bg-emerald-50/60 dark:border-emerald-500/30 dark:bg-emerald-500/10",
+ disabled &&
+ "opacity-50 pointer-events-none cursor-not-allowed",
+ )}
+ >
+
handleFileSelect(e, field)}
+ id={`file-input-${field.fileKey}`}
+ className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
+ aria-label={`Replace ${field.fileLabel}`}
+ />
-
- Supported formats:{" "}
- {field.allowedExtensions.join(", ").toUpperCase() ||
- "All"}
-
-
- ))}
+
+ {isDragOver ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {isDragOver
+ ? "Drop to replace"
+ : "Document uploaded"}
+
+ {existingForField.length > 0 ? (
+
+ {existingForField.map((f, idx) => (
+
+ ))}
+
+ ) : (
+
+ {isDragOver
+ ? "Release to replace the document on file."
+ : "Saved to your application. Drag a new file here or click to replace it."}
+
+ )}
+
+
+
+
+ Replace
+
+
handleDrag(e, field.fileKey, true)}
+ onDragLeave={(e) => handleDrag(e, field.fileKey, false)}
+ onDrop={(e) => handleDrop(e, field)}
+ className={cn(
+ "relative border-2 border-dashed rounded-lg p-6 flex flex-col items-center justify-center text-center transition-all bg-card/50",
+ isDragOver
+ ? "border-primary bg-primary/5 dark:bg-primary/10"
+ : "border-border hover:border-primary/50 hover:bg-muted/10",
+ fieldError &&
+ "border-destructive hover:border-destructive/80",
+ disabled &&
+ "opacity-50 pointer-events-none cursor-not-allowed",
+ )}
+ >
+
handleFileSelect(e, field)}
+ id={`file-input-${field.fileKey}`}
+ className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
+ />
+
+
+
+
+
+
+ Drag & drop your file here, or{" "}
+
+ browse
+
+
+
+
+ Supported formats:{" "}
+ {field.allowedExtensions.join(", ").toUpperCase() ||
+ "All"}
+
+
+ ))}
+ >
+ )}
{/* Validation Error Message */}
{fieldError && (