-
- {fileObj.name}
-
-
-
- {formatBytes(fileObj.size)}
-
-
- Ready
-
+
+ {isUploaded && (
+
+ Already uploaded
+
+ )}
+
+
+
+ Max size: {field.maxSizeMb}MB
+ {field.isMultiple &&
+ ` • Files: ${currentFiles.length}/${maxFiles}`}
+
+
+
+ {/* Help / Description Text */}
+ {field.helpText && (
+
+ {field.helpText}
+
+ )}
+
+ {/* Selected Files List */}
+ {currentFiles.length > 0 && (
+
+ {currentFiles.map((fileObj, idx) => (
+
+
+
+
+
+
+
+
+ {fileObj.name}
+
+
+
+ {formatBytes(fileObj.size)}
+
+
+ Ready
+
+
+
+
+
+ {/* Hidden inputs to represent file details in traditional form submissions */}
+
+
+ ))}
+
+ )}
+
+ {/* Dropzone area */}
+ {!reachedLimit &&
+ (variant === "minimal" ? (
+
+
+ {
+ 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"}
+
+
+ ) : 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}`}
+ />
+
+
+ {isDragOver ? (
+
+ ) : (
+
+ )}
-
-
- {/* Hidden inputs to represent file details in traditional form submissions */}
+
+
+ {isDragOver ? "Drop to replace" : "Document uploaded"}
+
+
+ {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"}
+
))}
-
- )}
- {/* Dropzone area */}
- {!reachedLimit && (
- variant === "minimal" ? (
-
-
-
{
- 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"}
-
+ {/* Validation Error Message */}
+ {fieldError && (
+
- ) : (
-
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 && (
-
- )}
-