import { html, useState, useEffect, useCallback, useRef } from '../lib/preact.js'; /** * Lightweight toast notification system. * Tracks error counts and surfaces persistent issues. */ // Singleton state for toast management (shared across components) let toastListeners = []; let toastIdCounter = 0; export function showToast(message, type = 'error', duration = 5000) { const id = ++toastIdCounter; const toast = { id, message, type, duration }; toastListeners.forEach(listener => listener(toast)); return id; } export function ToastContainer() { const [toasts, setToasts] = useState([]); const timeoutIds = useRef(new Map()); useEffect(() => { const listener = (toast) => { setToasts(prev => [...prev, toast]); if (toast.duration > 0) { const timeoutId = setTimeout(() => { timeoutIds.current.delete(toast.id); setToasts(prev => prev.filter(t => t.id !== toast.id)); }, toast.duration); timeoutIds.current.set(toast.id, timeoutId); } }; toastListeners.push(listener); return () => { toastListeners = toastListeners.filter(l => l !== listener); // Clear all pending timeouts on unmount timeoutIds.current.forEach(id => clearTimeout(id)); timeoutIds.current.clear(); }; }, []); const dismiss = useCallback((id) => { // Clear auto-dismiss timeout if exists const timeoutId = timeoutIds.current.get(id); if (timeoutId) { clearTimeout(timeoutId); timeoutIds.current.delete(id); } setToasts(prev => prev.filter(t => t.id !== id)); }, []); if (toasts.length === 0) return null; return html`