import { type Readable } from '@vielzeug/ripple'; export declare const formatBytes: (bytes: number) => string; /** Upload lifecycle status for a single file. `idle` covers both "no `upload` handler wired up" * (picker-only mode, fully supported) and "not started yet". */ export type FileUploadStatus = 'error' | 'idle' | 'success' | 'uploading'; /** Per-file upload snapshot. One reactive signal per file — see `createFileQueue` — not one * signal holding a map, so a progress tick for one file never invalidates another's bindings. */ export type FileUploadState = { error: string | null; loaded: number; speedBps: number; status: FileUploadStatus; total: number; }; /** * Consumer-supplied transport — this component has no built-in network layer (zero-dependency, * transport-agnostic by design, same reasoning as `courier`'s own fetch-wrapping-only stance). * This function is the seam between the UI's upload lifecycle (progress, retry, per-file * isolation) and however the app actually moves bytes (`fetch`, `XMLHttpRequest`, a presigned S3 * PUT, `@vielzeug/courier`, …). * * `resumeFrom` is a *hint*, not a guarantee: it's the byte offset the component last observed * via `onProgress` before the previous attempt failed (0 on a fresh upload). A transport that * supports byte ranges (e.g. an HTTP `Range`/`Content-Range` header, S3 multipart, tus) can use * it to genuinely resume from that point; a plain `fetch(url, { body: file })` can ignore it and * simply re-send the whole file — the UI still shows a resumed-from-N-bytes experience either * way, since the file itself was never dropped from memory. */ export type FileUploadFn = (file: File, ctx: { onProgress: (loaded: number, total: number) => void; resumeFrom: number; signal: AbortSignal; }) => Promise; export type FileQueueOptions = { accept: Readable; disabled: Readable; maxFiles: Readable; maxSize: Readable; multiple: Readable; onChange: (files: File[], originalEvent?: Event) => void; onRemove: (file: File, files: File[], originalEvent?: Event) => void; onUploadError: (file: File, error: unknown) => void; onUploadProgress: (file: File, loaded: number, total: number) => void; onUploadSuccess: (file: File) => void; upload: Readable; }; export type FileQueue = { addFiles(newFiles: File[], originalEvent?: Event): void; dispose(): void; readonly files: Readable; fileState(file: File): FileUploadState; removeFile(file: File, originalEvent?: Event): void; /** Validates `newFile` (accept/max-size) and, if accepted, swaps it in for `oldFile` in place * and starts its upload. Returns whether the replacement was accepted. Also fires `onRemove` * for `oldFile` — a replace is a removal-and-add that happen to land in the same slot, and a * consumer listening only for removal (e.g. to clean up a server-side record) still needs to * hear that the old file is gone. */ replaceFile(oldFile: File, newFile: File, originalEvent?: Event): boolean; retryUpload(file: File): void; statusIconName(file: File): string; uploadMetaText(file: File): string; uploadPercent(file: File): number; }; /** * Owns file selection *and* the opt-in upload lifecycle together — they were never really * separable (adding a file starts its upload; removing one must abort it; replacing one is both * at once). Independent of `html`/rendering, following the same shape as `datagrid`'s * `createDataGridControls` and `combobox`'s `combobox-options.ts`: a factory `file-input.ts` * wires into drag/drop/native-input events and the template, directly unit-testable without * mounting a component. * * Every file-level rule (accept, max-size, max-files, disabled) and every upload-lifecycle rule * (progress, retry-from-offset, per-file isolation) lives here in one place. */ export declare function createFileQueue(options: FileQueueOptions): FileQueue; //# sourceMappingURL=file-input-upload.d.ts.map