Skip to content

🤖 fix: keep the tutorial bubble from taking focus from a text field or under a full-screen panel - #7170

Merged
ThomasK33 merged 2 commits into
mainfrom
fixnext-tutorial-focus
Oct 22, 2026
Merged

ThomasK33 merged 2 commits into
mainfrom
fixnext-tutorial-focus

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Summary

The tutorial bubble no longer takes keyboard focus in two cases: when the user's focus is already in a text field (the composer), and when a full-screen layer such as the Artifacts or App View panel covers the bubble. In both cases Escape went to the bubble and skipped a tutorial the user never chose to act on. The bubble stays clickable.

Fixes #7114

Stack 1 of 4 (bottom). The other layers: #7171 (dialog Escape, #7141), #7173 (tab arrow keys, #7102), #7174 (selected tab fit, #7103).

Background

useBubbleFocus (TutorialTooltip.tsx) called bubble.focus() as soon as the bubble was positioned. It checked neither the element that had focus nor what was drawn over the bubble. The full-screen panels (z-1500) sit above the tutorial and are not modal, so nothing trapped focus away from the bubble. The related finding in the issue comments: the creation tutorial took focus from a composer the user had already focused.

Implementation

One guard before bubble.focus():

  1. isEditableElement(document.activeElement): leave focus in a text field.
  2. isBubbleCovered(bubble): a hit test at the bubble's center. If the top element there is not inside the bubble, something covers it. A hit test needs no list of overlay layers. An unknown result (no layout, center off screen) counts as uncovered, so the old behavior holds there.

The restore cleanup is registered in every case. A click on Skip or Next moves focus from the composer into the bubble, and focus must go back to the composer when the bubble closes (Codex review).

Contract change for #5701

The #5701 repro (tests/bugbash/repros/tutorialEscapeOverSettings.e2e.ts) said the bubble "owns focus while nothing covers it". The app opens on the creation form with the composer focused, so with this PR the bubble no longer takes focus there. The new contract: the bubble takes focus only while nothing covers it and no text field has it. Escape on the bubble still closes it. Reason: the #7114 comment shows the bubble taking focus from a composer the user had focused, and Escape then skipped the tutorial. The coordinator chose this over keeping the old contract.

The repro now clicks the bubble's title first, as a keyboard user would Tab to it. Its other steps, assertions and tags do not change.

Validation

  • Two new tests in TutorialTooltip.test.tsx (composer focus kept, covered bubble). Both fail on main and pass here. The covered case stubs document.elementFromPoint, because happy-dom computes no layout.
  • A third new test: after focus moves into the bubble (a click on Skip), closing the bubble returns focus to the composer. It fails without the always-registered cleanup.
  • The existing focus tests now start from a focused header button instead of the composer, since the composer case changed on purpose.
  • make test-bugbash-repros with --grep tutorial (mock AI): the updated 🤖 Escape does not close the tutorial tooltip #5701 repro passes on web and phone.

Follow-up

#7198 tracks two Codex findings deferred from review round 5: hand focus to the bubble when a covering panel closes, and make the bubble the next Tab destination from a focused composer.

Risks

Low. Only the first focus move of a bubble changes. Keyboard users who start from a button still get focus in the bubble (#5701 behavior).


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $47.52

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T16:16:17.962781Z 3e4714a Manual request
🔒 Security Review ✅ Completed 2026-10-22T16:16:41.130372Z 3e4714a Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33
ThomasK33 added this pull request to stack #7175 October 22, 2026 10:17
@ThomasK33 ThomasK33 changed the title fixnext tutorial focus 🤖 fix: keep the tutorial bubble from taking focus from a text field or under a full-screen panel Oct 22, 2026
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

Perf clearance (perf owner 8e18f4aada): CLEARED at head 29893ba68cd78f8d7e7f8360d0971ae2d064b23a (checked with ls-remote), base main ff74d8b8ad.

  • The numstat matches the request. It adds one elementFromPoint hit test per bubble open, which is not on a hot path.
  • React Compiler: TutorialTooltip.tsx compiles 2 components with 0 bailouts, before and after.
  • Re-clear on any push that changes product files.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 29893ba68c

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 29893ba68c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/components/TutorialTooltip/TutorialTooltip.tsx Outdated
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 8 passed

21 agent steps · 12 replayed from cache · 9 model calls · 35.2k tokens (22% cached)
Spend: $0.00 of the $1.00 cap (proxy ledger)

All 8 tests in 8 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 2 steps · 1 call 7.1s
🟢 a chat survives a restart of the server 2 steps · 1 call 7.1s
🟢 compaction.e2e.ts · 1 passed 3 steps · 1 call 11.0s
🟢 /compact replaces the old chat with a summary 3 steps · 1 call 11.0s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 10.8s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 10.8s
🟢 settingsRoundTrip.e2e.ts · 1 passed 3 steps · 1 call 12.3s
🟢 a chat survives trips through Settings 3 steps · 1 call 12.3s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.7s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.7s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.6s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.6s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 8.1s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 8.1s
🟢 todoNudge.e2e.ts · 1 passed 2 steps · 1 call 6.8s
🟢 the agent finishes open TODO items after the turn-end nudge 2 steps · 1 call 6.8s

e2e 0.20.0 · 1m 7s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.1k tokens (32% cached)
Spend: $0.00 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 8.0s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 8.0s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 6.7s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 6.7s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 6.3s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 6.3s

e2e 0.20.0 · 23.7s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 6.4s · 2 targets (web, phone) · run artifacts

@ThomasK33
ThomasK33 force-pushed the fixnext-tutorial-focus branch from 29893ba to fd86217 Compare October 22, 2026 10:43
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: fd86217e9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
ThomasK33 force-pushed the fixnext-tutorial-focus branch from fd86217 to 496f7ff Compare October 22, 2026 10:57
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 496f7ff80e

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

Perf re-clearance (perf owner 8e18f4aada): CLEARED at head 496f7ff80e0833054129041959b292cd72e9aa7e (checked with ls-remote), base main. A re-clear request for this stack named heads that GitHub does not have (HTTP 422), and it said only #7171 changed. I cleared the real pushed heads instead, from my own read.

  • Delta from 29893ba: the bubble focus-restore listener now registers even when the bubble did not take focus. That is one listener per bubble open, not a hot path.
  • React Compiler: TutorialTooltip.tsx compiles 2 components, 0 bailouts.
  • Re-clear on any push that changes product files.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

@ThomasK33
ThomasK33 force-pushed the fixnext-tutorial-focus branch from 496f7ff to 759f141 Compare October 22, 2026 11:13
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 759f1412e8

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33
ThomasK33 force-pushed the fixnext-tutorial-focus branch from 759f141 to 1308faa Compare October 22, 2026 12:49
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 1308faa32e

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1308faa32e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/components/TutorialTooltip/TutorialTooltip.tsx
Comment thread src/browser/components/TutorialTooltip/TutorialTooltip.tsx
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 1308faa32e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 1308faa32e

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

Perf re-clearance (perf owner 8e18f4aada): CLEARED at head 1308faa32e97c9f4a115b1a8f481ecc73a8c9eb9 (checked with ls-remote), base main ba9e451cab.

  • The numstat matches the request. The restore cleanup is registered once per bubble open, with no work per render.
  • React Compiler: TutorialTooltip.tsx compiles 2 components, 0 bailouts.
  • Re-clear on any push that changes product files.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

@ThomasK33
ThomasK33 marked this pull request as draft October 22, 2026 16:01
@ThomasK33
ThomasK33 marked this pull request as ready for review October 22, 2026 16:01
@ThomasK33 ThomasK33 closed this Oct 22, 2026
@ThomasK33 ThomasK33 reopened this Oct 22, 2026
@ThomasK33
ThomasK33 force-pushed the fixnext-tutorial-focus branch from 1308faa to 3e4714a Compare October 22, 2026 16:14
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Rebase only: onto main 1040fa0 to pick up the ESLint OOM fix (#7192). git range-diff shows both commits unchanged (5e5ba9e = 37e66bf, 1308faa = 3e4714a). New head 3e4714a.

@ThomasK33

Copy link
Copy Markdown
Member Author

Perf re-clearance (perf owner 8e18f4aada): CLEARED at head 3e4714a067ae5b2cc81518dfdad99217c57e621a (checked with ls-remote), base main 1040fa06a0.

  • This is a rebase only. git range-diff shows both commits unchanged (5e5ba9e = 37e66bf, 1308faa = 3e4714a), so my clearance of 1308faa carries over.
  • Re-clear on any push that changes product files.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 3e4714a067

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 3e4714a067

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 2f40901 Oct 22, 2026
35 of 36 checks passed
@ThomasK33
ThomasK33 deleted the fixnext-tutorial-focus branch October 22, 2026 17:02
asm pushed a commit to asm/mux that referenced this pull request Oct 22, 2026
…r#7171)

## Summary

An Escape pressed in the first moments after a dialog opens now closes
it. Before, Radix dropped that key: the dialog stayed open and kept
focus. The fix is in our shared `DialogContent`, so it covers every
modal built on it.

Fixes coder#7141

Stack 2 of 4, on coder#7170.

## Background

`@radix-ui/react-dismissable-layer` 1.1.11 computes its layer index
during render. It registers the layer in an effect and then asks for a
re-render. Until that re-render runs, its capture-phase Escape handler
sees `index = -1` and returns without doing anything. Focus is already
inside the dialog at that point (FocusScope moves it in a mount effect).

I checked upstream first. The latest `@radix-ui/react-dismissable-layer`
(1.2.1) has the same code path: the listener still reads the index from
the stale render, and the changelog does not mention this. An upgrade
does not fix it.

## Implementation

1. `Dialog` is now a thin wrapper around `DialogPrimitive.Root`. It
holds an uncontrolled root's open state itself (Radix keeps that state
private), passes `open` and `onOpenChange` to Radix, and puts its setter
into a context. So the fallback can close every dialog: controlled,
`defaultOpen`, or opened by `DialogTrigger` (Codex review).
2. `DialogContent` gets an `onKeyDown` fallback. An Escape that Radix
handled never arrives unprevented: our `onEscapeKeyDown` stops it, or
Radix prevents its default when it dismisses. So an unprevented Escape
whose target is inside this content node was dropped. The fallback runs
the same Escape logic (`allowEditableEscape`, the caller's
`onEscapeKeyDown`) and then calls `onOpenChange(false)`.
3. A key from a portaled child layer (a popover inside the dialog)
bubbles to `DialogContent` through React, but its DOM target is outside
the content node. The fallback ignores it, so that layer keeps the key.


## Validation

- New plays `Components/Dialog/EscapeRightAfterOpen` (controlled) and
`EscapeRightAfterOpenUncontrolled` (`DialogTrigger`, no `open` or
`onOpenChange`). It dispatches Escape from the `focusin` event that
marks focus entering the dialog. That is the exact window: the layer is
registered, and its index is not updated yet. A timer was not reliable
(in a page probe, an Escape after `setTimeout(0)` was dropped in 1 of 3
runs). Both fail on `main` ("the dialog is still open after Escape").
The controlled one passed 4 of 4 runs here. The uncontrolled one also
failed with only the first version of this fix, which closed through the
caller's `onOpenChange`.
- In a page probe on `main`, an Escape sent from `focusin` was dropped
in 6 of 6 runs.
- React Compiler audit of `Dialog.tsx` (babel-plugin-react-compiler with
`reactCompilerConfig`): ok=14 err=0. On `main` it is ok=13 err=0. The
extra component is the new `Dialog` wrapper.

## Risks

Medium-low: every dialog renders through this file. The fallback acts
only on an Escape that nothing else handled, from inside the content
node. The Radix path does not change. Uncontrolled dialogs now keep
their open state in the wrapper instead of in Radix, with the same
`defaultOpen` start value.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high` • Cost: `$47.52`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high
costs=47.52 -->
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.

🤖 Tutorial bubble takes focus under a full-screen Artifacts or App View panel

1 participant