Spaces:
Running
Running
File size: 1,764 Bytes
0dd2082 | 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 | 'use client';
import { createContext, useContext, useState, useCallback } from 'react';
import './ToastContext.css';
const ToastContext = createContext(null);
export function ToastProvider({ children }) {
const [toasts, setToasts] = useState([]);
const addToast = useCallback((message, type = 'info', duration = 3000) => {
const id = Date.now();
setToasts(prev => [...prev, { id, message, type }]);
setTimeout(() => {
setToasts(prev => prev.filter(t => t.id !== id));
}, duration);
}, []);
const removeToast = useCallback(id => {
setToasts(prev => prev.filter(t => t.id !== id));
}, []);
return (
<ToastContext.Provider value={{ addToast }}>
{children}
<div className="toast-container" aria-live="polite">
{toasts.map(toast => (
<div key={toast.id} className={`toast toast-${toast.type} fade-in-up`}>
{toast.type === 'success' && '✅ '}
{toast.type === 'error' && '❌ '}
{toast.type === 'info' && '💡 '}
{toast.message}
<button
className="toast-close"
onClick={() => removeToast(toast.id)}
aria-label="Close"
>
×
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
export function useToast() {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within a ToastProvider');
}
return context;
}
|