Skip to content

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
UtilityPathNotes
getInitialssrc/types/canary/utilities/get-initials.tsExtracted from item-grid-columns
getCroppedImagesrc/types/canary/utilities/get-cropped-image.tsCanvas-based crop helper
TypePath
ImageFieldConfig, ImageMimeType, ImageInput, ImageUploadResult, CropData, PixelCropsrc/types/canary/utilities/image-field-config.ts
ImageUploadHandler, ImageReachabilityChecksrc/types/canary/utilities/image-upload-handlers.ts

alert-dialog, checkbox, popover, progress, slider, aspect-ratio — all in src/components/canary/primitives/.

ComponentPathKey behavior
CopyrightAcknowledgmentatoms/copyright-acknowledgment/Mandatory checkbox, disabled submit until checked
ImageCellDisplayatoms/grid/image/image-cell-display.tsxAG Grid cell renderer, composes ImageDisplay + ImageHoverPreview
ImageCellEditoratoms/grid/image/image-cell-editor.tsxAG Grid cell editor with isPopup(), createImageCellEditor factory
ComponentChange
BadgeAdded error-overlay CVA variant
AvatarAdded entityName prop, getInitials extracted to utility
ComponentPathKey behavior
ImageDisplaymolecules/image-display/Loaded/loading/error/no-image states; baked-in edit via onImageChange + config (double-click/Enter opens dialog)
ImageDropZonemolecules/image-drop-zone/Unified drag-drop, file picker, URL entry, clipboard paste
ImagePreviewEditormolecules/image-preview-editor/Crop/zoom/rotate/pan via react-easy-crop
ImageHoverPreviewmolecules/image-hover-preview/500ms delay popover on thumbnail hover
ImageInspectorOverlaymolecules/image-inspector-overlay/Full-size modal; controlled + uncontrolled modes; optional Edit button
ImageComparisonLayoutmolecules/image-comparison-layout/Desktop side-by-side / mobile tabs; baked-in Accept/Dismiss/Upload New buttons
ImageFormFieldmolecules/form/image/Composes ImageDisplay with onImageChange; hover eye (inspect) + trash (remove with AlertDialog)
ComponentPathKey behavior
ImageUploadDialogorganisms/shared/image-upload-dialog/State machine: EmptyImage, ProvidedImage, EditExisting, FailedValidation, Uploading, Warn phases

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.

CriterionGoalActualStatus
Components implemented1919Met
Unit tests~115~112Met (within margin)
Storybook stories~79~76Met (within margin)
Storybook buildsExit 0Exit 0Met
LinterZero warningsZero warningsMet
Barrel exportsUpdatedUpdatedMet
  1. ImageComparisonLayout interactive story (#7 from inconsistencies audit) — low priority.
  2. Backend upload integration — explicitly deferred, prop interfaces ready.
  3. Avatar rewrite to compose ImageDisplay — deferred to post-production validation.

Copyright: (c) Arda Systems 2025-2026, All rights reserved