# Uplofile Uplofile is a composable React file upload library built from accessible UI primitives. It manages UI state, orchestration, and complex file upload lifecycles (uploading, removing, retrying) but leaves the network logic ("bring your own upload logic") entirely up to the user. ## Core Philosophy - Uploads are UI state problems disguised as network problems. - Uplofile doesn't prescribe `fetch`, `axios`, or S3. You provide an `upload` function that returns a Promise. - Unstyled by default: Use Tailwind CSS, CSS Modules, or any styling solution by passing standard `className` props. ## Key Components ### 1. `UplofileRoot` (The Provider) Manages the entire upload state. Must wrap all other components. - **`upload`**: `(file: File, signal: AbortSignal, setProgress: (pct: number) => void) => Promise<{ url: string; id?: string }>` - The core upload logic. - **`initial`**: `MaybePromise>>` - Pre-hydrated files from the server. If you pass a `Promise`, **you must catch/handle its rejection yourself** — `Root` does not attach a `.catch`, so a rejected `initial` promise becomes an unhandled rejection. Initial-load errors are consumer-owned, not surfaced through `item.error`. - **`onRemove`**: `(item: UploadFileItem, signal: AbortSignal) => Promise` - Optional server-side delete logic. If it throws/rejects, the item is kept (or restored, in `optimistic` mode) with `status: 'done'` and `item.error` set to the failure message, so `onChange` consumers can distinguish a failed removal from a successful one. `item.error` is cleared as soon as a new removal attempt begins, and `actions.remove(uid)` remains available to retry. - **`removeMode`**: `'optimistic'` (default) or `'strict'`. - **`beforeUpload`**: Hook to validate or transform files before they start uploading. - **`accept`, `multiple`, `maxCount`**: Standard HTML5 file constraints. Extension filters must be dot-prefixed, such as `.pdf` or `.tar.gz`. Invalid `accept` tokens are ignored, matching browser-permissive behavior. ### 2. `UplofileDropzone` A drag-and-drop area. Render-props allow styling based on drag state: ```tsx {({ isDragActive }) => (
Drop here
)}
``` ### 3. `UplofileTrigger` A button or element that opens the OS file dialog. ### 4. `UplofilePreview` Displays the list of files. By default, it renders a list, but can be customized completely using the `render` prop: ```tsx (
    {items.map((item) => (
  • {item.name} - {item.status} ({item.progress}%) {item.status === 'error' && }
  • ))}
)} /> ``` ### React Native (`uplofile/native`) Import from `uplofile/native` for React Native. - `Root` — wraps RN root view, integrates a document/image picker - `Trigger` — Pressable that opens the OS file picker - `Preview` — renders thumbnails using RN `` and action buttons By default (no `pickFiles` prop), `Root` falls back to `@react-native-documents/picker` and files are typed as `DocumentPickerResponse` instead of `File`. **This fallback is deprecated and will be removed in the next major version** — omitting `pickFiles` now logs a one-time deprecation warning per `Root` instance (silence it with `suppressDeprecationWarnings`). - **`pickFiles`**: `(accept: string | undefined, options: { multiple: boolean }) => Promise` — optional prop that replaces the built-in picker call entirely. When provided, `Root`'s file-source generic (`TFileSource`) is inferred from it, so `upload`, `beforeUpload`, and item types all get the picked asset's real shape with no casting. - **`suppressDeprecationWarnings`**: silences the one-time warning logged when `pickFiles` is omitted. Four adapters are named exports from `uplofile/native`, each a higher-order function that wraps a picker function you've already imported (the adapter itself never imports the picker package): - `adapterReactNativeDocumentsPicker` — wraps `@react-native-documents/picker`'s `pick()`. Throws on cancel (`err.code === "OPERATION_CANCELED"`). - `adapterExpoDocumentPicker` — wraps `expo-document-picker`'s `getDocumentAsync()`. Resolves `{ canceled: true, assets: null }` on cancel. - `adapterExpoImagePicker` — wraps `expo-image-picker`'s `launchImageLibraryAsync()`. Resolves `{ canceled: true, assets: null }` on cancel. - `adapterReactNativeImagePicker` — wraps `react-native-image-picker`'s `launchImageLibrary()`. Resolves `{ didCancel: true }` on cancel; a returned `errorCode` is thrown as an `Error` instead (this package reports errors rather than throwing them). `adapterExpoImagePicker` and `adapterReactNativeImagePicker` **ignore `accept`** — image-only pickers only filter by media category (images/videos), not MIME type or extension — and log a one-time, dev-only warning if a non-image/video `accept` is passed. ```tsx import { Root, Trigger, Preview, adapterExpoDocumentPicker } from 'uplofile/native'; import * as DocumentPicker from 'expo-document-picker'; function App() { return ( Select Files ); } ``` Peer dependency `@react-native-documents/picker` is only required while relying on the deprecated fallback; it will be dropped from peer dependencies in the next major alongside the fallback itself. No Dropzone or HiddenInput component — they are web-only. ### 5. Action Helpers - `` - `` - `` ## Status Lifecycle A file (`UploadFileItem`) moves through these statuses: `idle` -> `uploading` -> `done` (or `error` or `canceled`). If deleted, it moves to `removing`. ## Example Usage ```tsx import { UplofileRoot, UplofileDropzone, UplofileTrigger, UplofilePreview } from 'uplofile'; function App() { const handleUpload = async (file, signal, setProgress) => { // Implement your network request here setProgress(100); return { url: URL.createObjectURL(file) }; }; return ( Select Files ); } ``` ## Full Examples & References For more complex usage patterns, refer to the official documentation and interactive examples: - [Basic Uploader](https://uplofile.kristofajosh.dev/examples/basic) - [Dropzone Drag-and-Drop](https://uplofile.kristofajosh.dev/examples/dropzone) - [Image Gallery](https://uplofile.kristofajosh.dev/examples/image-gallery) - [Avatar / Profile Picture Upload](https://uplofile.kristofajosh.dev/examples/avatar) - [Advanced File List with Actions](https://uplofile.kristofajosh.dev/examples/file-list) - [HTML Form Integration](https://uplofile.kristofajosh.dev/examples/form) - [Video Uploader](https://uplofile.kristofajosh.dev/examples/video) - [Before Upload Validation](https://uplofile.kristofajosh.dev/examples/validation) - [Sortable Dnd-Kit Gallery](https://uplofile.kristofajosh.dev/examples/sortable-gallery) - [Pause / Resume (Resumable Uploads)](https://uplofile.kristofajosh.dev/examples/pause-resume) - [Batch Upload — Collect Files, Then Upload as One](https://uplofile.kristofajosh.dev/examples/batch-upload) - [Imperative Actions via Ref](https://uplofile.kristofajosh.dev/examples/root-imperative) - [useUplofile Hook Reference](https://uplofile.kristofajosh.dev/api/use-uplofile)