Repository navigation
fix(muya): keep the link popover open when moving between links (#5313) - #5324
Merged
Jocs merged 4 commits intoSep 14, 2026
Merged
Conversation
…text#5313) Hovering a link emits `muya-link-tools` with a reference; leaving one emits it with `reference: null`, which arms a 500ms hide. Moving the pointer from one link to another fires `mouseout` on the old link before `mouseover` on the new one, so that hide is still pending when the popover is shown for the second link. Nothing cancelled it, so it fired 500ms later and closed the popover while the pointer was sitting on a link. With consecutive anchor lines the pointer crosses a link almost continuously, so a stale hide is nearly always pending and the popover appears to flicker and vanish before it can be clicked, leaving Ctrl+Click as the only way to follow a link. Cancel the pending hide when a reference arrives. Leaving a link and going nowhere still hides after the usual delay. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01XWr9UtfXxdTdfHMydFh4V8
anandghegde
force-pushed
the
fix/5313-link-tooltip-stale-hide-timer
branch
from
September 14, 2026 04:45
e00cedc to
bdedf7b
Compare
…on fails The marktext#5313 tests appended their stub anchors to document.body and removed them after the assertions, so a failing expect leaked them into later tests. Mount them inside the session's domNode, which the shared teardown already removes, and move the fake-timer setup into beforeEach/afterEach. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01FbzrQyyA4iG32wvK6j3ki6
The marktext#5313 regression test only checked `status === true`, which the first link's popover had already set, so an implementation that cancelled the stale hide but never showed the second link's popover still passed. Give the second link its own linkInfo and assert that show() last ran for that exact element and that the popover now holds the second link's info. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01FbzrQyyA4iG32wvK6j3ki6
The fix comment restated the timer delay, so changing the delay would have left it wrong, and the test's describe comment repeated the same event-order explanation. Keep one short explanation at the cancel site and point the test at it, per the commenting guidelines. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01FbzrQyyA4iG32wvK6j3ki6
Member
|
Thanks @anandghegde. The root cause and the fix are both right. Verified
Pushed on top (3 small commits)
Left out of this PR (the problem already existed) The popover sits 5px below its link (
With Merging, thanks! |
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.
Fixes #5313.
Root cause
linkMouseEvents.tsdrives the popover with one event: hovering a link emitsmuya-link-toolswith a reference, and leaving one emits it withreference: null.LinkTools.listen()turns the second form into a delayed hide:The show branch never touched
_hideTimer. Because moving the pointer from one element to another firesmouseouton the old one beforemouseoveron the new one, the sequence for two adjacent links is:mouseouton link A →{ reference: null }→ arms a 500ms hidemouseoveron link B →{ reference: B }→ popover shown for B, stale timer still armedhide()→ the popover closes while the pointer is on link BThe delay exists so the pointer can travel from the link to the popover without it closing. It was only ever cancelled by the
mouseoverhandler on the popover container itself, so any path that re-enters a link first left the timer running.That matches the report exactly: it is worst with consecutive anchor lines, because the pointer then crosses links almost continuously, so a stale hide is nearly always pending. The popover flickers and vanishes before it can be clicked, leaving Ctrl+Click as the only way to follow a link.
The fix
Cancel the pending hide when a reference arrives:
Nine lines including the comment, in the one branch that was missing it. The delay itself is unchanged, so leaving a link and going nowhere still hides after the usual 500ms.
Verification
Two tests added to the existing
linkTools.spec.ts, using itsbootLinkTools()harness (realEventCenter, realLinkTools) with fake timers, asserting onBaseFloat's publicstatusflag:keeps the popover open when the pointer moves straight to another link— replays the exact three-step sequence above and advances 1000ms.still hides when the pointer leaves a link and goes nowhere— guards the other direction, so the fix cannot degrade into "never hides".Reverting just the
index.tschange makes the first test fail and leaves the second passing:With the fix, the full muya suite is green:
eslint src/ui/linkToolsandtsc --noEmitare both clean inpackages/muya.Notes
I could not reproduce on Windows 11 as reported — I verified on macOS. The mechanism is platform-independent (DOM event ordering plus a timer), and the reporter's "densely stacked anchors" detail is what makes a stale hide almost always pending, so I'm confident it is the same bug. If you would like it confirmed on Windows before merging, I'm happy to wait for someone with that setup.
I left the
mouseOverHandleron the popover container alone; it clears the timer without nulling it, which is harmless since every read is guarded.