import { createContext, useCallback, useContext, useRef, useState, type ReactNode } from "react"; import { CheckCircle2, AlertTriangle, Info, X } from "lucide-react"; import { cn } from "./cn"; type ToastTone = "success" | "error" | "info"; interface Toast { id: number; tone: ToastTone; msg: string; } interface ToastCtx { push: (tone: ToastTone, msg: string) => void; } const Ctx = createContext({ push: () => {} }); // useToast 在任意组件里弹出全局通知。 export function useToast() { return useContext(Ctx); } const icons = { success: CheckCircle2, error: AlertTriangle, info: Info }; const accent = { success: "text-success", error: "text-danger", info: "text-accent-400", }; export function ToastProvider({ children }: { children: ReactNode }) { const [toasts, setToasts] = useState([]); const seq = useRef(0); const push = useCallback((tone: ToastTone, msg: string) => { const id = ++seq.current; setToasts((t) => [...t, { id, tone, msg }]); setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 4200); }, []); const dismiss = (id: number) => setToasts((t) => t.filter((x) => x.id !== id)); return ( {children}
{toasts.map((t) => { const Icon = icons[t.tone]; return (
{t.msg}
); })}
); }