Repository navigation
fix(frontend): pause the timer of a toast that a bottom sheet hides - #131
Conversation
On a phone on its side, a bottom sheet hides each toast but the newest, and the hidden toasts keep their timers. The three functional scenarios stop the clock before the page opens, move it by hand, and record which toasts show as time passes. So the real time that a slow browser takes does not count. All three fail. The success toast never shows, and the error toast closes while it waits, also after the focus leaves the toasts. A component test adds a toast while the pointer is on the toasts, and then a newer toast hides it. The hidden toast must not close at its first deadline.
While a bottom sheet is open on a phone, index.css shows only the newest toast and hides the others visually. React Aria started the timer of each toast when it mounted, so a hidden toast closed before the user saw it. An error toast behind a newer success toast was lost. The toast queue now pauses the timer of a hidden toast. When the toast shows again, it gets its full time. A ResizeObserver on each toast tells the queue when the toast is hidden, so index.css stays the one place that decides which toasts show. A pointer or focus that leaves the toast region resumes only the toasts that show. React Aria starts a second timeout when it resumes or resets a timer that runs, and a pause stops only the newest one. So the queue pauses a timer before it starts it again, and it does not resume a toast that has not rendered yet, because the toast starts its timer when it mounts.
|
Open findings from the review gate. Both stay as they are, for the reasons below. L1 (low): the pause flag can stay set when the region empties while it has focus. The queue copies React Aria's own behavior here. Not re-reviewed: the last change to |
Why
On a phone, while a bottom sheet is open,
index.cssshows only the newest toast and hides the others visually (#126). React Aria starts the timer of a toast when the toast mounts, so the hidden toasts closed while the user could not see them. An error toast behind a newer success toast was lost.Closes #128
What changed
toastQueueis now aShownToastQueue. It pauses the timer of a hidden toast, and gives the toast its full time again when it shows. ItsresumeAlldoes not restart a hidden toast when the pointer or the focus leaves the toast region. It pauses a timer before it starts it again, because React Aria starts a second timeout for a timer that runs.Toasterputs aResizeObserveron each toast. A toast thatindex.csshides is 1 px by 1 px, so the observer tells the queue that it is hidden.index.cssstays the one place that decides which toasts show.Scope
Tradeoffs
Blast Radius
Every toast goes through this queue. On a desktop, the observer always reports a shown toast, and
markShowndoes nothing for a toast that was never hidden. The queue uses the publicpause,resume, andresetmethods of the React Aria timer, andpackage.jsonalready pinsreact-aria-componentsto~1.22.1for theUNSTABLE_toast API.Verification
pnpm test:e2e: three new scenarios intests/features/toasts/toasts.spec.tsstop the clock at 667x375 and move it by hand. They fail on main and pass with the fix. 36 passed. The toast specs passed 180 of 180 with--repeat-each=10and--repeat-each=20on 4 workers.pnpm test: a new test intoaster.test.tsxadds a toast while the pointer is on the toasts, then hides it with a newer toast. It fails on main and passed 10 of 10 with the fix. 81 passed.pnpm lintandpnpm buildpass.Sheet open, Success then Error then Info, 5 s later. Before: no toast shows. After: the error shows.