fix: braille cursor issue and extra braille text at beginning in nvda eliminated#596
fix: braille cursor issue and extra braille text at beginning in nvda eliminated#596
Conversation
- Sync focus stack with hotkeys scope in dismissModalScope by accepting a targetScope parameter, preventing stale [TRACE] vs SUBPLOT mismatch - Add cancellation to notifyFocusChange to prevent stale deferred events from rapid repeated calls, and clean up timer in dispose() - Move role="application" from wrapper div to textarea element to avoid suppressing browse-mode navigation for potential sibling content - Expand comment on notifyStateUpdate() call explaining why enterSubplot does not notify observers itself Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Remove redundant removeLast call in dismissModalScope; simplify signature to only accept targetScope since the full stack is cleared - Move notifyStateUpdate() from MoveToTraceContextCommand into Context.enterSubplot() so the model layer owns observer notification Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Revert notifyStateUpdate() from Context.enterSubplot() as it caused unwanted audio on subplot entry. Update braille service directly from MoveToTraceContextCommand instead — only braille needs refreshing. Add unit tests for ExitBrailleAndSubplotCommand, MoveToTraceContextCommand, and DisplayService (dismissModalScope, notifyFocusChange debounce/dispose). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… updates Add a dedicated refreshDisplay() method on BrailleService to make the intent explicit when updating braille outside the observer chain. Add console.warn for the defensive state type guard after enterSubplot(). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… updates Add a dedicated refreshDisplay() method on BrailleService to make the intent explicit when updating braille outside the observer chain. Add console.warn for the defensive state type guard after enterSubplot(). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…ity/maidr into fix-multipanel_plot_escape
- Correct refreshDisplay JSDoc: other services are not triggered because the model's notifyStateUpdate() is not called, not because this method bypasses observers - Add architectural exception comment on MoveToTraceContextCommand documenting why it holds service references directly - Add test for state.type !== 'trace' branch (console.warn path) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…scape # Conflicts: # src/ui/component/Braille.tsx
Replace jest.fn(() => ...) as any with jest.fn<() => void>().mockImplementation(...) and use Record<string, unknown> for mock factory overrides to comply with the project's no-any policy. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replace console.warn with a defensive comment explaining the invariant. Update test to verify refreshDisplay is skipped without asserting on console output. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…semantics Place role="application" on the wrapper <div> instead of the <textarea> so the textarea is announced normally without an extra "application" label, while still ensuring screen readers pass all keys (including Escape) through to the web app. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…scape # Conflicts: # src/command/factory.ts
Code ReviewThanks for this targeted fix! The motivation is clear and the ARIA reasoning is solid. I do have one significant finding to flag. Bug:
|
The merge with main re-introduced role="application" on the <textarea>, leaving it on both the wrapper <div> and the textarea. Remove the duplicate from the textarea so it only exists on the wrapper div. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
Code Review for PR 596 - Braille role=application placement fix |
|
What is Good
Concern 1 — Missing accessible name on the application landmark Per WAI-ARIA 1.2 and the ARIA Authoring Practices Guide, role=application SHOULD have an accessible name so screen reader users navigating by landmarks can identify the region. Without one, NVDA/JAWS announces something generic like 'application' with no context. Suggested fix: add aria-label='Braille display' (or aria-labelledby pointing to a heading) to the wrapper div. Concern 2 — Rationale for the placement change is implicit PR #593 placed role=application on the textarea to 'avoid suppressing browse-mode navigation for any future sibling content.' That concern is silently dropped here. A brief note in the comment — e.g. browse-mode for sibling content is not a current concern; the textarea is the sole interactive child — would help future reviewers understand this was a deliberate trade-off. Minor / Questions
Summary The fix is directionally correct and addresses real screen reader regressions from #593. The main actionable item before merging is adding an accessible name (aria-label or aria-labelledby) to the div with role=application to satisfy ARIA naming requirements. The rest are suggestions for maintainability and test coverage. |
Add aria-label="Braille display" to the role="application" wrapper div to satisfy ARIA naming requirements. Expand comment to explain why role="application" lives on the div (not the textarea) and why browse-mode suppression for sibling content is not a concern. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Code ReviewNote: A prior automated comment on this PR incorrectly claimed `role="application"` would remain on the `<textarea>` after this change — that is not true. The diff clearly removes it (and its comment block) from the textarea. The fix is complete. What's correct
Remaining concern: `<textarea>` has no accessible nameThe `<textarea>` has no `aria-label`, `aria-labelledby`, or associated ``. Screen readers will announce it as "edit multiline" or similar with no context. This is a pre-existing issue not introduced by this PR, but it's worth a follow-up since we're already touching accessibility here. Suggested follow-up (separate PR or issue): <textarea
aria-label="Braille output"
...
/>Minor: no regression test for attribute placementGiven the back-and-forth between #593 and this PR, a simple `@testing-library/react` assertion would guard against this regressing again: expect(screen.getByRole('application')).toBeInTheDocument(); // on div
expect(screen.getByRole('textbox')).not.toHaveAttribute('role', 'application'); // textarea cleanNot a blocker, but worth a follow-up issue. Overall: The fix is correct, the ARIA reasoning is sound, and the previous feedback has been addressed. Good to merge once reviewers sign off. |
|
All major suggestions by claudebot have been implemented. I have tested the PR locally. @nk1408 Could you please test if visually braille mode is as before? @jooyoungseo @nk1408 I believe its ready to merge. |
|
yes @soundaryakp1999 , looks good to me visually. Merging |
|
🎉 This PR is included in version 3.62.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Description
Moves
role="application"from the<textarea>to the wrapper<div>in the Braille component to fix screen reader regressions.Related Issues
Follow-up to #593
Changes Made
The
role="application"attribute was previously placed directly on the braille<textarea>, which caused two regressions:role="application"on the textarea itself overrides its native form control behavior.Moving
role="application"to the parent<div>fixes both issues. The textarea retains its native editing behavior (cursor movement, standard announcements), while the parent's application mode still ensures keys like Escape are passed through to the web app rather than being intercepted by the screen reader.Before:
role="application"on<textarea>→ "edit braille app" announced, cursor movement brokenAfter:
role="application"on wrapper<div>→ textarea announced normally, cursor works, Escape still passes through in one pressChecklist
ManualTestingProcess.md, and all tests related to this pull request pass.