Reusable React component for hero-style image uploading with client-side validation, preview, and flexible upload strategies including deferred (base64 preview) and custom authenticated upload handlers. ## Key Components ### `HeroImageUploaderProps` | Prop | Type | Description | |---|---|---| | `imageUrl` | `string?` | Existing image URL to display | | `onChange` | `(url: string \| undefined) => void` | Fires with new URL or `undefined` on removal | | `uploadEndpoint` | `string` | POST endpoint for default upload flow | | `height` | `number \| string` | Drop-zone height; numbers treated as `px` | | `objectFit` | `string` | CSS `object-fit` for preview image (default: `'cover'`) | | `deferUpload` | `boolean` | Return base64 data URL instead of uploading (unauthenticated flows) | | `onUpload` | `(file: File) => Promise` | Custom authenticated upload handler | | `onDelete` | `() => Promise` | Custom delete handler | ### Internal Logic - **`handleFile`** — validates MIME type (JPEG/PNG/WebP/GIF) and file size (≤ 5 MB), then routes to deferred preview, custom `onUpload`, or default `fetch` POST - **`handleRemove`** — calls optional `onDelete` before clearing state via `onChange(undefined)` - **`openDialog`** — programmatically triggers the hidden `` ## Usage Example ```typescript // Default upload flow setHeroImage(url)} /> // Deferred upload (unauthenticated preview) setLocalPreview(dataUrl)} /> // Custom authenticated upload { const { url } = await myAuthenticatedUpload(file); return url; }} onDelete={async () => { await myAuthenticatedDelete(currentImageId); }} onChange={(url) => setHeroImage(url)} height={400} objectFit="contain" /> ``` **Source:** [`hero-image-uploader.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/hero-image-uploader.tsx)