fix: hit-test the topmost view for touch :hover#9731
Draft
MatiPl01 wants to merge 2 commits into
Draft
Conversation
Touch :hover recomputed which views are hovered with a flat on-screen bounds test, so two views that overlap without an ancestor relationship both hovered. Hit-test the topmost view instead and hover it plus its ancestors, matching CSS and the pointer path. Android builds the hit path via TouchTargetHelper rooted on the touched view's own window, so :hover also works inside a Modal/Dialog; iOS uses UIView hitTest, mirroring the :active idiom.
ddc6205 to
e0690e9
Compare
The window touch observer set its state to .failed on touch end/cancel. Because it never sets .began it never claims a touch, so failing was pointless and made UIKit stop delivering the rest of a multi-touch sequence to it (losing the scroll-clear slop and the new-finger recompute). Drop the .failed writes so it stays .possible. Also drop the window<->screen round-trip: observeTouchBegan converted the touch to screen space only for recompute to convert it straight back for hitTest, so track and hit-test in window space directly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Touch
:hoverrecomputed which views are hovered with a flat on-screen bounds test, so two views that overlap on screen but are not in an ancestor relationship both got:hover. CSS hit-tests the topmost element and applies:hoverto it and its ancestors only.This hit-tests the topmost view and hovers it plus its registered ancestors, on each touch-down:
TouchTargetHelper, rooted on the touched view's own window, so:hoveralso works inside aModal/Dialog(a separate window).[window hitTest:]+ a superview walk — the idiom already shipped for:active.The pointer path (
OnHoverListener/UIHoverGestureRecognizer) was already hit-tested correctly; only the touch recompute changes.Test plan
Validated on the Android emulator: overlapping sibling
:hoverboxes → only the topmost hovers;:hoverinside aModalworks; ancestor propagation, sticky persistence, recompute-on-new-tap, and blank-space clear all hold.Known limitations (low severity)
hitTestskips it (now consistent with:active).:hoveris undefined; a second finger recomputes from its own point.