Files
2026-04-01 11:26:39 +02:00

204 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 09-md3-components
verified: 2026-04-01T11:30:00Z
status: passed
score: 16/16 must-haves verified
re_verification:
previous_status: passed
previous_score: 12/12
gaps_closed:
- "Hovering the tooltip info button reveals tooltip text without clicking (hoverTooltip state + onMouseEnter/onMouseLeave)"
- "Clicking the tooltip icon pins it open; clicking again dismisses it (click-unpin clears hoverTooltip to prevent sticky state)"
- "Tooltip icon appears beside helpText below the field, not above the field (helpTextPrefix prop passed to TextFieldMD3)"
- "Tooltip icon renders even when field has tooltipText but no helpText (guard is (helpText || helpTextPrefix) && !error)"
gaps_remaining: []
regressions: []
human_verification:
- test: "Floating label visual animation"
expected: "Labels in RemoteConfigStep and PasswordField inputs animate upward on focus and stay floated when a value is typed. On blur with empty field, label returns to center position."
why_human: "CSS :placeholder-shown pseudo-class behavior and transition animation cannot be verified with jsdom — JSDOM does not compute CSS or trigger CSS transitions."
- test: "MD3 button visual appearance"
expected: "Next/Download-All buttons appear as pill-shaped (rounded-full) with primary fill color. Back/Copy/Download buttons appear as pill-shaped with an outline border and transparent background."
why_human: "Tailwind class presence is verified programmatically, but rendered visual output (actual computed styles, color tokens resolving correctly) requires browser inspection."
- test: "StepIndicator visual states"
expected: "Step 1 shows a highlighted numbered circle (primary color ring). Completed steps show a checkmark circle. Connector lines between steps are filled (primary) for completed segments and muted (outline) for future. Dark mode renders correctly with no hardcoded colors."
why_human: "Semantic token resolution (bg-primary, border-outline etc.) to actual CSS custom property values requires browser rendering."
- test: "BackendCard elevation and shape"
expected: "Backend cards display with visibly rounded corners (rounded-xl = 12px) and a subtle shadow. Hovering an unselected card increases shadow. Selected card has elevated shadow."
why_human: "Shadow rendering and hover state transitions require browser inspection."
- test: "Tooltip icon placement (visual)"
expected: "Tooltip icon (ⓘ) appears visually inline to the left of helpText, below the floating-label input — not above it. On fields with no helpText, the icon still appears below the input."
why_human: "Flexbox inline rendering of helpTextPrefix inside TextFieldMD3 requires browser inspection to confirm correct visual position relative to input and helpText."
- test: "Tooltip hover appearance and pin behavior (manual)"
expected: "Hovering the ⓘ icon on a text field shows the tooltip panel below the field. Moving the mouse away hides it. Clicking the icon pins it open; moving mouse away keeps it open. Clicking again dismisses it even while hovering."
why_human: "fireEvent in JSDOM verifies state logic but not actual mouse pointer interaction feel, tooltip visual positioning, or whether content is readable at that position."
---
# Phase 9: MD3 Components Verification Report
**Phase Goal:** All interactive elements use MD3-styled primitives with consistent visual language across the entire wizard
**Verified:** 2026-04-01T11:30:00Z
**Status:** passed
**Re-verification:** Yes — after gap closure via Plan 09-05 (commits 23617c0 and d2b6da2)
## Goal Achievement
### Observable Truths
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | TextFieldMD3 renders an outlined input with a floating label that floats on focus | VERIFIED | `src/components/ui/TextFieldMD3.tsx` uses `peer-focus:top-3 peer-focus:scale-75` CSS peer utilities |
| 2 | TextFieldMD3 floating label floats when the field has a value | VERIFIED | `peer-[:not(:placeholder-shown)]:top-3 peer-[:not(:placeholder-shown)]:scale-75`; `placeholder=" "` drives CSS detection |
| 3 | TextFieldMD3 preserves htmlFor/id pairing so getByLabelText queries work | VERIFIED | `<label htmlFor={id}>` + `<input id={id}>` pattern; Test 2 explicitly verifies `getByLabelText` |
| 4 | MD3 button class constants exist for filled, outlined, and text variants | VERIFIED | `src/styles/md3-buttons.ts` exports `MD3_BTN_FILLED`, `MD3_BTN_OUTLINED`, `MD3_BTN_TEXT` with `rounded-full` classes |
| 5 | FieldRenderer text-branch tooltip button uses aria-label for accessibility | VERIFIED | FieldRenderer.tsx line 92: `aria-label={\`More info about \${field.label}\`}` on tooltip button; 4/4 DEBT-01 tests pass |
| 6 | Step indicator shows numbered circles for each wizard step | VERIFIED | StepIndicator.tsx: `w-8 h-8 rounded-full` spans with `{i + 1}` content for active/future steps |
| 7 | Completed steps display a checkmark and are clickable buttons | VERIFIED | StepIndicator.tsx: `<button>` with `&#10003;` checkmark; test confirms selector works |
| 8 | Current step is visually highlighted with primary color | VERIFIED | Active step uses `border-primary bg-primary/10 text-primary font-bold` — no hardcoded colors |
| 9 | Future steps appear muted | VERIFIED | Future steps use `border-outline text-on-surface-container/40` semantic tokens |
| 10 | Connector lines link steps — filled for completed, muted for future | VERIFIED | `bg-primary` if `isCompleted` else `bg-outline`; `aria-hidden="true"` applied |
| 11 | Clicking step 0 dispatches SET_REMOTE_PARAMS({}) then SET_STEP(0) | VERIFIED | `handleStepClick` logic unchanged; StepIndicator tests verify params are cleared and deployment state preserved |
| 12 | All text inputs in the wizard render with floating labels | VERIFIED | FieldRenderer text-branch, PasswordField, and BackendSelectionStep all use TextFieldMD3 |
| 13 | Hovering the tooltip icon reveals tooltip text without clicking | VERIFIED | FieldRenderer.tsx line 90-91: `onMouseEnter={() => setHoverTooltip(true)}` / `onMouseLeave={() => setHoverTooltip(false)}`; `tooltipVisible = showTooltip \|\| hoverTooltip`; FieldRenderer test "hovering tooltip button shows tooltip text" passes |
| 14 | Clicking the tooltip icon pins it open; clicking again dismisses it | VERIFIED | Click handler: `setShowTooltip(v => { if (v) setHoverTooltip(false); return !v; })` — clears hover on unpin to prevent sticky state; tests "pins through mouseLeave" and "clicking again dismisses" both pass |
| 15 | Tooltip icon appears beside helpText below the field, not above the field | VERIFIED | TextFieldMD3 `helpTextPrefix` prop renders icon inside `<div className="flex items-start gap-1">` below the input; `tooltipIcon` passed as `helpTextPrefix={tooltipIcon}` in FieldRenderer line 110 and PasswordField line 54 |
| 16 | Tooltip icon renders even when field has tooltipText but no helpText | VERIFIED | TextFieldMD3 guard changed to `(helpText \|\| helpTextPrefix) && !error` (line 67); Test 11 "renders helpTextPrefix alone when helpText is absent" passes |
**Score: 16/16 truths verified**
---
### Plan 09-05 Gap Closure — Truths #13#16
**Previously:** COMP-04 had 4 FAILED truths related to tooltip behavior and icon placement identified in UAT session (test 7).
**Now:** All 4 fixed in commit `23617c0` (feat) and `d2b6da2` (test):
- `TextFieldMD3.tsx` — added `helpTextPrefix?: React.ReactNode` prop; guard changed to `(helpText || helpTextPrefix) && !error`; renders `<div className="flex items-start gap-1">` wrapping prefix + helpText text
- `FieldRenderer.tsx` — added `hoverTooltip` state; moved tooltip icon from above-field to `tooltipIcon` element passed as `helpTextPrefix`; select-branch also gains hover support; click-unpin clears hoverTooltip
- `PasswordField.tsx` — same dual-state tooltip fix as FieldRenderer text-branch
7 new tests added (4 in FieldRenderer.test.tsx hover suite, 3 in TextFieldMD3.test.tsx Tests 9-11). All 186 tests pass.
---
### Required Artifacts
| Artifact | Expected | Status | Details |
|----------|----------|--------|---------|
| `src/components/ui/TextFieldMD3.tsx` | MD3 outlined text field with CSS floating label and helpTextPrefix slot | VERIFIED | 82 lines; exports `TextFieldMD3`; `helpTextPrefix?: React.ReactNode` in interface (line 10); guard `(helpText \|\| helpTextPrefix) && !error` (line 67) |
| `src/components/ui/TextFieldMD3.test.tsx` | Unit tests including helpTextPrefix behavior | VERIFIED | 11 tests (Tests 1-11); Tests 9-11 cover helpTextPrefix combinations |
| `src/styles/md3-buttons.ts` | MD3 button class constants | VERIFIED | Exports `MD3_BTN_FILLED`, `MD3_BTN_OUTLINED`, `MD3_BTN_TEXT` as string constants |
| `src/components/ui/FieldRenderer.test.tsx` | Tests for DEBT-01 aria-label consistency and tooltip hover behavior | VERIFIED | 8 tests total — 4 hover behavior tests + 4 DEBT-01 aria-label tests |
| `src/components/wizard/StepIndicator.tsx` | Rebuilt MD3 step indicator with circles and connectors | VERIFIED | Exports `StepIndicator`, uses `useWizard()` for state and dispatch |
| `src/components/ui/FieldRenderer.tsx` | Text-branch using TextFieldMD3 with tooltip below field via helpTextPrefix | VERIFIED | `hoverTooltip` state (line 15); `tooltipIcon` element (lines 86-97); `helpTextPrefix={tooltipIcon}` (line 110); select-branch has `onMouseEnter`/`onMouseLeave` (lines 53-54) |
| `src/components/ui/PasswordField.tsx` | Password field with tooltip below via helpTextPrefix and hover+click behavior | VERIFIED | `hoverTooltip` state (line 17); `tooltipIcon` element (lines 30-41); `helpTextPrefix={tooltipIcon}` (line 54); `tooltipVisible = showTooltip \|\| hoverTooltip` (line 43) |
| `src/components/ui/BackendCard.tsx` | MD3 elevation and shape | VERIFIED | `rounded-xl` on line 17; `shadow` / `shadow-md` / `hover:shadow-md` |
| `src/components/wizard/BackendSelectionStep.tsx` | All text inputs use TextFieldMD3 | VERIFIED | Imports `TextFieldMD3` and `MD3_BTN_FILLED`; TextFieldMD3 rendered for Remote name |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| `TextFieldMD3.tsx` | `react-hook-form` | `{...registration}` spread onto input | VERIFIED | Line 43: `{...registration}` spreads `UseFormRegisterReturn` onto `<input>` |
| `FieldRenderer.tsx` | `TextFieldMD3.tsx` | `import { TextFieldMD3 }` + render with `helpTextPrefix` | VERIFIED | Line 5 import; line 103 renders `<TextFieldMD3 helpTextPrefix={tooltipIcon}>` |
| `PasswordField.tsx` | `TextFieldMD3.tsx` | `import { TextFieldMD3 }` + render with `helpTextPrefix` and `suffix` | VERIFIED | Line 3 import; line 47 renders `<TextFieldMD3 helpTextPrefix={tooltipIcon} suffix={toggleButton}>` |
| `FieldRenderer.tsx` | tooltip hover state | `hoverTooltip` + `onMouseEnter`/`onMouseLeave` on `tooltipIcon` button | VERIFIED | Lines 15, 90-91: dual-state `showTooltip \|\| hoverTooltip`; click-unpin clears hover state (line 89) |
| `PasswordField.tsx` | tooltip hover state | `hoverTooltip` + `onMouseEnter`/`onMouseLeave` on `tooltipIcon` button | VERIFIED | Lines 17, 34-35: same dual-state pattern as FieldRenderer |
| `TextFieldMD3.tsx` | `helpTextPrefix` slot | `(helpText \|\| helpTextPrefix) && !error` guard + flex wrapper | VERIFIED | Line 67: guard enables prefix-only rendering; line 68-73: `<div className="flex items-start gap-1">` wraps prefix and helpText |
| `BackendSelectionStep.tsx` | `src/styles/md3-buttons.ts` | `import { MD3_BTN_FILLED }` | VERIFIED | Applied to Next button |
| `RemoteConfigStep.tsx` | `src/styles/md3-buttons.ts` | `import { MD3_BTN_FILLED, MD3_BTN_OUTLINED }` | VERIFIED | Applied to Back/Next buttons |
| `DeploymentStep.tsx` | `src/styles/md3-buttons.ts` | `import { MD3_BTN_FILLED, MD3_BTN_OUTLINED }` | VERIFIED | Applied to Back/Next buttons |
| `ReviewStep.tsx` | `src/styles/md3-buttons.ts` | `import { MD3_BTN_FILLED, MD3_BTN_OUTLINED }` | VERIFIED | Back = OUTLINED, Download All = FILLED |
| `OutputBlock.tsx` | `src/styles/md3-buttons.ts` | `import { MD3_BTN_OUTLINED }` | VERIFIED | `smallBtn` constant uses `MD3_BTN_OUTLINED` with size overrides |
| `StepIndicator.tsx` | `src/store/context.tsx` | `useWizard()` for state.currentStep and dispatch | VERIFIED | `const { state, dispatch } = useWizard()` |
---
### Requirements Coverage
| Requirement | Source Plan(s) | Description | Status | Evidence |
|-------------|---------------|-------------|--------|----------|
| COMP-01 | 09-01, 09-03, 09-04 | All text inputs render as MD3 outlined text fields with floating labels that animate on focus and when the field has content | VERIFIED | FieldRenderer text-branch, PasswordField, and BackendSelectionStep all use TextFieldMD3. No plain label+input blocks remain in wizard step files. |
| COMP-02 | 09-03 | Buttons follow MD3 hierarchy — filled for primary actions, outlined for secondary | VERIFIED | All 4 wizard steps + OutputBlock import and apply `MD3_BTN_FILLED` / `MD3_BTN_OUTLINED` correctly |
| COMP-03 | 09-03 | Cards and output blocks use MD3 elevation with shape tokens | VERIFIED | BackendCard: `rounded-xl` + `shadow`/`shadow-md`; OutputBlock pre: `rounded-xl shadow-sm` |
| COMP-04 | 09-02, 09-05 | Step indicator shows numbered circles with checkmarks, highlighted current, muted future; tooltip icon beside helpText below field, hover reveals tooltip | VERIFIED | StepIndicator rebuilt with circles, connector lines, semantic tokens; tooltip placement and hover behavior fixed in Plan 09-05 — all 4 gap truths (#13#16) now pass; 186/186 tests pass |
| DEBT-01 | 09-01 | FieldRenderer uses consistent aria-label pattern across text-branch and select-branch | VERIFIED | Both branches and PasswordField use `aria-label={\`More info about \${field.label}\`}` pattern; 4/4 tests pass |
**REQUIREMENTS.md Traceability Cross-Check:**
All 5 IDs (COMP-01, COMP-02, COMP-03, COMP-04, DEBT-01) are mapped to Phase 9 in REQUIREMENTS.md with status "Complete". All 5 are VERIFIED with full evidence. No orphaned requirements found.
---
### Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| `src/components/wizard/ReviewStep.tsx` | 16, 27 | `PLACEHOLDER` constant | Info | Legitimate empty-state UX string, not a stub — renders when config cannot be built |
No TODO/FIXME/HACK comments found in plan 09-05 modified files. No hardcoded hex color codes. No `return null` / `return {}` stubs.
---
### Human Verification Required
#### 1. Floating Label CSS Animation
**Test:** Navigate to BackendSelectionStep (step 1). Click into the Remote name field, then click away without typing. Then type a value, blur, then clear it.
**Expected:** On focus, the label smoothly translates upward and scales to 75%. When a value is present and the field is blurred, the label stays floated. When the value is cleared, the label returns to center. Verify the same behavior in RemoteConfigStep and PasswordField.
**Why human:** JSDOM does not compute CSS transitions or `:placeholder-shown` pseudo-class behavior. The Tailwind `peer-[:not(:placeholder-shown)]` arbitrary variant is untested by jsdom.
#### 2. MD3 Button Visual Appearance
**Test:** Navigate through all wizard steps and observe button appearances at each step.
**Expected:** Next/Download-All = pill shape with solid primary background color. Back/Copy/Download = pill shape with a visible outline border and no fill. Disabled state shows reduced opacity.
**Why human:** `MD3_BTN_*` class strings are applied correctly (verified), but the visual rendering of semantic tokens (`bg-primary`, `border-outline`, etc.) requires actual CSS custom property resolution in a browser.
#### 3. StepIndicator Visual States in Browser
**Test:** Complete step 1 (Backend selection) and observe the step indicator.
**Expected:** Step 1 circle shows a checkmark and is clickable. Step 2 circle is highlighted with a primary color border/background. Steps 3 and 4 appear muted. The connector line between steps 1 and 2 is filled (primary color); between 2-3 and 3-4 it is muted.
**Why human:** Semantic token resolution and visual differentiation of states requires browser rendering.
#### 4. Dark Mode Consistency
**Test:** Toggle to dark mode and navigate through all wizard steps.
**Expected:** All MD3 components render correctly with no hardcoded colors bleeding through. Floating label color changes on focus/error still work. Card shadows remain visible but subtle.
**Why human:** CSS custom property values under the dark theme class cannot be verified without rendering.
#### 5. Tooltip Icon Placement (Visual)
**Test:** Open a step that has fields with `tooltipText` (e.g., RemoteConfigStep with Azure Blob SAS URL field). Inspect the position of the ⓘ icon relative to the input and any helpText.
**Expected:** The ⓘ icon appears below the input, inline to the left of the helpText (or alone below the input if there is no helpText). It does NOT appear above the input floating-label area.
**Why human:** The `helpTextPrefix` slot renders inside a `<div className="flex items-start gap-1">` below the input — flexbox layout and visual position must be confirmed in a real browser.
#### 6. Tooltip Hover and Pin Behavior (Manual)
**Test:** Move the mouse over the ⓘ icon on a field with `tooltipText`. Then move the mouse away. Then click and move away. Then click again while still hovering.
**Expected:** Hover shows tooltip, mouse-leave hides it. Click pins it open so mouse-leave no longer hides it. Second click while hovering dismisses the tooltip completely (no sticky state).
**Why human:** `fireEvent` in JSDOM verifies state transitions correctly, but actual mouse pointer UX (timing, visual feedback of hover vs. pinned state, tooltip readability at that position) requires manual validation in a browser.
---
### Summary
Plan 09-05 (commits `23617c0` and `d2b6da2`) fully closed all 4 tooltip-related gaps identified in the UAT session:
1. `helpTextPrefix` prop added to TextFieldMD3 — enables inline slot left of helpText below the input.
2. Guard changed to `(helpText || helpTextPrefix) && !error` — tooltip icon renders even without helpText.
3. Tooltip icon moved from above-field position to `helpTextPrefix` slot below the input in both FieldRenderer and PasswordField.
4. Dual-state hover+click: `onMouseEnter`/`onMouseLeave` drive `hoverTooltip`; click toggles `showTooltip`; click-unpin explicitly clears `hoverTooltip` to prevent sticky-after-dismiss edge case.
5. Select-branch in FieldRenderer also received hover support (onMouseEnter/onMouseLeave).
All 16 must-have truths are VERIFIED. All 5 requirements (COMP-01, COMP-02, COMP-03, COMP-04, DEBT-01) are fully satisfied. The full test suite (186 tests across 15 files) passes with zero regressions.
Six items remain flagged for human verification — all relate to CSS animation, visual token resolution, visual tooltip placement, and interactive hover feel that cannot be confirmed programmatically.
---
_Verified: 2026-04-01T11:30:00Z_
_Verifier: Claude (gsd-verifier)_
_Re-verification after gap closure via Plan 09-05 (commits 23617c0, d2b6da2)_