import React, { useEffect, useState } from 'react'; import { useStyles } from '../../core/hooks/useStyles'; import { useTheme } from '../../core/theme/ThemeProvider'; import { ToastData } from './useToast'; import { Text } from '../Text/Text'; import { ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from '../../icons'; interface ToastProps { toast: ToastData; onDismiss: (id: string) => void; } const icons = { info: InfoIcon, success: SuccessIcon, warning: WarningIcon, error: ErrorIcon, }; export const Toast: React.FC = ({ toast, onDismiss }) => { const { theme } = useTheme(); const createStyle = useStyles('toast'); const [isVisible, setIsVisible] = useState(false); useEffect(() => { // Use requestAnimationFrame to ensure the component is mounted with initial styles // (opacity: 0, transform: translateX(20px)) before transitioning to the visible state. const showRaf = requestAnimationFrame(() => { setIsVisible(true); }); const hideTimer = setTimeout(() => { setIsVisible(false); }, toast.duration); const removeTimer = setTimeout(() => { onDismiss(toast.id); }, toast.duration! + 300); // Wait for fade out animation to complete return () => { cancelAnimationFrame(showRaf); clearTimeout(hideTimer); clearTimeout(removeTimer); }; }, [toast, onDismiss]); const variantColors = { info: theme.colors.primary, success: '#10b981', warning: theme.colors.accent, error: '#ef4444', }; const containerClass = createStyle({ backgroundColor: theme.colors.backgroundSecondary, borderRadius: '8px', border: `1px solid ${theme.colors.border}`, borderLeft: `5px solid ${variantColors[toast.variant!]}`, boxShadow: `0 8px 24px rgba(0,0,0,0.5)`, padding: '12px 16px', display: 'flex', alignItems: 'center', gap: theme.spacing.md, width: '360px', maxWidth: '90vw', '@supports (backdrop-filter: none) or (-webkit-backdrop-filter: none)': { backdropFilter: 'blur(16px)', }, }); const iconContainerClass = createStyle({ color: variantColors[toast.variant!], flexShrink: 0, width: '24px', height: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center', }); const IconComponent = icons[toast.variant!]; return (
{toast.title} {toast.description && {toast.description}}
); };