forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor how focusable
is handled in RCTView
#1437
Merged
Merged
Conversation
This file contains 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
amgleitman
approved these changes
Sep 21, 2022
Tabling this for a bit while I explore an alternate fix. |
mischreiber
approved these changes
Sep 27, 2022
Saadnajmi
changed the title
Update
Refactor how Oct 24, 2022
focusable
to not depend on [NSApp isFullKeyboardAccessEnabled]
focusable
is handled in RCTView on macPS
Saadnajmi
changed the title
Refactor how
Refactor how Oct 24, 2022
focusable
is handled in RCTView on macPSfocusable
is handled in RCTView on macOS
Saadnajmi
changed the title
Refactor how
Refactor how Oct 25, 2022
focusable
is handled in RCTView on macOSfocusable
is handled in RCTView
chiuam
approved these changes
Oct 26, 2022
mischreiber
reviewed
Oct 26, 2022
mischreiber
approved these changes
Oct 26, 2022
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.
Please select one of the following
Summary
This PR does slight refactoring on how the
focusable
prop is handled by React Native macOS.[RCTView acceptsFirstResponder]
now doesn't depend on[NSApp isFullKeyboardAccessEnabled]
, and only depends on the propfocusable
.We initially only accepted first responder status if both focusable and
[NSApp isFullKeyboardAccessEnabled]
were true to properly respect a specific system preference, and only make<View focusable>
into a key view (AKA: tab stop) if the user allowed it. However, that's actually the wrong method to override, NSView's canBecomeKeyView is.Looking at some old Apple docs:
It seems that the default implementation of
[NSView canBecomeKeyView]
will check that OS preference for us, so we can do less work :).Discussion
This work is done to unblock a bug in FluentUI React Native, where we want our custom NSMenu Replacement always take keyboard focus, regardless of the OS preference (menus are a special case that shouldn't respect that OS preference).
Natively in Appkit, there are two relevant NSView methods that control keyboard focus:
acceptsFirstResponder
and `canBecomeKeyView.[NSView acceptsFirstResponder]
: controls whether a view can receive focus at all (programmatically, via the key view loop, etc).[NSView canBecomeKeyView]
: controls whether a view can receive focus from the key view loop (AKA: Can you press tab to get focus on the view, AKA: Is it a tab stop).[NSApp isFullKeyboardAccessEnabled]
: System preference that determines how many controls get keyboard focus. By default it's turned off, so most native Appkit views do not get keyboard focus. See https://microsoft.github.io/apple-ux-guide/KeyboardFocus.html .In React Native, the View prop
focusable
is a cross platform prop that determines whether a View receives keyboard focus. We implemented it natively by havingacceptsFirstResponder
(AKA, can a View receive focus at all) only return true if bothfocusable
is true and[NSApp isFullKeyboardAccessEnabled]
is true. This behavior approximately matches the equivalent SwiftUI Modifier.However, this leaves JS developers at an impasse. There is no way in JS for a developer to "force" a view to always be focusable. I needed this for my custom NSMenu replacement. To further complicate matters, Apple has confusingly introduced a new, similarly named system accessibility preference Full Keyboard Access that allows the user to force every view to be keyboard focusable. This new preference is on both iOS and macOS and seems to use an entirely different keyboard focus ring / OS layer / whatever you want to call it. So it feels like Apple might have forgotten about the original preference
[NSApp isFullKeyboardAccessEnabled]
? Or at least, would rather you forgot about it and use their new system preference?Last weird bit... I also needed to override
[NSView needsPanelToBecomeKey]
so that clicking on a<View focusable> / <Touchable> / <Pressable>
wouldn't place keyboard focus on it. That was quite jarring, and doesn't match what anNSControl
likeNSButton
does natively. For more info, see https://stackoverflow.com/questions/55078226/first-responder-on-mouse-down-behavior-nscontrol-and-nsviewWhile this change doesn't make it easier for JS developers to force a view to always be focusable, it does unblock a native module like FocusZone to force focus. It's not perfect, but I think it's a better state than we were before :).
Changelog
[macOS] [Fixed] - Refactor how
focusable
is handled natively on macOSTest Plan
Tested the View test page in RNTester. Notice that when the preference is OFF, only the TextField can receive focus (as it should be).
Screen.Recording.2022-10-25.at.3.30.06.PM.mov