[Tooltip] Close when a scroll moves the trigger away from the cursor - #49108
Open
stop1love1 wants to merge 2 commits into
Open
[Tooltip] Close when a scroll moves the trigger away from the cursor#49108stop1love1 wants to merge 2 commits into
stop1love1 wants to merge 2 commits into
Conversation
Scrolling moves the trigger out from under a motionless cursor without the browser firing any pointer event, so the tooltip stayed open with nothing hovered. Remember where the cursor was when it entered the trigger, and while the tooltip is open, close it on a scroll that leaves the cursor outside both the trigger and the tooltip. Tooltips opened by focus or by touch have no cursor to leave behind and are left untouched. Closes mui#44548
Deploy previewBundle size
Check out the code infra dashboard for more information about this PR. |
The tests only stubbed the trigger rect, so whether the cursor counted as being over the tooltip depended on where Popper laid it out, which in turn depends on the rendered size of the tooltip. The tooltip wraps differently on the CI font stack than it does locally, and the popper ended up covering the simulated cursor there. Stub every rect the component reads and keep the whole scenario away from the viewport origin so no real pointer of the test browser can interfere.
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.
Closes #44548
Problem
Hover a tooltip trigger, then scroll without moving the mouse: the trigger slides out from under the cursor, but the browser fires no pointer event, so
onMouseLeavenever runs and the tooltip stays open over unrelated content.Repro from the issue — hover a tooltip, scroll away, the tooltip is still there.
This matches what was agreed in the issue thread:
and the ARIA pattern quoted there: the tooltip "remains open as long as the cursor is over the trigger or the tooltip". React Aria and Radix already behave this way.
Solution
handleMouseOveralready funnels every open path, so it records where the cursor was — and recordsnullwhen the event was not amouseover, which is exactly the focus and touch cases.While the tooltip is open, a capture-phase
scrolllistener on the document (mirroring the existingEscapelistener right above it) closes the tooltip when that remembered point is no longer over the trigger nor over the tooltip. It goes throughhandleMouseLeave, soleaveDelayandonClosebehave exactly as they do when the cursor physically leaves.Deliberately unchanged:
The listener only exists while a tooltip is open, and in practice the first scroll event removes it again.
Testing
Four tests in a new
scrollblock. The first one fails onmaster(expected +0 to equal 1—onCloseis never called) and passes with the fix; the other three lock in the cases that must not change.The whole
@mui/materialsuite is unchanged:4687 passedon this branch vs4683 passedonmaster(the 4 new tests), with the same single pre-existingSelectfailure —does not select an option when the opening mouseup lands on it before the drag delay— present on both, and passing in isolation either way.pnpm eslint,pnpm typescriptandprettier --checkare clean on the touched files.