-
Notifications
You must be signed in to change notification settings - Fork 842
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
fix(tool_tip): stop propagation on escape key down #8140
fix(tool_tip): stop propagation on escape key down #8140
Conversation
98a69dd
to
7068ec9
Compare
a4d77c5
to
3bcd2b5
Compare
3bcd2b5
to
ba8708d
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.
This LGTM (awesome work with the E2E test!) - but I'll defer to @mgadewoll for any final comments since I believe she solved a similar bug/issue recently. My only other thought is we might also want to either QA or write a test for the following other focus trap components:
- modals
- popovers
- various fullscreen modes (EuiDataGrid fullscreen, EuiImage fullscreen, EuiCodeBlock fullscreen(?) - not sure that last one can even have a tooltip)
Thanks for the great suggestion, Cee! 🌈 I focused so much on fixing that one test case I forgot about the other overlay elements that might suffer the same issue. I updated the description with the screen recordings from the manual QA. One doubt I have - is the If we agree to add the automated tests after all, I'll work on that first thing Monday! |
ba8708d
to
7acdd8b
Compare
I'm fine with skipping the automated Cypress tests for each focus trap use case - flyouts are likely our biggest use-case in any case. EuiDataGrid might be the second most likely use-case in production. I'm also fine with manual QA only for the cases I noted, I just want to make sure someone tested it :) It might also be nice for future devs to add an inline comment next to the flyout Cypress test noting which other edge cases to manually QA. |
@@ -280,6 +280,7 @@ export class EuiToolTip extends Component<EuiToolTipProps, State> { | |||
|
|||
onEscapeKey = (event: React.KeyboardEvent<HTMLSpanElement>) => { | |||
if (event.key === keys.ESCAPE) { | |||
event.stopPropagation(); |
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.
One thing: This means the Escape
key will never propagate. We might rather want to stop propagation only conditionally when it's visible.
If the tooltip is closed it would be expected that Escape
closes the Flyout, otherwise users would first need to move off the tooltip anchor to be able to close it or would even be stuck in wrapper elements where there is no other element to navigate too. 🤔
static - blocking
Screen.Recording.2024-11-25.at.10.14.42.mov
conditional
Screen.Recording.2024-11-25.at.10.15.13.mov
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.
@mgadewoll that's true, the way I understood it is if the tooltip trigger is focused, the Escape shouldn't close the wrapping element. Is it something we can consult with an accessibility contractor? Or maybe it's something obvious that I'm not aware about 😅
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.
While the tooltip is open, I'd agree that it should not close any wrapping element. But while it's closed I'd think it's more useful to free up the Escape
key and prevent blocking.
I would see the behavior as follows:
- trigger is focused -> tooltip opens (active tooltip)
Escape
is pressed -> tooltip closes (inactive tooltip) -> trigger stays focused as that's where the DOM focus was all the time already (no new focus on trigger)Enter
is pressed -> opens tooltip (active tooltip)
OREscape
is pressed -> closes containing element (e.g. flyout or similar)
@alexwizp Do you have any insights here?
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.
@mgadewoll this absolutely makes sense to me! I'll let @alexwizp confirm and I'll push the changes. I also think it'd be good to cover both paths with an automated test.
7acdd8b
to
61d6291
Compare
@cee-chen @mgadewoll I conditionally call I'd appreciate a re-review 🙏🏻 and thanks again for the awesome suggestions! |
@weronikaolejniczak It looks like the added Cypress test is failing on React 17/16 which is odd 👀 You may want to |
@cee-chen I’m not exactly sure why but two tests for The solution was to focus the tool-tip trigger directly instead of tabbing into it to assure consistent behavior between versions. Otherwise, the tabbing would start and end at different elements depending on the version. |
to account for the differences between React versions
a696364
to
6dc6d35
Compare
@weronikaolejniczak For testing with key presses, I generally would prefer to be able to use proper Instead we could still use // example for Flyout
cy.mount(
<Flyout>
<EuiToolTip content="Tooltip text here" data-test-subj="tool_tip">
<EuiButton data-test-subj="tool_tip_trigger">Show tooltip</EuiButton>
</EuiToolTip>
</Flyout>
);
cy.get('[data-test-subj="flyout"]').focus(); // move focus to flyout
cy.get('[data-test-subj="tool_tip"]').should('not.exist');
cy.repeatRealPress('Tab', 2);
cy.get('[data-test-subj="tool_tip"]').should('exist');
cy.realPress('Escape');
cy.get('[data-test-subj="tool_tip"]').should('not.exist');
cy.get('[data-test-subj="flyout"]').should('exist');
cy.realPress('Escape');
cy.get('[data-test-subj="flyout"]').should('not.exist'); |
@mgadewoll that's a fantastic suggestion, thank you, Lene! 🙌🏻 I pushed the changes for all test cases, could you check? |
Preview staging links for this PR:
|
💚 Build Succeeded
History
|
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.
🚢 🐈⬛ Thanks for the additional changes! Updates LGTM 👍
Summary
When we have
EuiIconTip
(consequently,EuiTooltip
) withinEuiFlyout
and with the tooltip open we click "Escape" key, the flyout gets closed. The reason is, the escape keydown event is propagated from the tooltip and captured by the flyout as its parent. Simpleevent.stopPropagation()
insideEuiTooltip
seemed to do the trick.closes #8130
QA
Test path:
yarn storybook
.EuiFlyout
.EuiFlyoutBody
to contain aEuiToolTip
as children.Screen.Recording.2024-11-27.at.12.43.26.mov
Manual QA of other focus-trap elements
EuiModal
Screen.Recording.2024-11-27.at.12.37.48.mov
EuiPopover
Screen.Recording.2024-11-27.at.12.42.35.mov
EuiDataGrid fullscreen
Screen.Recording.2024-11-27.at.12.44.14.mov
General checklist
Checked in both light and dark modes(not applicable)Checked in mobile(not applicable)Added documentation(not applicable)Props have proper autodocs (using(not applicable)@default
if default values are missing) and playground togglesChecked Code Sandbox works for any docs examples(not applicable)Updated visual regression tests(not applicable)If applicable, added the breaking change issue label (and filled out the breaking change checklist)If applicable, file an issue to update EUI's Figma library with any corresponding UI changes. (This is an internal repo, if you are external to Elastic, ask a maintainer to submit this request)