at main 1.6 kB view raw
1// global toast notification state using Svelte 5 runes 2 3export type ToastType = 'success' | 'error' | 'info' | 'warning'; 4 5export interface ToastAction { 6 label: string; 7 href: string; 8} 9 10export interface Toast { 11 id: string; 12 message: string; 13 type: ToastType; 14 duration: number; 15 dismissible: boolean; 16 action?: ToastAction; 17} 18 19class ToastState { 20 toasts = $state<Toast[]>([]); 21 22 add(message: string, type: ToastType = 'info', duration = 3000, action?: ToastAction): string { 23 const id = crypto.randomUUID(); 24 const toast: Toast = { 25 id, 26 message, 27 type, 28 duration, 29 dismissible: true, 30 action 31 }; 32 33 this.toasts = [toast, ...this.toasts]; 34 35 if (duration > 0) { 36 setTimeout(() => this.dismiss(id), duration); 37 } 38 39 return id; 40 } 41 42 dismiss(id: string): void { 43 this.toasts = this.toasts.filter(t => t.id !== id); 44 } 45 46 update(id: string, message: string, type?: ToastType): void { 47 const index = this.toasts.findIndex(t => t.id === id); 48 if (index !== -1) { 49 this.toasts[index].message = message; 50 if (type) { 51 this.toasts[index].type = type; 52 } 53 } 54 } 55 56 success(message: string, duration = 3000, action?: ToastAction): string { 57 return this.add(message, 'success', duration, action); 58 } 59 60 error(message: string, duration = 5000): string { 61 return this.add(message, 'error', duration); 62 } 63 64 info(message: string, duration = 3000, action?: ToastAction): string { 65 return this.add(message, 'info', duration, action); 66 } 67 68 warning(message: string, duration = 4000): string { 69 return this.add(message, 'warning', duration); 70 } 71} 72 73export const toast = new ToastState();