You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using multiple levels of toasts and adding toasts to a queue paused with pauseAll (explained in Context below), the toast gets to a state when it doesn't properly respond to hover/focus, and disappears after timeout even when hovered/focused
🤔 Expected Behavior?
Toast added to a paused queue should be in paused state after being added
After the queue resumes, hover/focus should properly pause the timer, not letting it timeout
😯 Current Behavior
When toast is added to a paused queue that gets later resumed, hover/focus doesn't pause it and it disappears even when hovered
💁 Possible Solution
We created a workaround by using a customized toast queue that knows when it is paused, and makes sure the newly added toast gets properly paused when the queue is paused.
Having said that, we are aware that the flushSync is somewhat hacky, as we can't easily influence the default timer being started in the mount of useToast hook
Ideally, the knowledge of the queue being paused should be somehow native, and the hook shouldn't start the timer in this state at all...
import { ToastQueue, ToastOptions } from '@react-stately/toast';
import { flushSync } from 'react-dom';
// We use a custom toast queue to handle the special case when new toast is added while the active toasts are paused
// Without this extra handling, toast added while toasts are paused doesn't respect the pause on hover/focus
export class CustomToastQueue<T> extends ToastQueue<T> {
private _isPaused: boolean = false;
pauseAll() {
this._isPaused = true;
super.pauseAll();
}
resumeAll() {
super.resumeAll();
this._isPaused = false;
}
add(content: T, options?: ToastOptions): string {
let key: string = '';
// Wait for the added toast to render and start its timer in useToast effect
flushSync(() => {
key = super.add(content, options);
});
if (this._isPaused) {
// When all are paused, immediately pause the added toast to prevent premature closing
this.visibleToasts.find((toast) => toast.key === key)?.timer?.pause();
}
return key;
}
}
🔦 Context
In our app, we use several layers of toasts
Top level toast provider in app root + root toast region
Modal with modal fog
Local toast provider in the modal + local toast region
While the modal (local toast provider) is mounted (the underlying layer is not active), the underlying toasts are being paused with queue.pauseAll and upon unmount queue.resumeAll.
While we use only two layers at a time, it is technically possible to nest this behavior. Whenever there is a modal, the underlying layer pauses so that the user can get back to the original context. Some actions may finish just before opening modal, or asynchronously underneath the modal, that is why we decided to handle it with several layers, modal gets its own context...
The problem is that the modal may trigger an action that finishes just before the modal (its local toast provider) gets unmounted and the "confirmation" toast for the modal action that is supposed to appear in the top layer is being added during a paused state,
Because of this, its timer starts even when the parent state is paused, and subsequent resumeAll on the unmount of the local toast provider calls resume on a running timer.
This results in some internal inconsistency, leading to a situation that the hover/focus to a toast no longer pauses its timer, and the toast disappears after the given timeout even when hovered
🖥️ Steps to Reproduce
I extended an existing SnackBar demo that I found with pausing the queue, it is similar to what we use toasts for
Open the code sandbox
Click on "Add snackbar that doesn't pause on hover"
Hover over the snackbar and wait
The snackbar hides even when hovered (FAIL)
Do the same with "Add regular snackbar"
The snackbar correctly pauses on hover (OK)
Note: The code just simulates the situation of adding toast to a paused queue, didn't want to complicate it with multiple levels of providers that we use
Version
3.0.1
What browsers are you seeing the problem on?
Chrome
If other, please specify.
No response
What operating system are you using?
Windows
🧢 Your Company/Team
Kontent.ai
🕷 Tracking Issue
No response
The text was updated successfully, but these errors were encountered:
Provide a general summary of the issue here
When using multiple levels of toasts and adding toasts to a queue paused with
pauseAll
(explained in Context below), the toast gets to a state when it doesn't properly respond to hover/focus, and disappears after timeout even when hovered/focused🤔 Expected Behavior?
Toast added to a paused queue should be in paused state after being added
After the queue resumes, hover/focus should properly pause the timer, not letting it timeout
😯 Current Behavior
When toast is added to a paused queue that gets later resumed, hover/focus doesn't pause it and it disappears even when hovered
💁 Possible Solution
We created a workaround by using a customized toast queue that knows when it is paused, and makes sure the newly added toast gets properly paused when the queue is paused.
Having said that, we are aware that the
flushSync
is somewhat hacky, as we can't easily influence the default timer being started in the mount ofuseToast
hookIdeally, the knowledge of the queue being paused should be somehow native, and the hook shouldn't start the timer in this state at all...
🔦 Context
In our app, we use several layers of toasts
While the modal (local toast provider) is mounted (the underlying layer is not active), the underlying toasts are being paused with
queue.pauseAll
and upon unmountqueue.resumeAll
.While we use only two layers at a time, it is technically possible to nest this behavior. Whenever there is a modal, the underlying layer pauses so that the user can get back to the original context. Some actions may finish just before opening modal, or asynchronously underneath the modal, that is why we decided to handle it with several layers, modal gets its own context...
The problem is that the modal may trigger an action that finishes just before the modal (its local toast provider) gets unmounted and the "confirmation" toast for the modal action that is supposed to appear in the top layer is being added during a paused state,
Because of this, its timer starts even when the parent state is paused, and subsequent
resumeAll
on the unmount of the local toast provider callsresume
on a running timer.This results in some internal inconsistency, leading to a situation that the hover/focus to a toast no longer pauses its timer, and the toast disappears after the given timeout even when hovered
🖥️ Steps to Reproduce
I extended an existing SnackBar demo that I found with pausing the queue, it is similar to what we use toasts for
https://codesandbox.io/p/sandbox/snackbar-joy-ui-feat-react-aria-forked-wqz56v?file=%2Fdemo.tsx
Open the code sandbox
Click on "Add snackbar that doesn't pause on hover"
Hover over the snackbar and wait
The snackbar hides even when hovered (FAIL)
Do the same with "Add regular snackbar"
The snackbar correctly pauses on hover (OK)
Note: The code just simulates the situation of adding toast to a paused queue, didn't want to complicate it with multiple levels of providers that we use
Version
3.0.1
What browsers are you seeing the problem on?
Chrome
If other, please specify.
No response
What operating system are you using?
Windows
🧢 Your Company/Team
Kontent.ai
🕷 Tracking Issue
No response
The text was updated successfully, but these errors were encountered: