-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Components: Add onFocusLoss option to withFocusReturn #14444
Conversation
@gziolo mentioned an alternative take which seemed interesting: If the idea with suggesting that focus be placed on More Options menu button when a modal is closed is on the basis that it's the next best place as far as being the most recent still-present element in the user's focus history, maybe we can represent this as some sort of stack where the implementation of focus return is to pop the stack until it finds something which still exists in the DOM to which to direct focus. The upsides to this are decreased reliance on DOM selectors (a maintenance concern), simpler implementation for developers using |
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.
This PR needs a rebase.
I reviewed the code and shared the idea about a different approach with @aduth as explained above. It would be more complex than the current proposal but might have better ergonomics for plugin developers as it would (hopefully) magically work behind the scenes. The issue is that it is still an assumption. This PR offers very solid fix which I'm happy with. It resolves the issue completely and can be included in the upcoming Gutenberg release, as well as, it would be part of WordPress 5.2 release. I think we should land this PR and keep looking into alternatives while users can benefit from the fact that bug is resolved.
} | ||
|
||
export default createHigherOrderComponent( withFocusReturn, 'withFocusReturn' ); | ||
export { Provider, Consumer }; |
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.
Consumer
is never used outside of this file.
There are 2 failing snapshot tests: https://travis-ci.com/WordPress/gutenberg/jobs/185021828#L5512 They have to be regenerated since modals are now wrapped with a different component. Aside: this is the part of snapshot testing which is quite annoying and introduces unnecessary noise. |
Ideally, focus should be moved back to the "invoking context", i.e.: the control that opened the modal. I'd like to point out again that this is more a design issue rather than a technical one. Opening a modal from a dropdown menu that closes as soon as the modal opens doesn't seem the best idea to start with. This should have been taken into consideration when this feature was designer. It's a perfect case to explain why accessibility specialists stress that accessibility should be designed and implemented since the beginning. I really appreciate the effort to solve this issue. I'd just like to invite everyone to consider that sometimes the best solution doesn't need to be a complicated, technical, one. Sometimes, keeping things simple and solving the issue in the design is way better. Just saying because sometimes I see a certain tendency to solve issues only with advanced technicalities. Instead, accessibility is more about simplicity. I do realize proposing relevant design changes would bring us into endless discussions. If there are no better ideas (e.g. can we keep the menu open?), the only option I can see is a compromise. It's not ideal for accessibility but it's better than what we have now. A fallback to the "more options" button would be a sort of extended concept of "invoking context". |
326de49
to
718e089
Compare
I've pushed a few revisions:
I'd encountered a failure in one of the unit tests for gutenberg/packages/components/src/higher-order/with-focus-return/test/index.js Lines 74 to 85 in 39bd834
(It appears to test that focus would be forcibly returned even after the element had been blurred?) I still want to add some additional test cases here, however. |
Another note: I didn't do away with the idea of an |
718e089
to
13c7ae3
Compare
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.
Tested and works nicely as expected. Design considerations apart, I think the idea of a focusHistory "stack" is very valuable at the point I'd like to see it introduced in core in the future.
I'd consider to better highlight this feature in the readme, if possible.
Thanks also for fixing the regression described at #1918 (comment)
From an accessibility perspective 👍 I'll leave code related considerations to coders more skilled than me 🙂
Candidate elements may still be in the DOM at the point of willUnmount, and must be excluded from consideration (as they are pending removal)
I pushed a few more revisions:
The test coverage is still lacking here, but depending on if this is needed for feature freeze (vs. qualifying for a subsequent bug fix release), I'd be inclined to suggest those be tackled separately. |
All applied changes. since I reviewed last time, seem to look good. I would appreciate some sanity check for the updated implementation of |
@@ -66,7 +72,7 @@ function Layout( { | |||
tabIndex: -1, | |||
}; | |||
return ( | |||
<div className={ className }> | |||
<FocusReturnProvider className={ className }> |
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.
What happens if I use two of these providers? Say each BlockEditorProvider
uses one?
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.
What happens if I use two of these providers? Say each
BlockEditorProvider
uses one?
Generally, I'd say it should probably be avoided, if possible. The component should fall under a "one-per-app" recommendation.
That said, in practice it shouldn't be too problematic. Any withFocusReturn
-enhanced component would rely on its closest provider as a source to determine where focus returns. The only potential problem is that the highest provider would still detect focus changes into an area technically governed by another provider, so they're not mutually exclusive. It's hard to imagine it would result in any unexpected behavior, though.
LGTM 👍 |
Fixes #1918
Addresses #10215 (comment)
This pull request seeks to enhance
withFocusReturn
to handle cases of focus loss by accepting anonFocusLoss
handler. This handler can be passed as an option when callingwithFocusReturn
, or applied as fallback on a virtual hierarchy using the newwp.components.FocusReturnProvider
context component. Furthermore, theModal
component accepts theonFocusLoss
prop to allow customized handling.To this end, the following behaviors take place:
edit-post-header
wrapperIn all cases, the specific behavior can be customized if there's a more suitable alternative presented.
Pending tasks:
This could do for some improved unit and/or end-to-end tests, pending feedback on direction.
Testing instructions:
Repeat Steps to Reproduce from #1918 and #10215 (comment), verifying that focus loss does not occur.