A client-side React component providing a drag-and-drop file upload zone with support for both simple synchronous file handling and async managed upload workflows (e.g., presigned URL uploads). ## Key Components ### Interfaces - **`ManagedFileEntry`** — Represents an async upload entry with `id`, `fileName`, `fileSize`, `status` (`"uploading" | "uploaded" | "error"`), and optional `error` message. - **`FileUploadProps`** — Full prop surface for the component, supporting both simple (`value`/`onChange`) and managed (`managedFiles`/`onRemoveManagedFile`) modes. ### Internal Utilities - **`formatFileSize(bytes)`** — Converts byte count to a human-readable string (B, KB, MB, GB). - **`matchesAccept(file, accept)`** — Validates a `File` against an `accept` string (extension, wildcard MIME, or exact MIME). - **`dragHasFiles(e)`** — Checks whether a native `DragEvent` carries file payloads. ### Component - **`FileUpload`** — Main export. Renders a dropzone with file list, validation, and optional window-level drop capture. ## Usage Example ```typescript // Simple mode — synchronous, single file setFile(f as File)} accept="image/*" maxSize={5 * 1024 * 1024} fieldLabel="Attachment" /> // Managed mode — async upload workflow uploadToPresignedUrl(files as File[])} onRemoveManagedFile={(id) => removeFile(id)} onDownloadManagedFile={(id) => downloadFile(id)} multiple accept=".pdf,.doc,.docx" maxFiles={5} acceptWindowDrops // captures drops anywhere in the window /> ``` ## Key Behaviors | Feature | Detail | |---|---| | Mode detection | `managedFiles !== undefined` switches to managed mode | | Validation | Type, size, and count checks before `onChange` fires | | Window drops | `acceptWindowDrops` suppresses browser default and routes drops here | | Single-file mode | Dropzone hides after a file is selected | | Scroll cap | `maxListHeight` constrains the file list with independent scroll |