-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(#2444): useRestoreFocus when nodeToRestore has been unmounted #2445
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
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
950b16d to
a328b77
Compare
This comment was marked as outdated.
This comment was marked as outdated.
…esent Per code comment: #2445 (comment)
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
Build successful! 🎉 |
| triggerPress(item3); | ||
| expect(onSelectionChange).toHaveBeenCalledTimes(1); | ||
| act(() => jest.runAllTimers()); | ||
| act(() => jest.runAllTimers()); |
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.
note: this test used to be technically wrong, after the first runAllTimers here, focus was on the body, we never ran the queued restore focus which is queued up as a result of the render contained in the act.
Because we now have a stack of nodes to restore focus to, we need to make sure to run our cleanup in the raf to clear that stack out, otherwise we have extra elements in the stack that will cause problems further down in the test
it's the same for all other tests here where it's runalltimersx2
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.
So to clarify, where I now have act(() => {jest.runAllTimers();}); twice is appropriate for this case? I saw instances where runAllTimers was called twice, in ActionBar.test and Picker.test, and figured I'd give it a try to fix some failing tests here. Sure enough, it worked.
| <DialogTrigger type="popover" isOpen={isPopoverOpen} onOpenChange={setPopoverOpen}> | ||
| <ActionButton>Open popover</ActionButton> | ||
| <Dialog> | ||
| <Dialog isDismissable={false}> |
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.
these should already be false? what are these changes for?
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.
The responsive Popover hides the footer containing the "Open modal" button when rendered as a Dialog which defaults to isDismissible={true}, making it difficult to test if your screen width is too narrow. I should probably open a separate issue for this.
| } | ||
| return; | ||
| } | ||
| // Otherwise try to focus the nodeToRestore, and clean up |
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 don't quite understand this case, can you explain when we'd hit this?
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.
We have to account for FocusScopes where contain={false}, as @LFDanLu pointed out in this comment: #2445 (review)
I'll need to dig into it a some more but the following story breaks in the following case:
- Open the dialog with you keyboard
- Open several layers of nested dialogs via the "open dialog" buttons in each new dialog
- Shift + Tab back to the first "dialog" you opened and hit the "close" button with the enter key
- Note that focus is lost instead of being restored to the first "open dialog" button
The above doesn't reproduce in an earlier version of this PR: https://reactspectrum.blob.core.windows.net/reactspectrum/c465126e8286623894aca7b692cb096121643211/storybook/index.html?path=/story/focusscope--keyboard-navigation-no-contain
EDIT:
Seems to be due to something in a2fad80
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.
We iterate backward through the nodeToRestoreArray using pop() only when the nodeToRestore for the closing scope is the last item in the array.
This comment was marked as outdated.
This comment was marked as outdated.
|
I looked into this with @devongovett , we came to the conclusion a stack, while close, isn't quite right. We want to try refactoring our Map |
|
Build successful! 🎉 |
@devongovett and @snowystinger While I agree that refactoring the restoreFocus behavior in FocusScopes around the composite pattern is desirable, please consider that this PR has been open since October 2021, ~7 months. Provided it fixes the problem and does not introduce breaking changes, I think it would be better to accept the PR and address the more significant refactoring as a separate issue. |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Fixed by #3323 |
Restore focus to previous nodeToRestore when expected nodeToRestore is no longer present, as with a Menu that opens a Dialog.
Closes #2444
✅ Pull Request Checklist:
📝 Test Instructions:
Open https://reactspectrum.blob.core.windows.net/reactspectrum/4b09194340f607fab1c56739c71f99e8a7d58337/storybook/index.html?path=/story/dialogcontainer--in-a-menu
Click or navigate to the "Open menu" button and press Enter or Space to expand the menu.
Click or arrow down to and activate the "Open dialog..." menu item.
Press Esc key to close the Dialog.
Focus should be restored to the "Open menu" button.
Open https://reactspectrum.blob.core.windows.net/reactspectrum/4b09194340f607fab1c56739c71f99e8a7d58337/storybook/index.html?path=/story/dialogcontainer--nested-dialog-containers
Click or navigate to the "Open menu" button and press Enter or Space to expand the menu.
Click or arrow down to and activate the "Do this..." or "Do that..." menu item.
Click or activate the "Do that" or "Do this" button to replace the Dialog with the nested Dialog.
Repeat step 4 a few times for good measure.
Press Esc key, or use the "Dismiss" button to close the Dialog.
Focus should be restored to the "Open menu" button.
Verify that https://reactspectrum.blob.core.windows.net/reactspectrum/4b09194340f607fab1c56739c71f99e8a7d58337/storybook/index.html?path=/story/focusscope--keyboard-navigation and https://reactspectrum.blob.core.windows.net/reactspectrum/4b09194340f607fab1c56739c71f99e8a7d58337/storybook/index.html?path=/story/focusscope--keyboard-navigation-inside-portal manage and restore focus appropriately.
🧢 Your Project:
Adobe/Accessibility