-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Event API: follow up fixes for FocusScope + context changes #15496
Conversation
ReactDOM: size: 0.0%, gzip: -0.0% Details of bundled changes.Comparing: 1eb2b89...503984a react-dom
react-events
Generated by 🚫 dangerJS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to use FocusScope around the Pressables in my sandbox (using the latest React builds) and it crashed when focus moved into the scope's subtree with the following error.
Uncaught Invariant Violation: addRootEventTypes() found a duplicate root event type of "focus". This might be because the event type exists in the event responder "rootEventTypes" array or because of a previous addRootEventTypes() using this root event type.
if (props.restoreFocus) { | ||
state.nodeToRestore = document.activeElement; | ||
state.nodeToRestore = context.getActiveDocument().activeElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll need to do something like check for blur
events that have a relatedTarget
within the event component subtree, that way we can know the last element focused (blurEvent.target
) before focus moved into the FocusScope instance. This should give the expected result in cases where the FocusScope is mounted well before the focus moves into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. We should do this later at some point.
if (props.restoreFocus && state.nodeToRestore !== null) { | ||
): void { | ||
if ( | ||
props.restoreFocus && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could both simplify the responsibilities of this component and make it more flexible for users if we instead had a callback API so we can leave it up to people to shift the focus themselves, in case they need custom behaviour.
const onFocusIn = (event) => {
// if there's a cancel button in the scope, move focus there instead of to the first focusable element
if (cancelRef.current != null) {
focusElement(cancelRef.current);
}
};
const onFocusOut = (event) => {
if (event.target != null) {
// restore focus if menu open-button if it is still open
focusElement(event.target);
} else {
// shift focus to menu open-button if menu auto-collapsed when modal opened
focusElement(fallbackElement);
}
};
<FocusScope onFocusIn={onFocusIn} onFocusOut={onFocusOut}>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a feature I was going to add anyway. I just added this to add a simple autofocus for modal cases.
This PR contains some follow up fixes as per comments in #15487 from @giuseppeg. This also adds a new helper method for getting the current active document
context.getActiveDocument
, which removes a bunch of code in places. I also addedcontext.isTargetWithinEventResponderScope
andcontext.requestResponderOwnership
to deal with ownership control of the same responder.Ref #15257