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)
Resolved Findings
Section titled “Resolved Findings”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”__mocks__ directorySeverity: 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 AlertDialogThe 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.
Open Findings
Section titled “Open Findings”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.
Verified Correct Components
Section titled “Verified Correct Components”These components have properly baked-in behaviors with no externalization issues:
| Component | Pattern | Status |
|---|---|---|
| ImageDisplay | Internal dialog state, onImageChange + config | Correct |
| ImageHoverPreview | Internal popover + timer state | Correct |
| ImagePreviewEditor | Internal crop/zoom/rotate state, event callbacks | Correct |
| ImageDropZone | Internal URL/error state, event callbacks | Correct |
| ImageUploadDialog | Internal state machine (6 phases) | Correct |
| ImageComparisonLayout | Layout + optional action callbacks | Correct |
| ImageCellDisplay | Pure renderer, composes ImageDisplay + HoverPreview | Correct |
| CopyrightAcknowledgment | Simple controlled atom | Correct |
| ImageFormField | Composes ImageDisplay + inspector + remove dialog | Correct |
| ImageInspectorOverlay | Controlled + uncontrolled modes | Correct |
| ImageCellEditor | Imperative AG Grid lifecycle (intentional divergence) | Correct |
Remediation Summary
Section titled “Remediation Summary”| # | Item | Original Severity | Status |
|---|---|---|---|
| 1 | ImageFormField edit/inspect stubs | Critical | Resolved (PR #63) |
| 2 | Mock imports in production code | Critical | Resolved (PR #63) |
| 3 | ImageInspectorOverlay uncontrolled mode | Moderate | Resolved (PR #63) |
| 4 | ImageFormField compose ImageDisplay | Moderate | Resolved (PR #63) |
| 5 | ImageCellEditor dialog duplication | Moderate | No fix required (by design) |
| 6 | FullFlow story for ImageUploadDialog | Low | Resolved (PR #63) |
| 7 | ImageComparisonLayout interactive story | Low | Open |
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved