Spaces:
Sleeping
Sleeping
Create Toasts.jsx
Browse files- client/src/Toasts.jsx +31 -0
client/src/Toasts.jsx
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { createContext, useContext, useMemo, useState, useCallback } from 'react';
|
| 2 |
+
|
| 3 |
+
const ToastCtx = createContext(null);
|
| 4 |
+
|
| 5 |
+
export function ToastProvider({ children }) {
|
| 6 |
+
const [toasts, setToasts] = useState([]);
|
| 7 |
+
const push = useCallback((msg, tone = 'good', ttl = 3200) => {
|
| 8 |
+
const id = Math.random().toString(36).slice(2);
|
| 9 |
+
setToasts(t => [...t, { id, msg, tone }]);
|
| 10 |
+
setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), ttl);
|
| 11 |
+
}, []);
|
| 12 |
+
const api = useMemo(() => ({ push }), [push]);
|
| 13 |
+
return (
|
| 14 |
+
<ToastCtx.Provider value={api}>
|
| 15 |
+
{children}
|
| 16 |
+
<div className="toast-wrap">
|
| 17 |
+
{toasts.map(t => (
|
| 18 |
+
<div key={t.id} className={`toast ${t.tone}`}>
|
| 19 |
+
{t.msg}
|
| 20 |
+
</div>
|
| 21 |
+
))}
|
| 22 |
+
</div>
|
| 23 |
+
</ToastCtx.Provider>
|
| 24 |
+
);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
export function useToasts() {
|
| 28 |
+
const ctx = useContext(ToastCtx);
|
| 29 |
+
if (!ctx) throw new Error('useToasts must be used inside <ToastProvider>');
|
| 30 |
+
return ctx;
|
| 31 |
+
}
|