Skip to content
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

[Popover] Improved focus event handling #2382

Merged
merged 3 commits into from
Apr 17, 2018

Conversation

reiv
Copy link
Contributor

@reiv reiv commented Apr 12, 2018

Fixes #2373

Changes proposed in this pull request:

This PR makes two changes to the way Popover handles focus events.

  1. Use FocusEvent.relatedTarget¹ instead of wrapping document.activeElement in a timeout to accomplish the same.
  2. Check if the target gained focus when it was already previously focused but the page itself lost focus (e.g. due to tabbing out) -- in this case the popover won't open again.

[1] MDN says this is "experimental technology", but it seems to be available in all browsers save for IE < 9.

@reiv
Copy link
Contributor Author

reiv commented Apr 12, 2018

Ignore focus gained from outside page

Preview: documentation | landing | table

Copy link
Contributor

@giladgray giladgray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 this is sweeeeeet!

this.handleMouseEnter(e);
}
};

private handleTargetBlur = (e?: React.FormEvent<HTMLElement>) => {
private handleTargetBlur = (e?: React.FocusEvent<HTMLElement>) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this arg required? to ensure that it exists before you reference it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing. No idea why it was optional to begin with. API change in React?

@@ -499,23 +503,26 @@ export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState>
}
};

private handleTargetFocus = (e?: React.FormEvent<HTMLElement>) => {
private handleTargetFocus = (e?: React.FocusEvent<HTMLElement>) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

required?

@reiv
Copy link
Contributor Author

reiv commented Apr 13, 2018

Make event arg non-optional

Preview: documentation | landing | table

@giladgray
Copy link
Contributor

@reiv what's the best way to verify this feature in the docs preview? perhaps you could add a switch for openOnTargetFocus in the example after canEscapeKeyClose in the Interactions column?
image

@reiv
Copy link
Contributor Author

reiv commented Apr 17, 2018

@giladgray I made the change to fix this tooltip behavior: #2373. You can try reproducing that (see the GIF I posted); the tooltip should no longer reappear when the page reacquires focus. The tooltip attached to the button on the Tooltip docs page can be used as well. The popover example which I think you're referring to still suffers from another buggy focus-related interaction which this PR does not address (#2307), so it would probably not work the way we'd expect.

@giladgray
Copy link
Contributor

@reiv ah yes of course, thanks. in this PR, the tooltip no longer re-opens when switching back to the page, but i think ideally the tooltip wouldn't close when you leave the page (relatedTarget == null). is that possible to implement?

@reiv
Copy link
Contributor Author

reiv commented Apr 17, 2018

@giladgray That sounds reasonable. I'll check it out when I get the time.

@giladgray
Copy link
Contributor

thanks @reiv, you are a champion! 🏆

@reiv
Copy link
Contributor Author

reiv commented Apr 17, 2018

@giladgray Ok so the behavior in #2373 is actually a bit more nuanced than that, and your suggestion alone wouldn't change it. To break it down step by step:

  1. Let's say I'm hovering the popover target with the mouse, causing the popover to appear.
  2. I then click the target, causing it to acquire focus (if it is focusable, either due to being an interactive element or via the openOnTargetFocus prop).
  3. Now I move the mouse away, which is what initially causes the popover to close. (Note that the target still has focus at this point).
  4. Then I navigate away from the page by tabbing out, clearing focus on that page.
  5. Finally, I return to the page, causing focus to return to the target and re-opening the popover. It feels weird because I already mentally registered "dismissing" the popover by moving the mouse away from it.

In order to reconcile this with your suggestion, the popover would need to stay open as long as the popover target has focus, even if the hover interaction dictates that it should close. I'm not sure what this means for canEscapeKeyClose, though. I think maybe the current state of the PR has the least surprising user experience, compared to all the focus-related edge cases we would otherwise have to consider.

@giladgray
Copy link
Contributor

@reiv thank you for investigating! what you describe makes good sense about opened vs focused. perhaps we could add some "opened & focused & lost focus to other page" logic but that's starting to feel crufty, so let's call it here.

the behavior in this PR is certainly an improvement so let's ship it!

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants