Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, gap_closure, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | gap_closure | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 09-md3-components | 05 | execute | 1 |
|
|
true | true |
|
|
Purpose: Close the last remaining UAT gap in Phase 9 (test 7: Tooltip Info Buttons Accessibility). Output: Tooltip icon renders inline with helpText below the field, and tooltip text appears on hover (pinnable via click).
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/09-md3-components/09-03-SUMMARY.md From src/components/ui/TextFieldMD3.tsx: ```typescript interface TextFieldMD3Props { id: string; label: string; error?: FieldError; registration: UseFormRegisterReturn; type?: 'text' | 'password'; helpText?: string; required?: boolean; suffix?: React.ReactNode; } ```From src/components/ui/FieldRenderer.tsx:
// text (default) — uses TextFieldMD3 for floating label
return (
<div className="flex flex-col gap-1">
{field.tooltipText && (
<button type="button" onClick={() => setShowTooltip(v => !v)}
aria-label={`More info about ${field.label}`}
className="text-primary hover:text-primary text-xs leading-none self-start">
ⓘ
</button>
)}
{field.tooltipText && showTooltip && (
<p className="text-xs text-primary bg-primary/10 border border-primary/30 rounded px-2 py-1.5">
{field.tooltipText}
</p>
)}
<TextFieldMD3 id={field.key} label={field.label} error={error}
registration={register(field.key)} helpText={field.helpText} required={field.required} />
</div>
);
{helpText && !error && (
<p className="text-xs text-on-surface-container/70">{helpText}</p>
)}
- Add
helpTextPrefix?: React.ReactNodetoTextFieldMD3Propsinterface. - Destructure
helpTextPrefixin the component function. - Change the helpText rendering block (lines 65-67) from:
To:
{helpText && !error && ( <p className="text-xs text-on-surface-container/70">{helpText}</p> )}This renders optional inline content (the tooltip icon) to the left of helpText. When{helpText && !error && ( <div className="flex items-start gap-1"> {helpTextPrefix} <p className="text-xs text-on-surface-container/70">{helpText}</p> </div> )}helpTextPrefixis undefined/null, the flex container still renders correctly with just the<p>.
FieldRenderer.tsx — Fix text-branch tooltip (lines 83-109):
- Remove the tooltip
<button>from ABOVETextFieldMD3(lines 85-93). Remove the tooltip content<p>from above as well (lines 95-98). - Add
onMouseEnter/onMouseLeavestate: addconst [hoverTooltip, setHoverTooltip] = useState(false)alongside existingshowTooltipstate. - Create a tooltip icon element that will be passed as
helpTextPrefix:const tooltipIcon = field.tooltipText ? ( <button type="button" onClick={() => setShowTooltip(v => !v)} onMouseEnter={() => setHoverTooltip(true)} onMouseLeave={() => setHoverTooltip(false)} aria-label={`More info about ${field.label}`} className="text-primary hover:text-primary/80 text-xs leading-none mt-px shrink-0" > ⓘ </button> ) : undefined; - Compute tooltip visibility:
const tooltipVisible = showTooltip || hoverTooltip. - Render the tooltip content BELOW TextFieldMD3 (after the component, inside the flex-col wrapper), conditioned on
tooltipVisible:{field.tooltipText && tooltipVisible && ( <p className="text-xs text-primary bg-primary/10 border border-primary/30 rounded px-2 py-1.5"> {field.tooltipText} </p> )} - Pass
helpTextPrefix={tooltipIcon}to TextFieldMD3. - The final text-branch return should look like:
return ( <div className="flex flex-col gap-1"> <TextFieldMD3 id={field.key} label={field.label} error={error} registration={register(field.key)} helpText={field.helpText} required={field.required} helpTextPrefix={tooltipIcon} /> {field.tooltipText && tooltipVisible && ( <p className="text-xs text-primary bg-primary/10 border border-primary/30 rounded px-2 py-1.5"> {field.tooltipText} </p> )} </div> );
FieldRenderer.tsx — Fix select-branch tooltip (lines 40-78):
The select branch also has a tooltip button. Apply the same hover fix to the select branch:
- Add
onMouseEnter={() => setHoverTooltip(true)}andonMouseLeave={() => setHoverTooltip(false)}to the existing select-branch tooltip button (line 51). - Change the tooltip content visibility condition from
showTooltiptotooltipVisible(line 59). - The select branch does NOT use TextFieldMD3, so no
helpTextPrefixneeded there — keep the icon in its current position above the select (it already has a visible label, not a floating label).
PasswordField.tsx — Same fix as FieldRenderer text-branch:
- Add
const [hoverTooltip, setHoverTooltip] = useState(false)alongside existingshowTooltip. - Remove the tooltip button from above TextFieldMD3 (lines 31-40). Remove the tooltip content
<p>from above (lines 41-44). - Create the same
tooltipIconelement withonClick,onMouseEnter,onMouseLeave,aria-label={More info about ${label}}. - Compute
const tooltipVisible = showTooltip || hoverTooltip. - Pass
helpTextPrefix={tooltipIcon}to TextFieldMD3. - Render tooltip content after TextFieldMD3, conditioned on
tooltipVisible.
IMPORTANT: Preserve existing aria-label format exactly as More info about ${field.label} (or ${label} in PasswordField) — existing tests assert this.
cd C:/Users/SebastienQUEROL/Documents/projets/Ready2Blob && npx vitest run --reporter=verbose 2>&1 | tail -30
- Tooltip icon renders inline to the left of helpText below the field (not above the field)
- Hovering the tooltip icon shows tooltip text
- Clicking the tooltip icon pins tooltip open; clicking again dismisses
- Mouse-leaving the icon hides tooltip (unless pinned via click)
- All existing tests pass including FieldRenderer aria-label tests
- PasswordField has identical fix
Add a new describe block 'FieldRenderer - tooltip hover behavior' with these tests:
-
'hovering tooltip button shows tooltip text':- Render FieldRenderer with
textFieldWithTooltip(already defined in test file) - Get tooltip button via
screen.getByRole('button', { name: /more info about bucket name/i }) fireEvent.mouseEnter(tooltipBtn)expect(screen.getByText('The name of your storage bucket')).toBeDefined()
- Render FieldRenderer with
-
'mouse-leaving tooltip button hides tooltip text':- Render, mouseEnter, verify visible, then
fireEvent.mouseLeave(tooltipBtn) expect(screen.queryByText('The name of your storage bucket')).toBeNull()
- Render, mouseEnter, verify visible, then
-
'clicking tooltip button pins it open through mouseLeave':- Render,
fireEvent.click(tooltipBtn),fireEvent.mouseLeave(tooltipBtn) expect(screen.getByText('The name of your storage bucket')).toBeDefined()(still visible because pinned)
- Render,
-
'clicking pinned tooltip button again dismisses it':- Render, click (pin), click again (unpin)
expect(screen.queryByText('The name of your storage bucket')).toBeNull()
Import fireEvent from @testing-library/react (add to existing import).
TextFieldMD3.test.tsx — Add helpTextPrefix tests:
Add tests in existing file (or create new describe block):
-
'renders helpTextPrefix inline with helpText':- Render TextFieldMD3 with
helpText="Some help"andhelpTextPrefix={<span data-testid="prefix">icon</span>} expect(screen.getByTestId('prefix')).toBeDefined()expect(screen.getByText('Some help')).toBeDefined()
- Render TextFieldMD3 with
-
'renders helpText without wrapper issues when helpTextPrefix is undefined':- Render TextFieldMD3 with
helpText="Some help"and no helpTextPrefix expect(screen.getByText('Some help')).toBeDefined()cd C:/Users/SebastienQUEROL/Documents/projets/Ready2Blob && npx vitest run src/components/ui/FieldRenderer.test.tsx src/components/ui/TextFieldMD3.test.tsx --reporter=verbose 2>&1 | tail -40- All new tooltip hover tests pass (mouseEnter shows, mouseLeave hides, click pins, click again unpins)
- helpTextPrefix rendering test passes
- All pre-existing FieldRenderer and TextFieldMD3 tests still pass
- Render TextFieldMD3 with
<success_criteria>
- UAT test 7 passes: tooltip info buttons show tooltip text on hover AND icon is positioned beside helpText below the field
- Zero test regressions
- Both FieldRenderer (text-branch + select-branch) and PasswordField have hover support
- TextFieldMD3 has helpTextPrefix prop for extensibility </success_criteria>