import * as React from 'react' ; import { useTransition , animated , useReducedMotion } from '@twilio-paste/animation-library' ; import { useTheme } from '@twilio-paste/theme' ; import { Box } from '@twilio-paste/box' ; import { Toast } from './Toast' ; import { ToastPortal } from './ToastPortal' ; import { ToasterPropTypes } from './propTypes' ; import type { ToasterProps } from './types' ; export const AnimatedToast = animated ( Box ) ; interface ReturnTargetState { trigger : HTMLElement | null ; } const Toaster = ( { toasts , pop , ... props } ) => { const prefersReducedMotion = useReducedMotion ( ) ; const [ refMap ] = React . useState ( ( ) => new WeakMap ( ) ) ; const [ returnTarget , setReturnTarget ] = React . useState < ReturnTargetState > ( { trigger : null } ) ; const theme = useTheme ( ) ; const transitions = useTransition ( toasts , { from : { marginBottom : '0rem' , opacity : 0 , transform : 'translateX(100%) scale(1)' , height : prefersReducedMotion ? 'auto' : 0 , } , enter : prefersReducedMotion ? { marginBottom : theme . space . space40 , opacity : 1 , transform : 'translateX(0px) scale(1)' } : ( item ) => async ( next ) => { await next ( { marginBottom : theme . space . space40 , opacity : 1 , transform : 'translateX(0px) scale(1)' , height : refMap . get ( item ) . offsetHeight , } ) ; } , leave : { marginBottom : '0rem' , opacity : 0 , transform : 'translateX(0px) scale(0.8)' , height : prefersReducedMotion ? 'auto' : 0 , } , config : { mass : 1 , tension : 150 , friction : 20 , } , } ) ; const clearReturnTarget = React . useCallback ( ( ) => { setReturnTarget ( { trigger : null } ) ; } , [ returnTarget ] ) ; React . useEffect ( ( ) => { if ( returnTarget . trigger != null && toasts . length === 0 ) { returnTarget . trigger . focus ( ) ; clearReturnTarget ( ) ; } } , [ toasts ] ) ; return ( < ToastPortal { ... props } > { transitions ( ( styles , item , state , index ) => { return ( < AnimatedToast as = "div" key = { state . key } style = { styles as any } > < Toast key = { item . id } { ... item } onDismiss = { ( ) => { if ( item . onDismiss != null ) { item . onDismiss ( ) ; } pop ( item . id ) ; } } ref = { ( ref ) => { if ( ref != null ) { refMap . set ( item , ref ) ; } } } setFocus = { index === 0 } onFocus = { ( e ) => { if ( e . relatedTarget && ! returnTarget . trigger ) { setReturnTarget ( { trigger : e . relatedTarget as HTMLElement } ) ; } } } > { item . message } < /Toast> < /AnimatedToast>); } ) } < /ToastPortal>); } ; Toaster . displayName = 'Toaster' ; if ( process . env . NODE_ENV === 'development' ) { Toaster . propTypes = ToasterPropTypes ; } export { Toaster } ;