forked from baron/baron-sso
67 lines
1.6 KiB
TypeScript
67 lines
1.6 KiB
TypeScript
import * as React from "react";
|
|
|
|
type ToastType = "success" | "error" | "info";
|
|
|
|
interface Toast {
|
|
id: string;
|
|
message: string;
|
|
type: ToastType;
|
|
}
|
|
|
|
let subscribers: ((toasts: Toast[]) => void)[] = [];
|
|
let toasts: Toast[] = [];
|
|
|
|
const notify = () => {
|
|
for (const sub of subscribers) {
|
|
sub(toasts);
|
|
}
|
|
};
|
|
|
|
const toastBase = (message: string, type: ToastType = "success") => {
|
|
const id = Math.random().toString(36).substring(2, 9);
|
|
toasts = [...toasts, { id, message, type }];
|
|
notify();
|
|
|
|
setTimeout(() => {
|
|
toasts = toasts.filter((t) => t.id !== id);
|
|
notify();
|
|
}, 3000);
|
|
};
|
|
|
|
export const toast = Object.assign(toastBase, {
|
|
success: (message: string, options?: { description?: string }) => {
|
|
const finalMessage = options?.description
|
|
? `${message}
|
|
${options.description}`
|
|
: message;
|
|
toastBase(finalMessage, "success");
|
|
},
|
|
error: (message: string, options?: { description?: string }) => {
|
|
const finalMessage = options?.description
|
|
? `${message}
|
|
${options.description}`
|
|
: message;
|
|
toastBase(finalMessage, "error");
|
|
},
|
|
info: (message: string, options?: { description?: string }) => {
|
|
const finalMessage = options?.description
|
|
? `${message}
|
|
${options.description}`
|
|
: message;
|
|
toastBase(finalMessage, "info");
|
|
},
|
|
});
|
|
|
|
export const useToastState = () => {
|
|
const [state, setState] = React.useState<Toast[]>(toasts);
|
|
|
|
React.useEffect(() => {
|
|
subscribers.push(setState);
|
|
return () => {
|
|
subscribers = subscribers.filter((sub) => sub !== setState);
|
|
};
|
|
}, []);
|
|
|
|
return state;
|
|
};
|