docs(09-05): complete tooltip fix plan - hover behavior and helpTextPrefix prop

- SUMMARY.md: tooltip placement fix and hover+pin behavior documented
- STATE.md: decisions added, session updated, progress at 100%
- ROADMAP.md: Phase 9 plan 5/5 complete
This commit is contained in:
2026-04-01 11:22:06 +02:00
parent d2b6da297f
commit d173fd4455
3 changed files with 128 additions and 8 deletions
+2 -2
View File
@@ -66,7 +66,7 @@ Plans:
3. Backend selection cards and output blocks display MD3 elevation with tonal surface tint and consistent shape tokens 3. Backend selection cards and output blocks display MD3 elevation with tonal surface tint and consistent shape tokens
4. Step indicator shows numbered circles connected by lines, with checkmarks on completed steps, highlight on current, and muted future steps 4. Step indicator shows numbered circles connected by lines, with checkmarks on completed steps, highlight on current, and muted future steps
5. FieldRenderer produces identical `aria-label` attributes for both text-branch and select-branch inputs 5. FieldRenderer produces identical `aria-label` attributes for both text-branch and select-branch inputs
**Plans:** 5 plans (4 complete + 1 gap closure) **Plans:** 5/5 plans complete
Plans: Plans:
- [x] 09-01-PLAN.md — TextFieldMD3 component, MD3 button constants, DEBT-01 aria-label fix - [x] 09-01-PLAN.md — TextFieldMD3 component, MD3 button constants, DEBT-01 aria-label fix
- [x] 09-02-PLAN.md — StepIndicator rebuild with MD3 circles and connectors - [x] 09-02-PLAN.md — StepIndicator rebuild with MD3 circles and connectors
@@ -108,6 +108,6 @@ Plans:
| 6. New Backends | v1.1 | 4/4 | Complete | 2026-03-31 | | 6. New Backends | v1.1 | 4/4 | Complete | 2026-03-31 |
| 7. Validation & UX Polish | v1.1 | 3/3 | Complete | 2026-03-31 | | 7. Validation & UX Polish | v1.1 | 3/3 | Complete | 2026-03-31 |
| 8. Theme Foundation | v1.2 | 2/2 | Complete | 2026-04-01 | | 8. Theme Foundation | v1.2 | 2/2 | Complete | 2026-04-01 |
| 9. MD3 Components | 4/4 | Complete | 2026-04-01 | - | | 9. MD3 Components | 5/5 | Complete | 2026-04-01 | - |
| 10. Content & Clarity | v1.2 | 0/? | Not started | - | | 10. Content & Clarity | v1.2 | 0/? | Not started | - |
| 11. Polish & Responsiveness | v1.2 | 0/? | Not started | - | | 11. Polish & Responsiveness | v1.2 | 0/? | Not started | - |
+8 -6
View File
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.2 milestone: v1.2
milestone_name: UI Polish & Clarity milestone_name: UI Polish & Clarity
status: completed status: completed
stopped_at: "Completed 09-04BackendSelectionStep TextFieldMD3 gap closure: all 12/12 wizard must-have truths satisfied" stopped_at: "Completed 09-05Tooltip placement fix + hover behavior: all UAT test 7 criteria satisfied"
last_updated: "2026-04-01T08:31:57.987Z" last_updated: "2026-04-01T09:21:49.765Z"
last_activity: 2026-04-01 — Phase 9 complete (COMP-01, COMP-02, COMP-03, COMP-04, DEBT-01 satisfied) last_activity: 2026-04-01 — Phase 9 complete (COMP-01, COMP-02, COMP-03, COMP-04, DEBT-01 satisfied)
progress: progress:
total_phases: 4 total_phases: 4
completed_phases: 2 completed_phases: 2
total_plans: 6 total_plans: 7
completed_plans: 6 completed_plans: 7
percent: 64 percent: 64
--- ---
@@ -55,6 +55,8 @@ Recent decisions affecting current work:
- [Phase 09-03]: PasswordField show/hide toggle passed as suffix prop to TextFieldMD3 — suffix slot is right-aligned inside input container - [Phase 09-03]: PasswordField show/hide toggle passed as suffix prop to TextFieldMD3 — suffix slot is right-aligned inside input container
- [Phase 09-03]: OutputBlock Copy/Download buttons use MD3_BTN_OUTLINED with !text-xs !px-3 !py-1.5 overrides to preserve small utility button size - [Phase 09-03]: OutputBlock Copy/Download buttons use MD3_BTN_OUTLINED with !text-xs !px-3 !py-1.5 overrides to preserve small utility button size
- [Phase 09-md3-components]: BackendSelectionStep gap: plain label+input replaced with TextFieldMD3; no test changes required because TextFieldMD3 preserves textbox role and role=alert contract - [Phase 09-md3-components]: BackendSelectionStep gap: plain label+input replaced with TextFieldMD3; no test changes required because TextFieldMD3 preserves textbox role and role=alert contract
- [Phase 09-05]: Tooltip hover uses dual-state (hoverTooltip + showTooltip); click-unpin explicitly clears hoverTooltip to prevent sticky tooltip after dismiss
- [Phase 09-05]: helpTextPrefix prop guard is (helpText || helpTextPrefix) so tooltip icon renders on fields without helpText
### Pending Todos ### Pending Todos
@@ -66,6 +68,6 @@ None yet.
## Session Continuity ## Session Continuity
Last session: 2026-04-01T08:28:33.352Z Last session: 2026-04-01T09:21:49.762Z
Stopped at: Completed 09-04BackendSelectionStep TextFieldMD3 gap closure: all 12/12 wizard must-have truths satisfied Stopped at: Completed 09-05Tooltip placement fix + hover behavior: all UAT test 7 criteria satisfied
Resume file: None Resume file: None
@@ -0,0 +1,118 @@
---
phase: 09-md3-components
plan: "05"
subsystem: ui
tags: [react, tailwind, tooltip, accessibility, testing-library]
# Dependency graph
requires:
- phase: 09-md3-components/09-04
provides: TextFieldMD3 component with suffix/helpText props
provides:
- Tooltip hover+click behavior in FieldRenderer (text and select branches) and PasswordField
- helpTextPrefix prop on TextFieldMD3 for inline left-of-helpText slot
- Tooltip icon rendered beside helpText below the field (not above the field)
- Tests covering hover show/hide, click-pin, click-unpin, and helpTextPrefix rendering
affects: [RemoteConfigStep, PasswordField, TextFieldMD3]
# Tech tracking
tech-stack:
added: []
patterns:
- "hoverTooltip + showTooltip dual-state: hover shows, click pins, click-unpin clears both"
- "helpTextPrefix slot pattern: ReactNode prop for inline content left of helpText in TextFieldMD3"
- "Click-to-unpin guard: setShowTooltip(v => { if (v) setHoverTooltip(false); return !v; })"
key-files:
created: []
modified:
- src/components/ui/TextFieldMD3.tsx
- src/components/ui/FieldRenderer.tsx
- src/components/ui/PasswordField.tsx
- src/components/ui/FieldRenderer.test.tsx
- src/components/ui/TextFieldMD3.test.tsx
key-decisions:
- "Tooltip hover uses dual-state (hoverTooltip + showTooltip); click-unpin explicitly clears hoverTooltip to prevent sticky tooltip after dismiss"
- "helpTextPrefix guard is (helpText || helpTextPrefix) not just helpText, enabling icon-only rendering when field has tooltipText but no helpText"
- "Tooltip content rendered BELOW TextFieldMD3 (after component), not inside it — TextFieldMD3 stays self-contained"
patterns-established:
- "helpTextPrefix slot: pass ReactNode as inline prefix left of helpText text in TextFieldMD3"
- "Hover+click tooltip: mouseEnter shows, mouseLeave hides, click pins, second-click clears both states"
requirements-completed: [COMP-04]
# Metrics
duration: 10min
completed: 2026-04-01
---
# Phase 9 Plan 05: Tooltip Placement and Hover Fix Summary
**Tooltip icon moved from above field to inline with helpText below it, with hover-to-preview and click-to-pin behavior via dual hoverTooltip+showTooltip state**
## Performance
- **Duration:** ~10 min
- **Started:** 2026-04-01T09:10:00Z
- **Completed:** 2026-04-01T09:20:34Z
- **Tasks:** 2
- **Files modified:** 5
## Accomplishments
- Added `helpTextPrefix` prop to TextFieldMD3 for rendering inline content (tooltip icon) left of helpText below the field
- Fixed tooltip icon position: moved from above the floating-label input to beside helpText below it
- Implemented hover-to-preview (mouseEnter shows, mouseLeave hides) and click-to-pin (stays open through mouseLeave) in FieldRenderer and PasswordField
- Fixed click-unpin edge case: second click explicitly clears hoverTooltip so tooltip dismisses even when mouse stays on button
- Added 7 new tests covering all tooltip hover/pin/unpin behaviors and helpTextPrefix rendering
## Task Commits
Each task was committed atomically:
1. **Task 1: Add helpTextPrefix prop and fix tooltip placement + hover** - `23617c0` (feat)
2. **Task 2: Add tests for tooltip hover behavior and helpTextPrefix rendering** - `d2b6da2` (test)
## Files Created/Modified
- `src/components/ui/TextFieldMD3.tsx` - Added `helpTextPrefix?: React.ReactNode` prop; changed helpText guard to `(helpText || helpTextPrefix) && !error`; renders `<div className="flex items-start gap-1">` wrapping prefix + helpText
- `src/components/ui/FieldRenderer.tsx` - Added `hoverTooltip` state; moved tooltip icon from above-field to `tooltipIcon` element passed as `helpTextPrefix`; tooltip content rendered below TextFieldMD3; select-branch also gains hover support
- `src/components/ui/PasswordField.tsx` - Same dual-state tooltip fix as FieldRenderer text-branch
- `src/components/ui/FieldRenderer.test.tsx` - Added `fireEvent` import; added 4 hover behavior tests (hover shows, leave hides, click pins, second-click unpins)
- `src/components/ui/TextFieldMD3.test.tsx` - Added Tests 9-11 for helpTextPrefix with helpText, without, and prefix-only
## Decisions Made
- Click-to-unpin must explicitly clear `hoverTooltip` because `userEvent.click()` simulates hover before click, leaving `hoverTooltip=true` after second click — required `setShowTooltip(v => { if (v) setHoverTooltip(false); return !v; })`
- Tooltip content stays outside TextFieldMD3 (rendered after the component in FieldRenderer/PasswordField) — keeps TextFieldMD3 self-contained, tooltip is a consumer concern
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Fixed click-unpin leaving tooltip visible due to hoverTooltip race**
- **Found during:** Task 1 verification (RemoteConfigStep.test.tsx "hides tooltip panel when clicked again")
- **Issue:** `userEvent.click()` simulates mouseEnter before click; second click set `showTooltip=false` but `hoverTooltip` stayed true, so tooltip remained visible
- **Fix:** Changed click handler to `setShowTooltip(v => { if (v) setHoverTooltip(false); return !v; })` — clears hover state when unpinning
- **Files modified:** src/components/ui/FieldRenderer.tsx, src/components/ui/PasswordField.tsx
- **Verification:** All 186 tests pass including RemoteConfigStep "hides tooltip panel when clicked again"
- **Committed in:** 23617c0 (Task 1 commit)
---
**Total deviations:** 1 auto-fixed (Rule 1 - bug)
**Impact on plan:** Required for correctness — without this fix, tooltip could not be dismissed by click when mouse was over the button.
## Issues Encountered
- Click-unpin sticky tooltip: `userEvent.click` triggers hover state before click event. Resolved by clearing `hoverTooltip` in the unpin branch of the click handler.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- UAT test 7 (Tooltip Info Buttons Accessibility) now satisfies all criteria: hover shows, mouseLeave hides, click pins, click again unpins, icon beside helpText below field
- Phase 9 (09-md3-components) fully complete — all must-have truths and requirements satisfied
- Ready for Phase 10
---
*Phase: 09-md3-components*
*Completed: 2026-04-01*