import delay from 'delay'; import React from 'dom-chef'; import {CheckIcon, StopIcon} from '@primer/octicons-react'; export function ToastSpinner(): JSX.Element { return ( ); } type ProgressCallback = (message: string) => void; type Task = (progress?: ProgressCallback) => Promise; export default async function showToast( task: TTask, { message = 'Bulk actions currently being processed.', doneMessage = 'Bulk action processing complete.', } = {}, ): Promise> { const iconWrapper = ; const messageWrapper = {message}; const toast = (
{iconWrapper} {messageWrapper}
); const updateToast = (message: string): void => { messageWrapper.textContent = message; }; document.body.append(toast); await delay(30); // Without this, the Toast doesn't appear in time try { const result = await task(updateToast); toast.classList.replace('Toast--loading', 'Toast--success'); updateToast(doneMessage); iconWrapper.firstChild!.replaceWith(); return result; } catch (error: unknown) { toast.classList.replace('Toast--loading', 'Toast--error'); updateToast(error instanceof Error ? error.message : 'Unknown Error'); iconWrapper.firstChild!.replaceWith(); throw error; } finally { // Without rAF the toast might be removed before the first page paint // rAF also allows showToast to resolve as soon as task is done requestAnimationFrame(() => { setTimeout(() => { toast.remove(); }, 3000); }); } }