@molecule/app-image-gallery-editor-react
Feature · image-gallery-editor · App (browser) · v1.0.3 · Apache-2.0
Hero drop zone + thumbnail slot grid
npm install @molecule/app-image-gallery-editor-reactHow it works
@molecule/app-image-gallery-editor-react is a ready-made image-gallery-editor feature for the app (browser) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.
import { useState } from 'react'
import { ImageGalleryEditor } from '@molecule/app-image-gallery-editor-react'
function GalleryEditor() {
const [slots, setSlots] = useState<(string | null)[]>(Array(4).fill(null))
return (
<ImageGalleryEditor
slots={slots}
onChange={setSlots}
onPickFiles={async (files) => {
// upload each file, return persisted URLs (null keeps a slot empty)
return Array.from(files).map((f) => URL.createObjectURL(f))
}}
header={<h3>Image Gallery</h3>}
counter={`${slots.filter(Boolean).length} / 24 Photos`}
/>
)
}Works with: @molecule/app-icons, @molecule/app-react, @molecule/app-ui, @molecule/app-ui-react
Reference
@molecule/app-image-gallery-editor-react — hero drop zone + side grid of
thumbnail slots. Click an empty slot or the drop zone to upload; click a
filled slot to remove (confirmed via the shared ConfirmDialog from
@molecule/app-ui-react).
Stateless about persistence — the consumer owns the slot array and handles
uploads via onPickFiles (defaults to local object URLs for preview).
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { useState } from 'react'
import { ImageGalleryEditor } from '@molecule/app-image-gallery-editor-react'
function GalleryEditor() {
const [slots, setSlots] = useState<(string | null)[]>(Array(4).fill(null))
return (
<ImageGalleryEditor
slots={slots}
onChange={setSlots}
onPickFiles={async (files) => {
// upload each file, return persisted URLs (null keeps a slot empty)
return Array.from(files).map((f) => URL.createObjectURL(f))
}}
header={<h3>Image Gallery</h3>}
counter={`${slots.filter(Boolean).length} / 24 Photos`}
/>
)
}
Type
feature
Installation
npm install @molecule/app-image-gallery-editor-react @molecule/app-icons @molecule/app-react @molecule/app-ui @molecule/app-ui-react react
npm install -D @types/react
API
Interfaces
ImageGalleryEditorProps
Props for ImageGalleryEditor.
interface ImageGalleryEditorProps {
/** Ordered slots, `null` for empty. Length determines slot count. */
slots: (string | null)[]
onChange: (slots: (string | null)[]) => void
/** Called when the user picks files; defaults to a local object URL. */
onPickFiles?: (files: FileList) => Promise<(string | null)[]> | (string | null)[]
maxImages?: number
/** Header heading + subtitle slot (renders left of the photo counter). */
header?: ReactNode
/** Photo-counter label (e.g. "3 / 24 Photos"). */
counter?: ReactNode
dropZoneTitle?: ReactNode
dropZoneHint?: ReactNode
confirmRemoveMessage?: string
statusMessage?: ReactNode
/**
* Glyph rendered in empty slots — a typed `IconName` from the bonded
* `@molecule/app-icons` set (an unknown name is a type error, not a blank).
*/
emptySlotIcon?: IconName
}
Functions
ImageGalleryEditor(props)
Editable image gallery primitive.
function ImageGalleryEditor({
slots,
onChange,
onPickFiles,
maxImages = 24,
header,
counter,
dropZoneTitle = 'Drag and drop assets here',
dropZoneHint = 'or click to browse local files',
confirmRemoveMessage = 'Remove this image?',
statusMessage,
emptySlotIcon = 'image',
}: ImageGalleryEditorProps): JSX.Element
Injection Notes
Requirements
Peer dependencies:
@molecule/app-icons^1.0.1@molecule/app-react^1.0.1@molecule/app-ui^1.0.1@molecule/app-ui-react^1.2.0react^18.0.0 || ^19.0.0
Runtime Dependencies
-
@molecule/app-icons -
@molecule/app-react -
@molecule/app-ui -
@molecule/app-ui-react -
react -
Styling is 100% ClassMap (
getClassMap()/cm.*) — the editor renders correctly out of the box under any bonded styling library and needs NO per-app Tailwind@sourcescan of this package. (It previously hardcoded raw Tailwind + Material-3 utility classes that no scaffold@source-scans, so even thehiddenfile input never generated a rule and rendered visible; the file input is now hidden with an inlinedisplay:none.) The fewstyle={...}values (grid-column span, aspect ratio, corner radius, the dashed drop-zone border,object-fit, dim opacity,display:none) are the documented ClassMap-can't-express cases and use real theme tokens. -
Icons are real SVG glyphs from
@molecule/app-ui-react's<Icon>(upload,trash, and theemptySlotIcon— a typedIconName) — NO Material Symbols font to load. Requires a bonded@molecule/app-iconsset. -
The filled-slot delete affordance is always visible (touch-friendly) rather than hover-revealed.
-
dropZoneTitle/dropZoneHint/confirmRemoveMessagedefault to English strings — pass translated values (t('...')) in localized apps. -
getClassMap()requires a bonded ClassMap for the layout primitives.