Skip to content

Modernize native-core desktop primitives and track remaining qualification - #4381

Merged
Jason Morse (JasonVMo) merged 15 commits into
mainfrom
user/jasonvmo/native-lib2
Oct 16, 2026
Merged

Jason Morse (JasonVMo) merged 15 commits into
mainfrom
user/jasonvmo/native-lib2

Conversation

@JasonVMo

@JasonVMo Jason Morse (JasonVMo) commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Platforms Impacted

  • iOS
  • macOS
  • win32 (Office)
  • windows
  • android

Description of changes

Deliver the native-core modernization milestone already accumulated on this branch, and replace its cross-machine handoff with repository-owned follow-ups.

Related issues: #4373 (not fixed; remove the quarantine when its native press-out regression is fixed), #4344 (Windows native Callout exclusion removed; other catalog exclusions remain), #4345 (driver hardening), and #4347 (focus regression infrastructure). These broader issues and all newly filed qualification gates remain open; this PR does not claim their full acceptance or production/root admission.

Verification

30-minute CI follow-up: At 18:01 PDT on October 15, 2026 (01:01 UTC on October 16), all 18 reported checks passed at head 81859dabc, including every Windows/Win32, macOS/iOS, JS/Android, Storybook, publishing, link, bundle-size, and CodeQL check. PR workflow run 38829974672 and CodeQL run 38829974596 both completed successfully. No follow-up pipeline fix or push was needed.

Executed for this submission on Windows:

  • Passed: yarn workspace @fluentui-react-native/components format --check
  • Passed: yarn workspace @fluentui-react-native/components lint
  • Passed: yarn workspace @fluentui-react-native/components build
  • Passed: yarn workspace @fluentui-react-native/components test --testNamePattern Button — story type-check and 52 selected Jest tests; 424 unrelated tests skipped by the name filter, 6 snapshots passed.
  • Passed: yarn check-agent-instructions
  • Passed: yarn change:check
  • Passed: yarn workspace @fluentui-react-native/agentic-components-storybook storybook bundle --win32
  • Passed: yarn workspace @fluentui-react-native/agentic-components-storybook storybook test --win32 --story components-button--focus-management --list — all 7 cases remain discoverable.
  • Passed with explicit skips: $env:STORYBOOK_SMOKE_STORY = 'components-button--focus-management'; yarn workspace @fluentui-react-native/agentic-components-storybook storybook smoke --win32 --mode stories-and-tests — 1 native-state case passed; 5 input-dependent cases capability-skipped; exactly the intervening-key case skipped with its Components: Win32 Button does not report onPressOut after Space with an intervening key #4373 quarantine reason. All owned channel/Metro/driver listeners closed afterward. This run verifies quarantine/reporting, not input qualification.
  • Passed: yarn clean-lage-cache
  • Failed, existing Windows baseline: yarn lage buildci --continue — 170 tasks passed, 1 failed (root lint-repo, 11 previously recorded Knip unused-dependency findings in untouched packages). Formatting, constraints, dependency alignment, lockfile lint, all package tests/builds/lints, and instruction checks passed.

Earlier native qualification is recorded by the branch's existing commits and retained in the follow-up issues: Windows full authored catalog 44/44 and native subset 19/19; Win32 legacy native subset 7/7 with only #4373 failing in the full authored catalog; macOS Fabric/Paper full smoke 178 stories, 38 passed / 5 skipped each. These are prior executed results, not new macOS runs in this Windows session. iOS/Android native qualification was not run locally.

Before After
Native-core handoff mixes delivered work and untracked gates; a Win32 press-out regression fails its authored case; branch fixes await submission. Remaining work has workstream sub-issues and durable contract links; only the known Win32 case reports an issue-linked skip; native-core and driver fixes are submitted together.

Pull request checklist

This PR has considered (when applicable):

  • Automated Tests
  • Documentation and examples
  • Keyboard Accessibility
  • Voiceover
  • Internationalization and Right-to-left Layouts

Jason Morse (JasonVMo) and others added 15 commits October 15, 2026 09:03
…ndoff

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prevent entry preferences from redirecting explicit Windows FocusZone commands. Add live-target refusal and detach/cancellation stories, deduplicate compatible Storybook runtime dependencies, and record the remaining modernization gates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make the modern Callout and FocusZone real phased components: hooks, live
targets, command channels, imperative handles, and slots run in the first
phase, and a hook-free directComponent render phase merges render-time
pass-through props. Remove the inner hook-owning components, delete the
FocusZoneHost wrapper, restore legacy FocusZone to main, and make the shared
CalloutHost a hook-free native binding without the stacked-slot style
workaround.

Move the new macOS Paper Callout commands to Swift with RCT_EXTERN_METHOD and
keep the extern registration free of generated Swift types through a narrow
property protocol. Derive the placement edge from the hint in shared Swift,
make main-actor isolation explicit, and give notification observers a single
owner. On Windows, use a dedicated explicit-command focus flag and an
auto-revoked light-dismiss subscription that legacy remounts retain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fabric passes all 11 native Callout/FocusZone cases; Paper cases are blocked by the Desktop Driver's missing enabled state for Paper views.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Treat macOS elements without AXEnabled (React Native Paper views that are
  not disabled) as enabled.
- Diagnose locked or switched-out login sessions before launch, attach,
  window discovery, and new physical input.
- Record window notifications, element descriptors, and a command journal on
  one clock; expose them through furn/window-events, publish window-closed
  events, and settle window listing while notifications arrive.
- Activate through AXFrontmost instead of cooperative workspace activation,
  journal activation details, and name the occluder of intercepted clicks.
- Share failure evidence capture that reads window events first and captures
  secondary windows, and use it for Storybook wdio callbacks.
- Give attached WebdriverIO sessions explicit wait defaults so waitUntil polls
  until its timeout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…detach

React Native macOS routes host focus() through TextInputState, which records
any focused View as the focused text input until a TextInput clears it. A View
focused through requestFocus() stayed recorded after unmounting, so a later
ScrollView touch dispatched blur to its removed tag and Paper raised a RedBox.
Focus targets now clear the record without dispatching on blur and genuine
detach.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Separate the modern Callout dismissal status so Paper's per-event delivery
cannot reorder it, and record full Paper and Fabric story runs and the
cross-story focus finding in the modernization plan.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix the RNW host crash on every Windows Callout mount: InputLightDismissAction
does not support weak references, so the auto_revoke subscription faulted at
popup creation. Use explicit tokens, give each mount its own popup, window, and
subscriptions, and report a shown presentation's dismissal once.

Mirror macOS dismissal and focus behavior on Windows: dismiss on outside
pointer input through the owner island's pointer source and a UI-thread
message hook, dismiss focused content on Escape, honor legacy
dismissBehaviors, and return keyboard input to the owner after a focused
presentation closes. Treat owned popups as active while their owner is the
foreground window so a FocusZone inside Callout content can enter and
navigate, and keep the requested gap when placement flips.

Retry a Windows Desktop Driver subtree read when a closing popup island
disappears while the window root remains live.

Include every native-core story on Windows and add authored cases for
light-dismiss/rearm, Escape on both facades, a flat Menu composition, and
Windows anchor geometry. Windows passes 18/18 native cases across 170
stories; Win32 passes 7/7 across 152 stories, including legacy Callout
popup operations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…iliation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace useFocusablePressable's focusOnPress boolean with a pointerFocus mode.
The default follows the platform: Windows and Win32 focus a pressed target,
and macOS follows AppKit by leaving keyboard focus in place. always and never
select one behavior on every platform. Tab maps its tablist exception to never.

The FocusZone stories made macOS items click-focusable by calling host focus()
directly, which left unmounted Views in React Native's focused-input record and
raised a Paper RedBox on a later ScrollView tap. They now use pointerFocus
always and a focus target.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…u work

Fabric hosts the Paper RCTFocusZone without a React tag, and RCTView throws
building focus and key events without one. Opening a Callout whose content
starts with a FocusZone aborted the app when AppKit selected the zone as the
popup's first key view, and every key bubbling through the zone was dropped,
so Escape never dismissed the popup. A tagless zone now sends resign and key
messages past RCTView, and the Fabric wrapper continues bubbled keys up the
responder chain instead of returning them to the zone.

Menu composition's trigger uses the pointer-focus mode: the default case
asserts each platform's convention and a new story asserts trigger restoration
with always. Record the macOS Fabric and Paper rerun in the plan.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Windows and Win32 focus stories failed because an Input never took focus after
a physical click. Input focus works: an absolute pointing device on the console,
such as a remote or virtual-machine viewer, moved the cursor back shortly after
each injected move, and the helper pressed without coordinates 50 ms later, so
the press landed under the restored cursor and activated another window.

Confirm that pointer placement reaches its target and retry it before any
press, inject each element click as one coordinate-carrying SendInput batch,
and carry coordinates on explicit pointer presses and releases. Add Input
coverage for native focus from a physical click.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Fabric FocusZone fixes

Both Menu composition cases pass on Windows with the platform-default and always pointer-focus modes; Win32's only authored failure is tracked as #4373.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… regression

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Bundle size report

Tree-shaken, minified production esbuild bundles with React and React Native runtimes externalized.

Scenario Modules-Mac (Δ) Modules-Win (Δ) Size-Mac (Δ) Size-Win (Δ)
components-button 64 (+2) 65 (+2) 50.22k (+273b) 50.14k (+273b)
components-catalog 161 (+2) 162 (+2) 155.56k (+291b) 155.48k (+291b)
design-theme-state 34 (+1) 35 (+1) 30.15k (+42b) 30.08k (+42b)
design-themed-root 38 (+1) 39 (+1) 32.12k (+42b) 32.04k (+42b)
design-color-lib 6 (+0) 6 (+0) 6.33k (+0b) 6.33k (+0b)
design-theme-state-legacy-source 35 (+1) 36 (+1) 31.81k (+42b) 31.73k (+42b)
design-legacy-theme-from-flex 58 (+1) 59 (+1) 97.77k (+42b) 97.63k (+42b)

The job is advisory: size changes are reported but do not fail the pull request. Bundle or analysis errors still fail.


View bundle-size workflow run

@JasonVMo

Copy link
Copy Markdown
Contributor Author

30-minute pipeline follow-up completed at 2026-10-15 18:01 PDT (2026-10-16 01:01 UTC), at head 81859da. All 18 reported checks passed, including JS, Android, Windows, Win32, Windows Storybook, Win32 Storybook, bundle size, publishing dry run, repository links, CodeQL, and all macOS/iOS lanes. The PR and CodeQL workflow runs both completed successfully. No pipeline failure needed a follow-up fix or push. The local Windows-only Knip baseline remains documented in the PR; the actual JS PR CI job passed.

@JasonVMo
Jason Morse (JasonVMo) enabled auto-merge (squash) October 16, 2026 03:48
@JasonVMo
Jason Morse (JasonVMo) merged commit e2092f9 into main Oct 16, 2026
18 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.

4 participants