import { useCallback, useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; type ToastProps = { status: 'success' | 'error'; message: string; onDismiss: () => void; autoHideAfter?: number; }; const baseClasses = 'pointer-events-auto relative flex min-w-[360px] items-center gap-4 rounded-xl border border-slate-200 bg-white px-7 py-5 shadow-xl ring-1 ring-black/5 transform transition-all duration-300 ease-out overflow-hidden'; const statusVisuals: Record< ToastProps['status'], { accent: string; iconColor: string } > = { success: { accent: 'bg-emerald-500', iconColor: 'text-emerald-500', }, error: { accent: 'bg-rose-500', iconColor: 'text-rose-500', }, }; const closeClasses = 'absolute top-2 right-2 inline-flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-slate-500 text-xs transition hover:bg-slate-200 focus:outline-none focus:ring-2 focus:ring-slate-300'; const Toast = ( { status, message, onDismiss, autoHideAfter = 5000, }: ToastProps ) => { const [ isVisible, setIsVisible ] = useState( false ); const dismissTimer = useRef( null ); const hideTimer = useRef( null ); const enterTimer = useRef( null ); const clearTimers = useCallback( () => { if ( dismissTimer.current ) { window.clearTimeout( dismissTimer.current ); dismissTimer.current = null; } if ( hideTimer.current ) { window.clearTimeout( hideTimer.current ); hideTimer.current = null; } if ( enterTimer.current ) { window.clearTimeout( enterTimer.current ); enterTimer.current = null; } }, [] ); const startHideSequence = useCallback( () => { if ( dismissTimer.current ) { window.clearTimeout( dismissTimer.current ); dismissTimer.current = null; } setIsVisible( false ); if ( hideTimer.current ) { window.clearTimeout( hideTimer.current ); } hideTimer.current = window.setTimeout( () => { clearTimers(); onDismiss(); }, 220 ); }, [ clearTimers, onDismiss ] ); const scheduleDismissal = useCallback( ( delay: number ) => { if ( delay <= 0 ) { return; } if ( dismissTimer.current ) { window.clearTimeout( dismissTimer.current ); } dismissTimer.current = window.setTimeout( () => { startHideSequence(); }, delay ); }, [ startHideSequence ], ); const handleManualDismiss = () => { startHideSequence(); }; useEffect( () => { clearTimers(); setIsVisible( false ); enterTimer.current = window.setTimeout( () => { setIsVisible( true ); scheduleDismissal( autoHideAfter ); }, 20 ); return () => { setIsVisible( false ); clearTimers(); }; }, [ message, status, autoHideAfter, scheduleDismissal, clearTimers ] ); const animationClasses = isVisible ? 'translate-x-0 opacity-100' : 'translate-x-12 opacity-0'; return (
); }; export default Toast;