/** @jsxImportSource @emotion/react */ import { keyframes } from '@emotion/react'; import { ReactNode, createContext, useContext, useEffect, useState } from 'react'; interface ToastProps { theme?: 'light' | 'dark'; status?: 'success' | 'failed'; id: string; title: string; description?: string; countdown?: number; } interface ToastContextType { addToast: (props: Omit & { countdown?: number }) => void; toasts: ToastProps[]; } const ToastContext = createContext({ addToast: () => {}, toasts: [], }); export const useJenga = () => useContext(ToastContext); export function JengaProvider({ children }: { children: ReactNode }) { const [toasts, setToasts] = useState([]); useEffect(() => { if (toasts.length === 0) return; const interval = setInterval(() => { setToasts(currentToasts => currentToasts .map(toast => ({ ...toast, countdown: (toast.countdown ?? 0) > 0 ? (toast.countdown ?? 0) - 1 : 0, })) .filter(toast => (toast.countdown ?? 0) > 0) ); }, 1000); return () => clearInterval(interval); }, [toasts.length]); const addToast = ({ theme, status, title, description, countdown = 3 }: Omit) => { const newToast = { id: Math.random().toString(36).substr(2, 9), theme, status, title, description, countdown, }; setToasts(prevToasts => [...prevToasts, newToast]); }; return ( {children} {toasts.length > 0 && (
{toasts.map(toast => (
))}
)}
); } // // toast function ToastSnackBar({ theme = 'light', status = 'success', id, title, description, closeTime, }: { theme?: 'light' | 'dark'; status?: 'success' | 'failed' | null | undefined; id: string; title: string; description?: string; closeTime?: number; }) { const fadeIn = keyframes` from { opacity: 0; } to { opacity: 1; } `; const fadeOut = keyframes` from { opacity: 1; } to { opacity: 0; } `; const THEME_VARIANT = { light: { bg: '#fff', title: '#555', sub: '#888' }, dark: { bg: '#222', title: '#e2e2e2', sub: '#999' }, }; return (
{status === 'success' && ( )} {status === 'failed' && ( )}

{title}

{description && (

{description}

)}
); }