Skip to content

fix(desktop): close a takeover on Escape after focus falls to the body - #922

Merged
github-actions[bot] merged 1 commit into
mainfrom
claude/cool-elbakyan-fc7e59
Oct 1, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
claude/cool-elbakyan-fc7e59

Conversation

@JSdotNet

@JSdotNet JSdotNet commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Escape now closes a takeover surface even after focus has fallen to <body>. QA found that clicking Refresh on Pull requests (and Sessions) disables the focused button while the read runs, the browser drops focus to <body>, and the next Escape never reached the surface's @onkeydown — the takeover stayed open. Fixed once in the shell rather than per pane.

Changes

  • wwwroot/app.js: backlogTakeoverEscape, a document keydown listener that acts on Escape only when
    • focus is on <body>/<html> (a key pressed inside a surface or the header stays with its own handler),
    • a main[data-escape-closes] is on screen,
    • the event is not defaultPrevented and no [aria-modal="true"] / dialog[open] is open (dialogs and menus keep Escape).
      It then calls Home.CloseSurfaceOnEscapeAsync.
  • Shell/Home.razor: Tools, Dashboard, Sessions and Pull requests <main>s carry data-escape-closes; Home registers with the listener on first render and unregisters on dispose; the new [JSInvokable] re-checks a closing surface is still open before closing.
  • The Roadmap is deliberately excluded: its existing comment explains Escape already puts a grabbed bar back and dismisses its planning dialogs.

Testing

  • 6 new bUnit tests in HomeWorkspaceSurfaceTests: the callback closes each of the four surfaces (which carry the marker), leaves the Roadmap open (no marker), and the shell registers/unregisters the listener.
  • dotnet build Backlog.sln: 0 warnings, 0 errors. All 28 test executables: 0 failed.
  • Desktop web harness via Playwright, real click + real Escape: Pull requests and Sessions — after Refresh activeElement was <body> (button "Reading…"), Escape closed the surface; Tools closed with focus on body; Roadmap stayed open. No harness error logs.
  • Not exercised live: a modal open over a takeover (covered by the listener's guard).

Related

No issue — found by QA on the Pull requests surface.

Checklist

  • Scope is focused and excludes unrelated changes
  • Documentation or instruction files were updated when governance or behavior changed (none needed)
  • Running Aspire instances for this checkout were stopped before PR creation
  • Follow-up work is captured when the implementation is intentionally partial (not partial)
  • Issues this PR closes are linked with a closing keyword, or there are none

🤖 Generated with Claude Code

A focused Refresh button that goes disabled while its read runs drops focus
to <body>, outside each surface's @onkeydown, so Escape left the Sessions and
Pull requests takeovers open. A document listener in app.js now hears Escape
on <body> while a surface marked data-escape-closes is open, unless a modal is
open or the key was already handled, and calls back into Home. Fixed once in
the shell for Tools, Dashboard, Sessions and Pull requests; the Roadmap keeps
its deliberate no-Escape rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions
github-actions Bot merged commit 5c21cda into main Oct 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant