forked from forthfate/openorbit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtoast.tsx
More file actions
73 lines (71 loc) · 2.1 KB
/
Copy pathtoast.tsx
File metadata and controls
73 lines (71 loc) · 2.1 KB
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
68
69
70
71
72
73
import {
useCallback,
useEffect,
useRef,
useState,
type ReactNode,
} from "react";
import { ToastContext, type ToastTone } from "./toast-context";
import { locales, resolveLocale } from "../../locales";
type Toast = { id: number; message: string; tone: ToastTone };
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const locale = resolveLocale(localStorage.getItem("orbit.locale"));
const nextId = useRef(0);
const timers = useRef(new Map<number, number>());
const dismissToast = useCallback((id: number) => {
const timer = timers.current.get(id);
if (timer !== undefined) {
window.clearTimeout(timer);
timers.current.delete(id);
}
setToasts((current) => current.filter((toast) => toast.id !== id));
}, []);
const pushToast = useCallback(
(message: string, tone: ToastTone = "error") => {
if (!message) return;
const id = ++nextId.current;
setToasts((current) => [{ id, message, tone }, ...current]);
timers.current.set(
id,
window.setTimeout(() => dismissToast(id), 10_000),
);
},
[dismissToast],
);
useEffect(
() => () => {
timers.current.forEach((timer) => window.clearTimeout(timer));
timers.current.clear();
},
[],
);
return (
<ToastContext.Provider value={{ pushToast, dismissToast }}>
{children}
<div
className="toast-viewport"
aria-live="polite"
aria-relevant="additions"
>
{toasts.map((toast) => (
<div
key={toast.id}
className={`notice notice--${toast.tone} notice--auto-dismiss`}
role={toast.tone === "error" ? "alert" : "status"}
>
<span>{toast.message}</span>
<button
className="toast-dismiss"
type="button"
aria-label={locales[locale].ui.dismissNotification}
onClick={() => dismissToast(toast.id)}
>
×
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}