import type { ToastAction, ToastItem } from './types'; /** * Reducer for managing toast state * * Removal is a two-phase flow so web can play its CSS exit transition * before the DOM node is unmounted: * `MARK_CLOSED` → flips `pendingRemoval: true` (node stays mounted). * `REMOVE` → filters the toast out of the array (node unmounts). * * Native dispatches `REMOVE` directly since Reanimated's `exiting` * layout animation plays before unmount without a lingering state. */ export function toastReducer(state: ToastItem[], action: ToastAction): ToastItem[] { switch (action.type) { case 'SHOW': { const filtered = state.filter((toast) => toast.id !== action.payload.id); return [...filtered, action.payload]; } case 'MARK_CLOSED': { const idsSet = new Set(action.payload.ids); // Early out preserves the array reference when nothing would change, // which keeps `useMemo(..., [toasts])` consumers stable. const hasChange = state.some((toast) => idsSet.has(toast.id) && !toast.pendingRemoval); if (!hasChange) return state; return state.map((toast) => idsSet.has(toast.id) && !toast.pendingRemoval ? { ...toast, pendingRemoval: true } : toast, ); } case 'REMOVE': { const idsSet = new Set(action.payload.ids); return state.filter((toast) => !idsSet.has(toast.id)); } default: return state; } }