Skip to content

fix(core): focus traps and the keyboard model are one per page across swizzled copies (AST-110 FR3) - #10831

Merged
cixzhang merged 19 commits into
mainfrom
fix/focus-keyboard-shared
Nov 11, 2026
Merged

cixzhang merged 19 commits into
mainfrom
fix/focus-keyboard-shared

Conversation

@cixzhang

@cixzhang cixzhang commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

User impact

A product engineer who swizzles an overlay or a field and keeps the package's other components gets two copies of the page's focus regions and of the mobile keyboard model:

  • Focus: with a package Dialog around a swizzled Popover (or the reverse), both focus regions answer the same Tab, because neither copy sees the other's region. Focus can wrap in the outer region instead of the inner one.
  • Keyboard: package and copied fields keep separate keyboard stores, layout guides and ride registries per window, so a copied sheet and a package field can disagree on the keyboard's height or both move the same element.

After this change both copies use one set of focus regions and one keyboard model per page.

Problem and solution fit

  • Why do the copies disagree? useFocusTrap keeps its region containers and its Escape-trap count, focusReturn its temporary-focus and removal state, and the keyboard modules their per-window stores, guides, takeovers, ride registries and targets in module variables. A swizzled copy carries its own copies.
  • Why does that matter? spec:AST-110 FR3: coordinating state lives in one store per page, held through Core's shared-realm helpers.

Each moves onto the helpers from #10817, with no other change:

  • useFocusTrap: Escape-trap count → sharedState; active region containers → sharedState(() => new Set()).
  • focusReturn: temporaryFocus, focusDetachedAtRemovalStart → sharedWeakMap.
  • keyboardHeight: stores, focusTakeovers, touchStartWatches → sharedWeakMap.
  • keyboardLayoutGuide: guides → sharedWeakMap.
  • keyboardTarget: currentRides, riddenAnimators → sharedWeakMap; targets → sharedWeakSet.
  • useMobileKeyboard: the learned reveal-at-report windows → sharedState.

The baseline loses these 12 entries. layoutViewport's scrollbar-thickness cache moves from "open" to "allowed" as a memo cache (a second measurement per copy changes no result).

Expected behavior and authority

spec:AST-110 FR3 (approved, authority: draft).

Evidence

  • Red first (keyboard/focusKeyboard.shared.test.tsx): the package does not see a copy's active Escape trap; two loads get two layout guides for one window; the package does not recognize a keyboard target a copy registered; and, for the lead fix, with a copy's focus region opened inside a package region, Tab from the copy region's last control lands on the package region's first control (A) instead of wrapping to the copy's first (B1). That last case fails on the PR below and passes here.
  • After: all three pass. The keyboard, hooks, utils, Dialog, BottomSheet, Popover and Drawer suites pass (163 files, 3376 tests), and Core's tsc passes for both the source and build configurations.
  • scripts/shared-identity.test.mjs passes with the entries removed.

Scope

Components: Dialog, Popover, BottomSheet, Drawer, and every component with a focus region or a keyboard-aware field

  • One defect group (focus traps and keyboard); no API change.
  • Public text contains no internal Meta context.

Testing

  • pnpm exec vitest run --project ui packages/core/src/keyboard packages/core/src/hooks packages/core/src/utils packages/core/src/Dialog packages/core/src/BottomSheet packages/core/src/Popover packages/core/src/Drawer
  • pnpm exec vitest run --project node scripts/shared-identity.test.mjs
  • tsc --noEmit -p packages/core (and tsconfig.build.json)

@vercel

vercel Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Nov 10, 2026 8:25pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Nov 10, 2026, 11:41 PM UTC

@cixzhang

cixzhang commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec 1cd7019

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved: all four pull requests in the stack pass review, and required CI passed on this head. Each pull request lands only when it and every pull request below it are approved.

#10807: approve. No blocking findings.

#10817: approve. No blocking findings.

#10822: approve. No blocking findings.

#10831: approve. No blocking findings.

Whole stack: pass. The increments build on each other cleanly, and the net public API is unchanged.

Optional follow-ups:

  • Add a nested-region Tab case to focusKeyboard.shared.test.tsx. It is the lead claim of #10831, and a two-load probe confirms the fix.
  • In docs/specs/AST-110-swizzle-output/spec.md, the FR3 sentence "unless the allowlist names it with a reason" is stricter than the check, which also accepts open entries. The gap line could name the unchecked rows instead of "no check on main".
  • The #10807 and #10817 descriptions have stale baseline counts. The #10817 description calls SharedBrand's member optional, but the code makes it required.

[Automated review]

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

🔎 Preview · 14cf8df

Storybook · Sandbox · built from this PR's head

Modified components

Component Size LoC
ChatComposer 79.7 kB (+252 B) · 12.0 kB CSS (0) —
BottomSheet 69.2 kB (+243 B) · 7.7 kB CSS (0) —
ChatComposerInput 77.5 kB (+243 B) · 11.3 kB CSS (0) —
130 more components
Component Size LoC
ChatComposerTokenElement 77.5 kB (+243 B) · 11.3 kB CSS (0) —
TimeInput 164.0 kB (+234 B) · 16.0 kB CSS (0) —
charts/Chart 206.4 kB (+232 B) · 494 B CSS (0) —
charts/ChartTooltip 183.6 kB (+222 B) · 422 B CSS (0) —
Typeahead 82.0 kB (+222 B) · 12.4 kB CSS (0) —
DateInput 188.8 kB (+211 B) · 17.0 kB CSS (0) —
DateTimeInput 210.4 kB (+207 B) · 18.7 kB CSS (0) —
SideNavHeading 76.9 kB (+196 B) · 11.3 kB CSS (0) —
lab/TransferListSelector 111.2 kB (+191 B) · 1.4 kB CSS (0) —
PowerSearch 292.0 kB (+188 B) · 24.2 kB CSS (0) —
TabMenu 73.2 kB (+185 B) · 11.1 kB CSS (0) —
BaseTypeahead 73.1 kB (+184 B) · 10.9 kB CSS (0) —
lab/Comments 354.5 kB (+182 B) · 2.5 kB CSS (0) —
SideNavItem 71.7 kB (+180 B) · 11.1 kB CSS (0) —
BreadcrumbItem 86.0 kB (+178 B) · 12.1 kB CSS (0) —
ComplexSelector 72.3 kB (+178 B) · 11.8 kB CSS (0) —
DropdownMenuSubMenu 71.4 kB (+177 B) · 9.7 kB CSS (0) —
TopNavHeading 76.5 kB (+175 B) · 11.2 kB CSS (0) —
ChatLayout 84.1 kB (+172 B) · 10.5 kB CSS (0) —
TopNavMenu 75.9 kB (+171 B) · 11.2 kB CSS (0) —
Tokenizer 93.8 kB (+169 B) · 18.8 kB CSS (0) —
lab/CommentThread 347.5 kB (+166 B) · 2.4 kB CSS (0) —
Popover 92.3 kB (+158 B) · 14.2 kB CSS (0) —
TopNavMegaMenu 71.0 kB (+155 B) · 11.8 kB CSS (0) —
ButtonGroup 42.1 kB (+153 B) · 3.7 kB CSS (0) —
Markdown 190.1 kB (+151 B) · 20.7 kB CSS (0) —
Table 127.2 kB (+151 B) · 18.4 kB CSS (0) —
lab/CommentComposer 153.7 kB (+151 B) · 1.9 kB CSS (0) —
ContextMenu 110.3 kB (+148 B) · 17.4 kB CSS (0) —
SideNav 116.0 kB (+148 B) · 11.4 kB CSS (0) —
lab/ChatReactionBar 108.7 kB (+148 B) · 1.1 kB CSS (0) —
MoreMenu 98.7 kB (+147 B) · 17.6 kB CSS (0) —
TableCell 111.6 kB (+147 B) · 17.9 kB CSS (0) —
AppShell 92.9 kB (+145 B) · 13.5 kB CSS (0) —
lab/TourStep 98.6 kB (+145 B) · 590 B CSS (0) —
Lightbox 123.8 kB (+144 B) · 10.6 kB CSS (0) —
Pagination 111.7 kB (+144 B) · 17.8 kB CSS (0) —
TableHeaderCell 111.2 kB (+143 B) · 17.6 kB CSS (0) —
Drawer 51.9 kB (+140 B) · 8.3 kB CSS (0) —
MultiSelector 96.3 kB (+140 B) · 16.8 kB CSS (0) —
DropdownMenu 98.5 kB (+135 B) · 17.6 kB CSS (0) —
DateRangeInput 94.3 kB (+134 B) · 12.5 kB CSS (0) —
LayoutPanel 21.9 kB (+133 B) · 4.9 kB CSS (0) —
Selector 101.6 kB (+133 B) · 17.4 kB CSS (0) —
lab/ChatEmojiPicker 107.5 kB (+131 B) · 773 B CSS (0) —
BottomSheetSwitcher 18.6 kB (+128 B) · 3.4 kB CSS (0) —
AvatarGroup 47.1 kB (+127 B) · 5.7 kB CSS (0) —
AlertDialog 106.8 kB (+123 B) · 14.6 kB CSS (0) —
Dialog 24.9 kB (+123 B) · 6.9 kB CSS (0) —
TableSelectionToolbar 71.6 kB (+121 B) · 13.2 kB CSS (0) —
richtext/RichTextEditorToolbar 280.2 kB (+121 B) · 454 B CSS (0) —
CommandPalette 74.5 kB (+118 B) · 12.7 kB CSS (0) —
TabList 44.8 kB (+118 B) · 6.5 kB CSS (0) —
lab/Schedule 107.3 kB (+116 B) · 3.9 kB CSS (0) —
lab/CommentPin 58.3 kB (+114 B) · 1.2 kB CSS (0) —
Toolbar 44.7 kB (+113 B) · 8.1 kB CSS (0) —
MobileNav 71.8 kB (+110 B) · 10.6 kB CSS (0) —
NavHeadingMenu 16.9 kB (+109 B) · 3.5 kB CSS (0) —
SegmentedControl 97.3 kB (+109 B) · 6.9 kB CSS (0) —
DropdownMenuRadioItem 23.4 kB (+108 B) · 6.6 kB CSS (0) —
DropdownMenuCheckboxItem 23.3 kB (+107 B) · 6.6 kB CSS (0) —
TreeList 45.6 kB (+106 B) · 5.6 kB CSS (0) —
lab/NavigationScreen 83.3 kB (+102 B) · 1.5 kB CSS (0) —
lab/NavigationStack 83.3 kB (+102 B) · 1.5 kB CSS (0) —
DropdownMenuItem 22.5 kB (+100 B) · 6.3 kB CSS (0) —
lab/TabBar 81.3 kB (+100 B) · 1.8 kB CSS (0) —
TopNav 73.5 kB (+94 B) · 10.9 kB CSS (0) —
Collapsible 28.4 kB (+79 B) · 4.5 kB CSS (0) —
ContextMenuItem 32.8 kB (+79 B) · 6.3 kB CSS (0) —
InfoTip 47.6 kB (+76 B) · 5.4 kB CSS (0) —
lab/SelectableCardGroup 65.4 kB (+76 B) · 162 B CSS (0) —
Avatar 44.3 kB (+75 B) · 5.6 kB CSS (0) —
CheckboxList 69.7 kB (+74 B) · 7.7 kB CSS (0) —
ResizeHandle 22.1 kB (+73 B) · 4.3 kB CSS (0) —
lab/DialogHeroHeader 84.3 kB (+73 B) · 372 B CSS (0) —
CheckboxListItem 72.4 kB (+71 B) · 11.4 kB CSS (0) —
AvatarGroupOverflow 50.0 kB (+70 B) · 5.7 kB CSS (0) —
Link 54.1 kB (+70 B) · 7.0 kB CSS (0) —
FieldLabel 52.1 kB (+69 B) · 5.7 kB CSS (0) —
FileInput 70.3 kB (+69 B) · 10.9 kB CSS (0) —
Slider 110.2 kB (+69 B) · 8.8 kB CSS (0) —
lab/TransferList 103.4 kB (+69 B) · 1.2 kB CSS (0) —
RadioList 57.4 kB (+68 B) · 7.3 kB CSS (0) —
lab/EmojiPicker 88.1 kB (+68 B) · 751 B CSS (0) —
ListItem 71.4 kB (+67 B) · 11.4 kB CSS (0) —
RadioListItem 68.5 kB (+67 B) · 10.1 kB CSS (0) —
lab/DiffViewer 88.4 kB (+66 B) · 2.1 kB CSS (0) —
lab/ListInput 89.3 kB (+65 B) · 922 B CSS (0) —
Field 56.0 kB (+64 B) · 7.2 kB CSS (0) —
HoverCard 28.7 kB (+63 B) · 4.4 kB CSS (0) —
InputGroup 57.6 kB (+63 B) · 7.8 kB CSS (0) —
StatusDot 32.2 kB (+62 B) · 5.3 kB CSS (0) —
TextInput 68.9 kB (+62 B) · 11.2 kB CSS (0) —
Thumbnail 65.6 kB (+62 B) · 11.6 kB CSS (0) —
Calendar 72.3 kB (+61 B) · 10.6 kB CSS (0) —
CodeBlock 76.4 kB (+61 B) · 11.3 kB CSS (0) —
NumberInput 72.8 kB (+61 B) · 11.4 kB CSS (0) —
Tooltip 30.5 kB (+61 B) · 4.4 kB CSS (0) —
lab/TabBarMoreList 93.6 kB (+61 B) · 1.8 kB CSS (0) —
richtext/RichTextEditor 299.6 kB (+61 B) · 2.6 kB CSS (0) —
Stepper 62.9 kB (+60 B) · 10.1 kB CSS (0) —
TextArea 63.4 kB (+60 B) · 9.3 kB CSS (0) —
Toast 99.2 kB (+60 B) · 10.3 kB CSS (0) —
Banner 63.3 kB (+59 B) · 10.5 kB CSS (0) —
SideNavCollapseButton 62.1 kB (+59 B) · 10.0 kB CSS (0) —
Button 61.3 kB (+58 B) · 10.0 kB CSS (0) —
ChatDictationButton 61.9 kB (+58 B) · 10.1 kB CSS (0) —
richtext/RichTextView 277.7 kB (+58 B) · 2.3 kB CSS (0) —
charts/ChartLegend 53.4 kB (+57 B) · 224 B CSS (0) —
IconButton 61.3 kB (+57 B) · 10.0 kB CSS (0) —
ChatSendButton 61.7 kB (+56 B) · 10.0 kB CSS (0) —
DialogHeader 64.1 kB (+56 B) · 11.5 kB CSS (0) —
MobileNavToggle 61.6 kB (+55 B) · 10.0 kB CSS (0) —
Switch 104.8 kB (+55 B) · 9.9 kB CSS (0) —
ChatLayoutScrollButton 61.8 kB (+54 B) · 10.2 kB CSS (0) —
Text 13.5 kB (+54 B) · 5.4 kB CSS (0) —
CheckboxInput 65.4 kB (+53 B) · 9.2 kB CSS (0) —
DrawerHeader 64.3 kB (+52 B) · 12.9 kB CSS (0) —
Spinner 26.4 kB (+49 B) · 6.2 kB CSS (0) —
CommandPaletteInput 33.5 kB (+48 B) · 7.5 kB CSS (0) —
Timer 15.6 kB (+48 B) · 6.0 kB CSS (0) —
ToggleButton 87.8 kB (+48 B) · 10.1 kB CSS (0) —
Heading 14.1 kB (+45 B) · 5.4 kB CSS (0) —
Timestamp 34.7 kB (+45 B) · 10.2 kB CSS (0) —
Carousel 71.0 kB (+42 B) · 10.9 kB CSS (0) —
ChatToolCalls 33.7 kB (+41 B) · 8.3 kB CSS (0) —
lab/LineClamp 15.6 kB (+41 B) · 168 B CSS (0) —
ChatMessageList 29.9 kB (+38 B) · 7.0 kB CSS (0) —
ProgressBar 11.9 kB (0) · 6.3 kB CSS (0) —
lab/TabBarItem 3.9 kB (0) · 1.8 kB CSS (0) —

Package size: @astryxdesign/core 7.29 MB packed (+678 B); no new dependencies.

API changes: none in this pull request

Committed API report behind this build: cli 36 rows, core 36 rows; run pnpm api:report.

Not run on this PR: add ci:run-visual or ci:run-rtl to run them.


Generated by PR Enrichment workflow | View full report

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec e8eeb8f

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Changes requested: #10817 and #10822 each need one fix, and a pull request lands only when it and every pull request below it are approved.

#10948: approve, with no blocking findings.

#10817: request changes

  • Miss: the new FR3 sentence in docs/specs/AST-110-swizzle-output/spec.md (lines 102-106) requires Core's internal shared-realm helpers and the source check's allowlist, which architecture:knowledge-contracts INV18 does not allow in a product requirement, so keep the observable guarantee in FR3 (one versioned slot per page, React-bound state one per React) and move the helpers, the check and the allowlist to an architecture record or the FR7 verification row.

#10822: request changes

  • Miss: the title, .changeset/scroll-lock-swizzle-shared.md and the description say a swizzled overlay kept its own page scroll lock, but swizzle copies import useScrollLock from @astryxdesign/core/hooks and never carry useScrollLock.ts, rootScrollStyles.ts or pageHold.ts, and closing the overlay on top already kept the page locked, so describe the fixed case as two loads of Core's scroll-lock modules on one page where closing the overlay that opened first unlocked it, name selection locks as the part that reaches swizzled copies, and drop the stuck-hidden sentence.

#10831: approve, with no blocking findings; it lands after #10817 and #10822.

Whole stack: fail on the two findings above; the net public API is unchanged.

  • Optional: add a nested-region Tab case to focusKeyboard.shared.test.tsx, since it is the lead claim of #10831.

[Automated review]

sharedRealm.ts gains the shapes the FR3 fixes need, each a thin layer
over realmValue and sharedKey: sharedState for counters, flags and host
objects; sharedMap, sharedWeakMap and sharedWeakSet for registries and
per-document stores; sharedStore for a value and its listeners;
sharedBrand and the SharedBrand type for brands; sharedSequence for id
counters; and resetSharedStateForTest. The source check asserts that
every shared slot is named with a literal name and version, once. AST-110
FR3 states that cross-module state is held through these helpers.
@cixzhang
cixzhang force-pushed the fix/focus-keyboard-shared branch from e8eeb8f to fee30cf Compare November 10, 2026 04:37
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec fee30cf

@cixzhang
cixzhang marked this pull request as draft November 10, 2026 06:27
@cixzhang
cixzhang marked this pull request as ready for review November 10, 2026 06:27
@github-actions github-actions Bot removed the needs:design-review Affects visuals — Design should review label Nov 10, 2026
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 63307d2

@cixzhang cixzhang added ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) ci:run-a11y Run the accessibility suite on this PR; write access, next push (AST-030 FR12) labels Nov 10, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Changes requested: the focus-trap and keyboard changes are sound, but two changesets that came back in the merge from main need to go.

  • Regression: .changeset/scroll-lock-swizzle-shared.md and .changeset/shared-realm-helpers.md repeat the release notes 0.7.12 already published for #10822 and #10817 (packages/core/CHANGELOG.md lines 128 and 222), so the next changelog would announce those fixes again under this pull request; delete both and keep .changeset/focus-keyboard-swizzle-shared.md.

The new cases in focusKeyboard.shared.test.tsx, including the nested focus-region Tab case, fail on main and pass on this head. One optional wording suggestion for the changed comment in useFocusTrap.ts is inline.

[Automated review]

Comment thread .changeset/shared-realm-helpers.md Resolved
Comment thread packages/core/src/hooks/useFocusTrap.ts Resolved
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 7ea1f91

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. One CI job fails at this head, but not because of this change: pr-a11y (audit and guards) reports 26 Layer story plays with "No open layer", and the same plays fail in a Storybook built from the base commit, so the merge guard waits on a fix for those plays on main.

Focus regions, the Escape-trap signal, focus return and the keyboard model now keep one shared state per page, and the new two-load cases fail without the change and pass with it.

  • Optional: the changeset's "no longer both answer the same Tab" describes a symptom the base does not show; there the outer region answers alone and focus leaves the inner overlay (inline suggestion).

[Automated review]

@cixzhang
cixzhang marked this pull request as draft November 10, 2026 15:29
@cixzhang
cixzhang marked this pull request as ready for review November 10, 2026 15:29
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 1d1d1af

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. Every CI check on this head passes, including the heavy test, build and docsite-test lanes.

Focus regions, the Escape-trap count, focus return and the on-screen keyboard model now keep one state per page across a swizzled copy and the package, and the four new two-load cases fail without the change and pass with it.

  • Heads-up: #11027 landed on main after this head and edits the same block of scripts/shared-identity.baseline.json, so merging main will need that file resolved.
  • Optional: the changeset's "no longer both answer the same Tab" describes a symptom the base does not show; there the outer region answers alone and focus leaves the inner overlay (see the inline suggestion on line 5).

[Automated review]

'@astryxdesign/core': patch
---

[fix] A swizzled overlay and the package's components now share one set of focus regions and one mobile keyboard model: nested focus regions from the package and a copy no longer both answer the same Tab, and package and copied fields agree on the keyboard's height, its layout guide and which elements ride it. No API changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optional wording: "nested focus regions from the package and a copy no longer both answer the same Tab" names a symptom the base does not show. Each region's Tab handler returns once another has called preventDefault (useFocusTrap.ts:402), so on the base only the outer region answers and focus leaves the inner overlay (the new case lands on A). Suggest: "a Tab inside a copy's focus region nested in a package region (or the reverse) now wraps inside the inner region instead of moving to the outer region's first control".

@cixzhang
cixzhang marked this pull request as draft November 10, 2026 19:54
@cixzhang
cixzhang marked this pull request as ready for review November 10, 2026 19:54
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 14cf8df

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. CI passes on this head, including the test, build and docsite-test jobs that the earlier run cancelled for capacity.

Focus regions, the Escape-trap count, focus return and the on-screen keyboard model keep one state per page across a swizzled copy and the package: the four two-load cases fail without the change and pass with it, and in a real browser Tab from a copied focus region nested in a package region now wraps inside the copied region.

  • Optional: the changeset's "no longer both answer the same Tab" describes a symptom the base does not show; there the outer region answers alone and focus leaves the inner overlay (see the inline suggestion on line 5).

[Automated review]

@cixzhang
cixzhang marked this pull request as draft November 10, 2026 23:19
@cixzhang
cixzhang marked this pull request as ready for review November 10, 2026 23:19
@cixzhang
cixzhang merged commit 421678d into main Nov 11, 2026
126 of 132 checks passed
@github-actions
github-actions Bot deleted the fix/focus-keyboard-shared branch November 11, 2026 06:05

This branch was successfully deployed

1 active deployment
Preview — 14cf8dfd Deployed Nov 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) ci:run-a11y Run the accessibility suite on this PR; write access, next push (AST-030 FR12) CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant