Image Upload Components — Post-Implementation Specification
This document reflects the final implementation as merged in PR #63, noting deviations from the original specification.
- Repository:
ux-prototype(Arda-cards/ux-prototype) - Target directories:
src/components/canary/(atoms, molecules, organisms),src/types/canary/utilities/ - No backend integration — all upload workflows use mock data
Component Inventory (19 components)
Section titled “Component Inventory (19 components)”Utilities (2)
Section titled “Utilities (2)”| Utility | Path | Notes |
|---|---|---|
getInitials | src/types/canary/utilities/get-initials.ts | Extracted from item-grid-columns |
getCroppedImage | src/types/canary/utilities/get-cropped-image.ts | Canvas-based crop helper |
Types (1 module)
Section titled “Types (1 module)”| Type | Path |
|---|---|
ImageFieldConfig, ImageMimeType, ImageInput, ImageUploadResult, CropData, PixelCrop | src/types/canary/utilities/image-field-config.ts |
ImageUploadHandler, ImageReachabilityCheck | src/types/canary/utilities/image-upload-handlers.ts |
Primitives (6)
Section titled “Primitives (6)”alert-dialog, checkbox, popover, progress, slider, aspect-ratio
— all in src/components/canary/primitives/.
Atoms (3)
Section titled “Atoms (3)”| Component | Path | Key behavior |
|---|---|---|
CopyrightAcknowledgment | atoms/copyright-acknowledgment/ | Mandatory checkbox, disabled submit until checked |
ImageCellDisplay | atoms/grid/image/image-cell-display.tsx | AG Grid cell renderer, composes ImageDisplay + ImageHoverPreview |
ImageCellEditor | atoms/grid/image/image-cell-editor.tsx | AG Grid cell editor with isPopup(), createImageCellEditor factory |
Modified Atoms (2)
Section titled “Modified Atoms (2)”| Component | Change |
|---|---|
Badge | Added error-overlay CVA variant |
Avatar | Added entityName prop, getInitials extracted to utility |
Molecules (7)
Section titled “Molecules (7)”| Component | Path | Key behavior |
|---|---|---|
ImageDisplay | molecules/image-display/ | Loaded/loading/error/no-image states; baked-in edit via onImageChange + config (double-click/Enter opens dialog) |
ImageDropZone | molecules/image-drop-zone/ | Unified drag-drop, file picker, URL entry, clipboard paste |
ImagePreviewEditor | molecules/image-preview-editor/ | Crop/zoom/rotate/pan via react-easy-crop |
ImageHoverPreview | molecules/image-hover-preview/ | 500ms delay popover on thumbnail hover |
ImageInspectorOverlay | molecules/image-inspector-overlay/ | Full-size modal; controlled + uncontrolled modes; optional Edit button |
ImageComparisonLayout | molecules/image-comparison-layout/ | Desktop side-by-side / mobile tabs; baked-in Accept/Dismiss/Upload New buttons |
ImageFormField | molecules/form/image/ | Composes ImageDisplay with onImageChange; hover eye (inspect) + trash (remove with AlertDialog) |
Organisms (1)
Section titled “Organisms (1)”| Component | Path | Key behavior |
|---|---|---|
ImageUploadDialog | organisms/shared/image-upload-dialog/ | State machine: EmptyImage, ProvidedImage, EditExisting, FailedValidation, Uploading, Warn phases |
Deviations from Original Specification
Section titled “Deviations from Original Specification”D-01: ImageFormField interaction model changed
Section titled “D-01: ImageFormField interaction model changed”Original: Three hover icons (eye, pencil, trash) with external dialog wiring.
Final: Two hover icons (eye, trash). Edit is handled by the underlying
ImageDisplay via onImageChange + config. No pencil icon — double-click
or Enter on the image opens the upload dialog.
Reason: Baking the edit flow into ImageDisplay eliminated the need for
a separate edit affordance on ImageFormField. The pencil icon created
competing interaction paths.
D-02: ImageInspectorOverlay supports uncontrolled mode
Section titled “D-02: ImageInspectorOverlay supports uncontrolled mode”Original: Controlled-only (open + onClose required).
Final: open is optional. When omitted, the component renders a trigger
button and manages its own open state.
Reason: Reduces consumer boilerplate and aligns with ImageDisplay’s
self-managed pattern.
D-03: ImageComparisonLayout has baked-in action buttons
Section titled “D-03: ImageComparisonLayout has baked-in action buttons”Original: Layout-only component; consumers wire action buttons externally.
Final: Action buttons (Accept, Dismiss, Upload New) are rendered internally when the corresponding callback props are provided.
Reason: Consistent with the baked-in interaction principle applied across the suite.
D-04: ImageUploadDialog gained EditExisting state
Section titled “D-04: ImageUploadDialog gained EditExisting state”Original: Dialog handles only new uploads (EmptyImage state).
Final: Added EditExisting state for editing images that already have a
URL. The dialog pre-loads the current image and shows the comparison layout.
Reason: Required for the ImageDisplay double-click edit flow — when a
user edits an existing image, the dialog must show the current image and
allow replacement.
D-05: Use-case story framework generalized
Section titled “D-05: Use-case story framework generalized”Original: Not in the component specification.
Final: createWorkflowStories factory added to the use-case framework,
enabling Interactive/Stepwise/Automated story variants for the edit-upload
workflow.
Reason: The edit flow spans multiple components and states. A stepwise walkthrough was needed to demonstrate the full lifecycle for stakeholder review. The generic factory was a natural extraction.
Metrics vs. Goal
Section titled “Metrics vs. Goal”| Criterion | Goal | Actual | Status |
|---|---|---|---|
| Components implemented | 19 | 19 | Met |
| Unit tests | ~115 | ~112 | Met (within margin) |
| Storybook stories | ~79 | ~76 | Met (within margin) |
| Storybook builds | Exit 0 | Exit 0 | Met |
| Linter | Zero warnings | Zero warnings | Met |
| Barrel exports | Updated | Updated | Met |
Open Items
Section titled “Open Items”- ImageComparisonLayout interactive story (#7 from inconsistencies audit) — low priority.
- Backend upload integration — explicitly deferred, prop interfaces ready.
- Avatar rewrite to compose ImageDisplay — deferred to post-production validation.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved