import React from 'react'; export type FileUploadSize = 'sm' | 'md'; /** A file the control refused, and the reason, so the caller can say so. */ export interface RejectedFile { file: File; reason: 'type' | 'size' | 'count'; message: string; } export interface FileUploadProps { /** Field label. Also the accessible name of the file input. */ label?: React.ReactNode; /** Helper text below the control. */ description?: React.ReactNode; /** Replaces the helper text when `isInvalid` is set. */ errorMessage?: React.ReactNode; isInvalid?: boolean; isDisabled?: boolean; /** Matches the Figma `Size` variant when drawn. Height of the drop target. */ size?: FileUploadSize; /** Native `accept` — a comma-separated list of extensions or MIME types. */ accept?: string; /** Allow more than one file. */ multiple?: boolean; /** Reject anything larger, in bytes. */ maxSize?: number; /** Reject once this many files are held. Only meaningful with `multiple`. */ maxFiles?: number; /** * The files held. Pass it to control the list; omit and the component keeps * its own. A controlled list is the usual case, because the caller is the * only thing that knows which uploads have since succeeded or failed. */ files?: readonly File[]; /** Fires with the full list after every add or remove, never with a delta. */ onChange?: (files: File[]) => void; /** Fires with anything refused by `accept`, `maxSize` or `maxFiles`. */ onReject?: (rejected: RejectedFile[]) => void; /** Call-to-action inside the drop target. */ prompt?: React.ReactNode; /** Second line inside the drop target — the constraints, in words. */ hint?: React.ReactNode; /** Accessible label for each file's remove button. Receives the file name. */ removeLabel?: (name: string) => string; /** Every other string the control renders, for translation. English by default. */ labels?: FileUploadLabels; className?: string; wrapperClassName?: string; id?: string; name?: string; } /** * The refusals are `RejectedFile.message`; the caller shows them. Sizes arrive * already formatted for the locale — "12 MB". Counts arrive as numbers so a * translation can choose its plural form. */ export interface FileUploadLabels { /** "report.xlsx is not an accepted file type." */ notAccepted?: (name: string) => string; /** "scan.pdf is 12 MB, over the 10 MB limit." */ tooLarge?: (name: string, size: string, limit: string) => string; /** "notes.txt was not added — at most 3 files." */ tooMany?: (name: string, max: number) => string; /** "notes.txt was not added — only one file is allowed." */ onlyOne?: (name: string) => string; /** Announced as files are added and removed — "2 files selected". */ selected?: (count: number) => string; } /** * FileUpload — a drop target wrapped around a real ``. * * Drawn in Figma as `File Upload` (1367:2333) — two sizes by five states. The * measurements came from `Input` and `EmptyState` rather than being invented: * the border, radius and disabled treatment are Input's; the centred * icon-over-text stack is EmptyState's. Figma draws the drop zone alone, the * same split `Input` makes against `Form Field`. * * THE INPUT IS THE CONTROL. THE DROP ZONE IS DECORATION. * * The usual build of this component is a `