Skip to content

Component Behavior Inconsistencies Audit

Audit of image upload components for behaviors that should be baked into components but are instead externalized into stories, requiring consumer wiring, or otherwise inconsistent.

Date: 2026-03-25 Scope: All 19 image components in ux-prototype canary library Branch: jmpicnic/item-image-upload-components Last verified: 2026-03-25 (against main after PR #63 merge)


1. ImageFormField: Edit and Inspect actions are stubbed — RESOLVED

Section titled “1. ImageFormField: Edit and Inspect actions are stubbed — RESOLVED”

Severity: Critical → Resolved Resolved in: PR #63

ImageFormField now composes ImageDisplay with onImageChange + config, delegating the edit flow (double-click/Enter opens ImageUploadDialog). The inspect action opens ImageInspectorOverlay in controlled mode via an eye icon button. The pencil icon was removed — edit is handled by the underlying ImageDisplay interaction. Only two hover actions remain: eye (inspect) and trash (remove with AlertDialog confirmation).


2. Production components import from __mocks__ directory — RESOLVED

Section titled “2. Production components import from __mocks__ directory — RESOLVED”

Severity: Critical → Resolved Resolved in: PR #63

Mock imports (__mocks__/image-story-data) no longer appear in any production component files. The only remaining __mocks__ imports are in *.test.tsx files, which is the correct usage pattern.


3. ImageInspectorOverlay: No uncontrolled mode — RESOLVED

Section titled “3. ImageInspectorOverlay: No uncontrolled mode — RESOLVED”

Severity: Moderate → Resolved Resolved in: PR #63

The component now supports both controlled and uncontrolled modes. When open is omitted, the component manages its own state internally and renders a trigger button. When open is provided, controlled mode is used (original behavior preserved).


4. ImageFormField hover icons do not use ImageDisplay’s baked-in edit — RESOLVED

Section titled “4. ImageFormField hover icons do not use ImageDisplay’s baked-in edit — RESOLVED”

Severity: Moderate → Resolved Resolved in: PR #63

ImageFormField now composes ImageDisplay with onImageChange + config. The current pattern:

ImageFormField
├── ImageDisplay (with onImageChange + config → baked-in edit)
├── Hover overlay (pointer-events-none container)
│ ├── Eye button → opens ImageInspectorOverlay
│ └── Trash button → opens remove AlertDialog

The hover overlay uses pointer-events-none on its container with pointer-events-auto only on the icon buttons, so double-clicks pass through to the underlying ImageDisplay button.


5. ImageCellEditor duplicates dialog wiring that ImageDisplay now handles

Section titled “5. ImageCellEditor duplicates dialog wiring that ImageDisplay now handles”

Severity: Moderate — No fix required (by design)

Unchanged. The AG Grid cell editor lifecycle requires imperative control (getValue, stopEditing, isPopup), so the duplication is intentional.


6. ImageUploadDialog stories show isolated states — RESOLVED

Section titled “6. ImageUploadDialog stories show isolated states — RESOLVED”

Severity: Low → Resolved Resolved in: PR #63

A FullFlow story was added to image-upload-dialog.stories.tsx that embeds ImageDisplay with onImageChange + config to demonstrate the end-to-end baked-in flow from the dialog’s perspective.


7. ImageComparisonLayout stories don’t demonstrate the full accept/dismiss flow

Section titled “7. ImageComparisonLayout stories don’t demonstrate the full accept/dismiss flow”

File: molecules/image-comparison-layout/image-comparison-layout.stories.tsx Severity: Low

The DesktopSideBySide story passes onAccept, onDismiss, onUploadNew callbacks that use alert() for demonstration. A more complete story would show the state change (image updated, dialog closed) rather than just an alert.

Fix: Add an interactive story that shows the full accept flow with state update, similar to DoubleClickToEdit in ImageDisplay.


These components have properly baked-in behaviors with no externalization issues:

ComponentPatternStatus
ImageDisplayInternal dialog state, onImageChange + configCorrect
ImageHoverPreviewInternal popover + timer stateCorrect
ImagePreviewEditorInternal crop/zoom/rotate state, event callbacksCorrect
ImageDropZoneInternal URL/error state, event callbacksCorrect
ImageUploadDialogInternal state machine (6 phases)Correct
ImageComparisonLayoutLayout + optional action callbacksCorrect
ImageCellDisplayPure renderer, composes ImageDisplay + HoverPreviewCorrect
CopyrightAcknowledgmentSimple controlled atomCorrect
ImageFormFieldComposes ImageDisplay + inspector + remove dialogCorrect
ImageInspectorOverlayControlled + uncontrolled modesCorrect
ImageCellEditorImperative AG Grid lifecycle (intentional divergence)Correct

#ItemOriginal SeverityStatus
1ImageFormField edit/inspect stubsCriticalResolved (PR #63)
2Mock imports in production codeCriticalResolved (PR #63)
3ImageInspectorOverlay uncontrolled modeModerateResolved (PR #63)
4ImageFormField compose ImageDisplayModerateResolved (PR #63)
5ImageCellEditor dialog duplicationModerateNo fix required (by design)
6FullFlow story for ImageUploadDialogLowResolved (PR #63)
7ImageComparisonLayout interactive storyLowOpen

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