Skip to main content

Toast auto-dismiss resumes after the hovered stack becomes empty (WEB-1537)

Version: 0.10.0 ยท Type: ๐Ÿ› Bug Fix

WEB-1537 ยท Source incident: FM-1582

Problemโ€‹

Hovering the toast stack pauses auto-dismiss timers. If the final visible toast is dismissed while the pointer is still over the stack, later finite-duration toasts can remain visible indefinitely and render with the expanded hover layout until the page is refreshed.

Root Causeโ€‹

Timer suspension lived in the global toastManager.paused state, but resuming depended on the Toaster host's mouseleave event. Dismissing the final visible toast unmounts the host <ol>, and browsers do not emit mouseleave for a node after it has been removed. The manager therefore stayed paused and only registered future timers without starting them.

The stacked expansion state was also stored separately in Toaster, even though it was driven by the same mouseenter / mouseleave pair, so both states could remain stale together.

Changed Filesโ€‹

  • packages/design/src/components/Toast/toast-manager.ts
  • packages/design/src/components/Toast/Toaster.tsx
  • packages/design/src/components/Toast/__tests__/Toast.autoDismiss.test.tsx

Changesโ€‹

  1. Expose toastManager.isPaused() and notify subscribers whenever pauseAll() or resumeAll() changes the pause state.
  2. After dismiss() marks a toast invisible, immediately call resumeAll() when no visible records remain. This runs before the exit-animation record is removed, so a toast created during that window starts its timer normally.
  3. Remove Toaster's local expanded state and derive stack expansion from the manager's pause snapshot through useSyncExternalStore, giving timer suspension and stack layout one source of truth.
  4. Add five regression tests covering ordinary auto-dismiss, hover pause/resume, dismissing the final hovered toast, creating a toast during the exit-animation window, and restoring the collapsed stack layout.

Impactโ€‹

Toasts created after a hovered stack is cleared now auto-dismiss normally. Existing hover-to-pause and leave-to-resume behavior is unchanged. There is no public API or visual-spec change.