import { createContext, useContext, createSignal, For, Show, onCleanup, } from "solid-js"; import { cn } from "~/lib/utils"; import type { JSX } from "solid-js"; type ToastVariant = "success" | "error" | "warning" | "info"; interface Toast { id: string; message: string; variant: ToastVariant; duration: number; } interface ToastContextValue { toasts: () => Toast[]; showToast: ( message: string, variant?: ToastVariant, duration?: number, ) => string; dismissToast: (id: string) => void; } const ToastContext = createContext(); export function useToast() { const ctx = useContext(ToastContext); if (!ctx) throw new Error("useToast must be used within a ToastProvider"); return ctx; } export function ToastProvider(props: { children: JSX.Element }) { const [toasts, setToasts] = createSignal([]); const timers = new Map>(); const showToast = ( message: string, variant: ToastVariant = "info", duration = 4000, ) => { const id = globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2, 10); const toast: Toast = { id, message, variant, duration }; setToasts((prev) => [...prev, toast]); if (duration > 0) { const timer = setTimeout(() => dismissToast(id), duration); timers.set(id, timer); } return id; }; const dismissToast = (id: string) => { const timer = timers.get(id); if (timer) { clearTimeout(timer); timers.delete(id); } setToasts((prev) => prev.filter((t) => t.id !== id)); }; onCleanup(() => { for (const timer of timers.values()) { clearTimeout(timer); } timers.clear(); }); const value: ToastContextValue = { toasts, showToast, dismissToast, }; return ( {props.children} ); } const variantStyles: Record = { success: "border-[var(--color-success)] bg-[var(--color-success-bg)] text-[var(--color-success)]", error: "border-[var(--color-error)] bg-[var(--color-error-bg)] text-[var(--color-error)]", warning: "border-[var(--color-warning)] bg-[var(--color-warning-bg)] text-[var(--color-warning)]", info: "border-[var(--color-info)] bg-[var(--color-info-bg)] text-[var(--color-info)]", }; function ToastContainer() { const { toasts, dismissToast } = useToast(); return ( 0}>
{(toast) => ( )}
); }