Fix toast progress bar desync (#871)
* Fix toast progress bar desync If a toast gets rendered again with the same animation-delay, the animation-delay seems to get added. This commit fixes that by ensuring that animation-delay is only set if the toast was not rendered before. * Fix comment
This commit is contained in:
parent
fa4f09ddca
commit
d987069fae
|
@ -10,6 +10,27 @@ const ToastContext = createContext(() => {})
|
||||||
|
|
||||||
export const TOAST_DEFAULT_DELAY_MS = 5000
|
export const TOAST_DEFAULT_DELAY_MS = 5000
|
||||||
|
|
||||||
|
const ensureFlow = (toasts, newToast) => {
|
||||||
|
const { flowId } = newToast
|
||||||
|
if (flowId) {
|
||||||
|
// replace previous toast with same flow id
|
||||||
|
const idx = toasts.findIndex(toast => toast.flowId === flowId)
|
||||||
|
if (idx === -1) return [...toasts, newToast]
|
||||||
|
return [
|
||||||
|
...toasts.slice(0, idx),
|
||||||
|
newToast,
|
||||||
|
...toasts.slice(idx + 1)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return [...toasts, newToast]
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapHidden = ({ id, tag }) => toast => {
|
||||||
|
// mark every previous toast with same tag as hidden
|
||||||
|
if (toast.tag === tag && toast.id !== id) return { ...toast, hidden: true }
|
||||||
|
return toast
|
||||||
|
}
|
||||||
|
|
||||||
export const ToastProvider = ({ children }) => {
|
export const ToastProvider = ({ children }) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [toasts, setToasts] = useState([])
|
const [toasts, setToasts] = useState([])
|
||||||
|
@ -21,20 +42,7 @@ export const ToastProvider = ({ children }) => {
|
||||||
createdAt: +new Date(),
|
createdAt: +new Date(),
|
||||||
id: toastId.current++
|
id: toastId.current++
|
||||||
}
|
}
|
||||||
const { flowId } = toast
|
setToasts(toasts => ensureFlow(toasts, toast).map(mapHidden(toast)))
|
||||||
setToasts(toasts => {
|
|
||||||
if (flowId) {
|
|
||||||
// replace previous toast with same flow id
|
|
||||||
const idx = toasts.findIndex(toast => toast.flowId === flowId)
|
|
||||||
if (idx === -1) return [...toasts, toast]
|
|
||||||
return [
|
|
||||||
...toasts.slice(0, idx),
|
|
||||||
toast,
|
|
||||||
...toasts.slice(idx + 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return [...toasts, toast]
|
|
||||||
})
|
|
||||||
return () => removeToast(toast)
|
return () => removeToast(toast)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
@ -149,7 +157,12 @@ export const ToastProvider = ({ children }) => {
|
||||||
: toast.onCancel
|
: toast.onCancel
|
||||||
? <div className={`${styles.toastCancel} ${textStyle}`}>cancel</div>
|
? <div className={`${styles.toastCancel} ${textStyle}`}>cancel</div>
|
||||||
: <div className={`${styles.toastClose} ${textStyle}`}>X</div>
|
: <div className={`${styles.toastClose} ${textStyle}`}>X</div>
|
||||||
|
// a toast is unhidden if it was hidden before since it now gets rendered
|
||||||
|
const unhidden = toast.hidden
|
||||||
|
// we only need to start the animation at a different timing when it was hidden by another toast before.
|
||||||
|
// if we don't do this, the animation for rerendered toasts skips ahead and toast delay and animation get out of sync.
|
||||||
const elapsed = (+new Date() - toast.createdAt)
|
const elapsed = (+new Date() - toast.createdAt)
|
||||||
|
const animationDelay = unhidden ? `-${elapsed}ms` : undefined
|
||||||
return (
|
return (
|
||||||
<Toast
|
<Toast
|
||||||
key={toast.id} bg={toast.variant} show autohide={toast.autohide}
|
key={toast.id} bg={toast.variant} show autohide={toast.autohide}
|
||||||
|
@ -167,7 +180,7 @@ export const ToastProvider = ({ children }) => {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ToastBody>
|
</ToastBody>
|
||||||
{toast.delay > 0 && <div className={`${styles.progressBar} ${styles[toast.variant]}`} style={{ animationDelay: `-${elapsed}ms` }} />}
|
{toast.delay > 0 && <div className={`${styles.progressBar} ${styles[toast.variant]}`} style={{ animationDelay }} />}
|
||||||
</Toast>
|
</Toast>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
Loading…
Reference in New Issue