Repository navigation
fix(interactive-hooks): use keyDownEvents and keyUpEvents on react-native-macos 0.78+ - #4372
Draft
Saad Najmi (Saadnajmi) wants to merge 1 commit into
Draft
Saad Najmi (Saadnajmi) wants to merge 1 commit into
Saad Najmi (Saadnajmi) wants to merge 1 commit into
Conversation
…tive-macos 0.78+ react-native-macos 0.78 removed native support for validKeysDown and validKeysUp. Share one worker between the key down and key up hooks, and use the win32 keyDownEvents/keyUpEvents path on react-native-macos 0.78 and later. Keep the legacy validKeys props only for react-native-macos 0.73 and 0.74. Mark the legacy macOS key props as deprecated in KeyPressProps and in the adapters ViewAdditionsMacOS type, and update the C-FOCUS-004 evidence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a127e053-064c-4e11-b063-fab2f57107ae
Contributor
Bundle size reportTree-shaken, minified production esbuild bundles with React and React Native runtimes externalized.
The job is advisory: size changes are reported but do not fail the pull request. Bundle or analysis errors still fail. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Platforms Impacted
This PR refactors the win32 code path. The win32 output does not change.
Description of changes
Why
FURN sends the deprecated react-native-macos props
validKeysDownandvalidKeysUpon all versions of react-native-macos. New versions of react-native-macos do not support these props natively:keyDownEventsandkeyUpEventsreact-native-macos#2171 addedkeyDownEventsandkeyUpEvents(August 2024, react-native-macos 0.76).validKeysDown,validKeysUp, andpassThroughAllKeyEventsreact-native-macos#1615 removed the native support forvalidKeysDown,validKeysUp, andpassthroughAllKeyEvents(January 2025, react-native-macos 0.78).Libraries/Utilities/normalizeLegacyHandledKeyEvents.js(fix(fabric): Add back compat layer forvalidKeysDownandvalidKeysUpreact-native-macos#2879, backport chore(0.81): backport fixes (#2878, #2879, #2880) react-native-macos#2884).View,TextInput, andPressableuse this layer to change the legacy props intokeyDownEventsandkeyUpEvents. A later release will remove this layer.The result:
validKeysDownandvalidKeysUp. The native view does not get a list of the keys that FURN handles, so it does not block the native handling of these keys.What changed
packages/utils/interactive-hooks/src/useKeyProps.ts:getKeyPropsWorker(direction, userCallback, keys), makes the props for key down and for key up.getKeyDownPropsWorkerandgetKeyUpPropsWorkercall this worker.keyDownEventsorkeyUpEvents. They do not sendvalidKeysDownorvalidKeysUp.useKeyProps,useKeyDownProps,useKeyUpProps,preferKeyDownForKeyEvents, anduseKeyCallbackdo not change. The emittedlib/useKeyProps.d.tsis the same as onmain.packages/utils/interactive-hooks/src/useKeyProps.types.ts:KeyPressProps.validKeysDownandKeyPressProps.validKeysUpare now@deprecated. The comments onkeyDownEventsandkeyUpEventsnow say "win32 and react-native-macos 0.78+". The type of these fields staysany[], so consumers see no type change.packages/utils/adapters/src/platformProps.ts:passthroughAllKeyEvents,validKeysDown, andvalidKeysUpinViewAdditionsMacOSare now@deprecated. The filter masks do not change.packages/utils/interactive-hooks/src/__tests__/useKeyProps.test.tsx: new unit tests for the props on each platform.references/agents/focus/platform-evidence.md:C-FOCUS-004now describes the new behavior and the native modifier matching (see below)..changeset/: patch changesets for@fluentui-react-native/interactive-hooksand@fluentui-react-native/adapters.Shared code path
useKeyDownPropsanduseKeyUpPropsundefinedonKeyDownoronKeyUponly. RNW filters oncode, not onkey(microsoft/react-native-windows#11049).onKeyDownandkeyDownEvents, oronKeyUpandkeyUpEvents. The events arekeys.map((key) => ({ key })).validKeysDownorvalidKeysUponKeyDownandvalidKeysDown, oronKeyUpandvalidKeysUpThe worker reads
Platform.constants.reactNativeVersion.minor.getRnVersion()in@fluentui-react-native/adapters(filters.base.ts) reads the same value, and the macOS filter masks use the same< 78limit. The index of the adapters package does not exportgetRnVersion, so this PR does not add a public export.The worker reads
Platform.OSwhen it runs. It does not usePlatform.select. The result on each platform is the same as before. This change lets the tests mock the platform, because thePlatform.selectin the win32 Jest preset always selects win32.Legacy path for react-native-macos 0.73 and 0.74
The FURN peer range includes react-native-macos
^0.73.0 || ^0.74.0. These versions do not supportkeyDownEventsorkeyUpEvents. On these versions, JS gets only the key events thatvalidKeysDownorvalidKeysUplists. Focusable views also get the native default for Space and Enter. Thus the legacy branch stays for these versions. A code comment tells maintainers to delete this branch when FURN drops support for react-native-macos versions before 0.78.Modifier matching
'Enter', matches Enter with all modifiers. The 0.81.6 compatibility layer does the same thing: it expands each string into all 16 combinations of Command, Control, Option, and Shift.{ key: 'Enter' }entry has no modifier fields. In react-native-macos 0.81.9, each matcher uses a different rule for a modifier that the entry does not specify:Libraries/Components/View/View.jsand the Paper native matcher inReact/Views/RCTHandledKey.mset the modifier tofalse. These matchers match Enter only when the user presses no modifier.KeyEvent.h,operator==(const KeyEvent&, const HandledKey&)) accepts all values for the modifier. This matcher matches Enter with all modifiers, the same as a legacy string entry.keyPressCallbackinuseKeyPropsignores events that have Option, Control, Command, or Shift. Thus the user callback runs for the same events as before.Remaining legacy references
This PR does not change these references. They stay because FURN supports react-native-macos 0.73 and 0.74:
packages/utils/interactive-hooks/src/useKeyProps.ts: the legacy branch for react-native-macos versions before 0.78.packages/utils/interactive-hooks/src/useKeyProps.types.ts: the deprecatedvalidKeysDownandvalidKeysUpfields.packages/utils/adapters/src/filters.macos.ts: the 0.74 view mask letspassthroughAllKeyEvents,validKeysDown, andvalidKeysUpthrough, and the 0.81 view mask extends the 0.74 mask. The 0.81 mask keeps these props on purpose. Consumers on react-native-macos 0.81.6 and later can still send the legacy props, and the react-native-macos compatibility layer translates them. If the mask removed them, FURN would silently remove these consumer props.packages/utils/adapters/src/platformProps.ts:ViewAdditionsMacOSkeeps the three props. They are now@deprecated.packages/utils/adapters/src/__drift__/macos.drift.ts:MacOSViewInjectedlists the three props, because the filter mask lets them through and the react-native-macos 0.81 types do not declare them.packages/components/Link/src/useLink.tsandpackages/components/Text/src/Text.tsx:filteredPropssetsvalidKeysDownandvalidKeysUptoundefined, together withkeyDownEventsandkeyUpEvents. These lines remove both forms, so they are correct on all versions of react-native-macos.Verification
Automated checks (local macOS, Yarn 4.18.0, Node.js 26.10.0 unless the row says Node.js 22):
yarnyarn formatyarn buildroot-prebuildandroot-build)yarn testinpackages/utils/interactive-hooksyarn lintinpackages/utils/interactive-hooksandpackages/utils/adaptersyarn lage test lint --scope @fluentui-react-native/interactive-hooks(the package, its dependencies, and all consumers)@fluentui-react-native/storybook-desktop-runtime testhad a 5 s Jest timeout inuseStorybookTheme.test.tsx. Another build made the machine load very high, and the suite took 224 s. With this change,yarn testin that package passed alone: 2 suites, 14 tests, 6 s. The failed test does not use key props.yarn lage test lint --to @fluentui-react-native/adaptersverify-drift)yarn check-agent-instructionsyarn change:checkyarn clean-lage-cache, thenyarn lage buildci(Node.js 26)@fluentui-react-native/desktop-driver test. Lage then stopped the other test tasks. The failure isUND_ERR_INVALID_ARGfrom undici on Node.js 26, and it occurs on every run. With Node.js 22 (the CI version),yarn testindesktop-driverpassed alone: 13 suites, 58 tests passed, 3 skipped.yarn lage buildci --continue --concurrency 6(Node.js 22, after the run above)desktop-driver testandstorybook-desktop test. All of these failures were timeouts during high machine load from other builds. Neither package depends oninteractive-hooksoradapters, and neither package has a diff fromupstream/main. The failedstorybook-desktoptests passed in a second run alone (4 of 4).desktop-driverpassed alone (13 of 13 suites).A mutation check changed the version limit from
< 78to< 100. As expected, 4 of the new tests then failed. The tests mockPlatform.OSwithjest.replaceProperty, the same as other FURN tests. They mockPlatform.constantswithjest.spyOn(Platform, 'constants', 'get').JavaScript tests do not prove the native behavior. This PR did not build or run fluent-tester on macOS.
Manual test plan for fluent-tester on macOS (react-native-macos 0.81, Paper and Fabric):
validKeysDownandvalidKeysUp. Versions 0.78 to 0.81.5 ignore these props. Version 0.81.6 and later translate them with a deprecated compatibility layer.keyDownEventsandkeyUpEvents, the same as on win32.Pull request checklist
This PR has considered (when applicable):
Questions for reviewers
getRnVersion(). A react-native-macos build frommainreports version 1000.0.0, and a 1.x release would also have a low minor version. These builds would get the legacy path. Do we want to add amajor === 0condition here and infilters.base.ts?{ key }entries, Paper does not block modified keys such as Shift+Enter, but Fabric blocks them. Is this difference acceptable? The other option is to add explicitfalsemodifier fields to each entry.