Workaround for iOS hover events bug #815
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This works around a bug in iOS Safari that fires the
onPointerEnter
andonMouseEnter
between theonPointerUp
andonFocus
events. This causedonPointerEnter
to be fired twice: once on touch and once before focus, which meant thatuseHover
fired a hover event even though you're on a touch device. Webkit bug filed here: https://bugs.webkit.org/show_bug.cgi?id=214609.The workaround is to register a global event listener for the
pointerup
/touched
event, which sets a flag and unsets it after a quick timeout (after theonFocus
event). This handles two scenarios: the iOS case whereonPointerEnter
is fired prior to focus, and the non-iOS case where this event is not fired. In that case, we do not want to leave the flag hanging, because if the user switched to a mouse after touching the element, the hover event would not fire. The short delay to reset this fixes that.The event is global due to another iOS quirk: focus events (and the prior
onPointerEnter
) are dispatched even when you didn't touch directly on the element, but somewhere nearby. iOS seems to be doing some magic to move focus to the closest element. This means we cannot use a touch event handler on the element itself to determine if there's a preceding touch, we need to listen on the document instead.