fix: notification stays visible when mounted under cursor#4
Open
athulchandroth wants to merge 1 commit into
Open
fix: notification stays visible when mounted under cursor#4athulchandroth wants to merge 1 commit into
athulchandroth wants to merge 1 commit into
Conversation
Auto-dismiss relied on `mouseenter`/`mouseleave` to track hover state and on a CSS `:hover` rule to pause the countdown bar. When a card mounts under the cursor (common with overlay notifications): - CSS `:hover` activates immediately and pauses the countdown animation, but `mouseenter` does NOT fire (the cursor was already inside, never "entered"). The bar stays paused indefinitely. - The JS `hovering` ref also stays false in some Tauri NSPanel cases, so the timer fires but visual state is stuck — or the ref incorrectly becomes true and the timer is cleared with no `mouseleave` to restart it. Net effect: the first-ever notification in a stack (and often the last remaining one) never auto-dismisses. Fix: drop the CSS `:hover` pause and replace `mouseenter`/`mouseleave` with global `mousemove` tracking + bounding-rect check. The dismiss tick checks the actual cursor position against the card's rect, so a card mounted under a stationary cursor still dismisses correctly once the cursor moves away (or immediately if it never moved).
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
mouseenterdoesn't fire when an element appears under an already-present cursor, but the CSS:hoverrule pauses the countdown animation immediately. JS hover state and CSS hover state desync, leaving the notification stuck.:hoverpause and replacemouseenter/mouseleavewith globalmousemovetracking + bounding-rect check.Repro (before this PR)
syncfu send -t "Test" "should auto-close in 8s".The same happens with the last remaining notification in a stack — once siblings dismiss and the bottom card slides into the cursor area, it gets stuck.
Root cause
Two independent hover-pause mechanisms that don't sync:
:hoverpseudo-class inoverlay.csspaused the countdown animation viaanimation-play-state: paused. This activates on mount the instant the cursor is inside the element's box.mouseenterhandler inNotificationCard.tsxsethovering.current = trueand cleared the dismiss timer. Butmouseenteronly fires when the cursor moves into an element — if the element appears under an already-present cursor, no event fires.Combined effect: CSS pauses the bar visually, JS may or may not pause the dismiss timer (depending on whether
mouseenterfires under the Tauri NSPanel), and once stuck there's no event to recover from.Fix
src/styles/overlay.css— remove:hoverrule that pausedanimation-play-stateon the countdown bar. JS now owns hover-pause exclusively.src/components/overlay/NotificationCard.tsx— replacemouseenter/mouseleaveref tracking with a globalmousemovelistener that records cursor position. The dismiss tick checks the cursor against the card's bounding rect viagetBoundingClientRect(). Initial cursor is(-1, -1)(treated as "not hovered"), so a card under a stationary cursor still dismisses on schedule.Test plan
NotificationCard.test.tsxtests passpnpm tsc --noEmit)autoDismissMs✅Notes
.pausedclass on hover and the CSS could pause via that class instead of:hover.