export type ToastType = 'success' | 'error' | 'info' | 'warning' export interface ToastItem { id: number type: ToastType message: string duration: number } type Listener = (items: ToastItem[]) => void let seq = 1 let items: ToastItem[] = [] const listeners = new Set() function emit() { listeners.forEach((fn) => fn([...items])) } function push(type: ToastType, message: string, duration = 3000) { const id = seq++ const item: ToastItem = { id, type, message, duration } items = [...items, item] emit() if (duration > 0) { window.setTimeout(() => { dismiss(id) }, duration) } return id } export function dismiss(id: number) { items = items.filter((t) => t.id !== id) emit() } export function subscribeToast(listener: Listener) { listeners.add(listener) listener([...items]) return () => { listeners.delete(listener) } } export const toast = { success: (message: string, duration?: number) => push('success', message, duration), error: (message: string, duration?: number) => push('error', message, duration ?? 4000), info: (message: string, duration?: number) => push('info', message, duration), warning: (message: string, duration?: number) => push('warning', message, duration), }