Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import React, { createContext, useContext, useState, useRef, useCallback, type ReactNode, type JSX, } from "react"; /** Visual style variant for a toast notification. */ export type ToastVariant = "success" | "error" | "warning" | "info"; /** A single toast notification item. */ export interface ToastItem { id: string; message: string; variant: ToastVariant; /** Auto-dismiss delay in milliseconds. */ duration: number; } interface ToastContextValue { toasts: ToastItem[]; /** Display a new toast notification. */ showToast: (message: string, variant?: ToastVariant, duration?: number) => void; /** Programmatically remove a toast by id. */ dismissToast: (id: string) => void; } const ToastContext: React.Context<ToastContextValue | undefined> = createContext< ToastContextValue | undefined >(undefined); const DEFAULT_DURATION_MS: number = 4_000; /** Provides toast notification state to the component tree. Mount <ToastContainer> as a sibling to receive rendered output. */ export function ToastProvider({ children }: { children: ReactNode }): JSX.Element { const [toasts, setToasts] = useState<ToastItem[]>([]); const toastCounterRef = useRef<number>(0); const dismissToast = useCallback((id: string) => { setToasts((prev) => prev.filter((t) => t.id !== id)); }, []); const showToast = useCallback( (message: string, variant: ToastVariant = "info", duration: number = DEFAULT_DURATION_MS) => { const id = `toast-${++toastCounterRef.current}`; setToasts((prev) => [...prev, { id, message, variant, duration }]); }, [], ); return ( <ToastContext.Provider value={{ toasts, showToast, dismissToast }}> {children} </ToastContext.Provider> ); } /** Consumes the toast context; must be called within a ToastProvider. */ export function useToast(): ToastContextValue { const ctx = useContext(ToastContext); if (!ctx) throw new Error("useToast must be used within ToastProvider"); return ctx; } |