Skip to content

fix(mix): add FocusVisibility.ensureInitialized and harden focus-visible tracking - #1101

Merged
leoafarias merged 2 commits into
mainfrom
cursor/focus-visibility-followup-c860
Oct 20, 2026
Merged

leoafarias merged 2 commits into
mainfrom
cursor/focus-visibility-followup-c860

Conversation

@leoafarias

@leoafarias leoafarias commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Related issue

Follow-up to #1099. It addresses the Codex review findings there and should merge before the 2.3.0 release (#1102).

Description

Hardens FocusVisibility before it ships. FocusVisibility and FocusVisibilityScope are still unreleased, so making the scope a final class is not a breaking change yet.

  • Adds FocusVisibility.ensureInitialized(). Tracking otherwise starts on first use, so a mouse click on a non-Mix screen that opens one with an autofocused Mix control used to be missed, and the control showed a focus ring. The method also initializes the widgets binding and is safe to call more than once.
  • Lock keys and extra modifiers no longer count as keyboard input: Num Lock, Scroll Lock, Fn Lock, AltGr, Symbol, Super and Hyper. Super and Hyper chords are treated like Control and Meta. Key repeat does count, as in browsers.
  • A pointer or key event that can't change visibility, such as input under alwaysTraditional, no longer rebuilds FocusVisibilityScope dependents. Highlight-mode changes always notify.
  • FocusVisibilityScope is now a final class. The docs say once that onFocusVisible doesn't apply CSS's text-input exception and that onFocused covers it.

Changes

  • packages/mix/lib/src/core/focus_visibility.dart: ensureInitialized, the expanded key filter, the notification gating and final class.
  • packages/mix/test/src/core/focus_visibility_test.dart: tests for
    • the alwaysTraditional, touch, automatic sequence (a regression test for an earlier dedup version that left the ring visible)
    • alwaysTraditional and alwaysTouch behaviour
    • lock and modifier keys, and key repeat
    • no rebuild under alwaysTraditional
    • requestFocus in onPointerDown
  • packages/mix/test/src/core/focus_visibility_initialization_test.dart: the ensureInitialized test. It's in its own file because once any test reads FocusVisibility, tracking stays on for the rest of the isolate, and this test would pass without the call.
  • Docs in variant.dart and widget_state_variant_mixin.dart, plus CHANGELOG.md.

Review Checklist

  • Testing: The focus-visibility, focus-visible variant and pressable tests pass (88). Both new tests fail without their fix.
  • Breaking Changes: None, because the API is unreleased.
  • Documentation Updates: API docs and CHANGELOG.
  • Website Updates: Follow-up in btwld/mix-docs alongside fix(mix): show focus-visible only after keyboard input #1099.

…ble tracking

Co-authored-by: Leo Farias <leoafarias@users.noreply.github.com>
- Notify on every highlight-mode change again. Skipping it while the pointer
  flag was set left a stale focus ring after alwaysTraditional, a touch
  press, and a switch back to automatic.
- FocusVisibility.ensureInitialized now initializes the widgets binding and
  just creates the tracker; drop the HardwareKeyboard.clearState re-add,
  which only mattered in tests.
- Move the ensureInitialized test to its own file so it fails without the
  call, add a regression test for the mode notification, test the
  alwaysTraditional no-rebuild path, and drop the clearState test.
- Say the ensureInitialized and strategy-change caveats once, in
  FocusVisibility, and split the CHANGELOG entry in two.
@leoafarias
leoafarias marked this pull request as ready for review October 20, 2026 18:00
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 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-20T18:02:18.397966Z 7f21207 Draft marked ready
ℹ️ 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.

@leoafarias
leoafarias merged commit 03296f8 into main Oct 20, 2026
13 of 14 checks passed
@leoafarias
leoafarias deleted the cursor/focus-visibility-followup-c860 branch October 20, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants