diff --git a/packages/components/src/navigator/navigator-screen/component.tsx b/packages/components/src/navigator/navigator-screen/component.tsx index 6f681034a347e..6a089b466473d 100644 --- a/packages/components/src/navigator/navigator-screen/component.tsx +++ b/packages/components/src/navigator/navigator-screen/component.tsx @@ -42,6 +42,7 @@ function UnconnectedNavigatorScreen( forwardedRef: ForwardedRef< any > ) { const screenId = useId(); + const animationTimeoutRef = useRef< number >(); // Read props and components context. const { children, className, path, ...otherProps } = useContextSystem( @@ -131,6 +132,19 @@ function UnconnectedNavigatorScreen( isAnimatingOut, ] ); + // Fallback timeout to ensure the screen is removed from the DOM in case the + // `animationend` event is not triggered. + useEffect( () => { + if ( exitAnimationStatus === 'animating' ) { + animationTimeoutRef.current = window.setTimeout( () => { + setExitAnimationStatus( 'animated' ); + animationTimeoutRef.current = undefined; + }, styles.TOTAL_ANIMATION_DURATION_OUT ); + } else if ( animationTimeoutRef.current ) { + window.clearTimeout( animationTimeoutRef.current ); + animationTimeoutRef.current = undefined; + } + }, [ exitAnimationStatus ] ); // Focus restoration const locationRef = useRef( location ); diff --git a/packages/components/src/navigator/styles.ts b/packages/components/src/navigator/styles.ts index 648c4f38a0b67..679b43138ead1 100644 --- a/packages/components/src/navigator/styles.ts +++ b/packages/components/src/navigator/styles.ts @@ -57,37 +57,42 @@ type NavigatorScreenAnimationProps = { }; const FADE = { - DURATION: '70ms', + DURATION: 70, EASING: 'linear', DELAY: { - IN: '70ms', - OUT: '40ms', + IN: 70, + OUT: 40, }, }; const SLIDE = { - DURATION: '300ms', + DURATION: 300, EASING: 'cubic-bezier(0.33, 0, 0, 1)', }; +export const TOTAL_ANIMATION_DURATION_OUT = Math.max( + FADE.DURATION + FADE.DELAY.OUT, + SLIDE.DURATION +); + const ANIMATION = { forwards: { in: css` - ${ FADE.DURATION } ${ FADE.EASING } ${ FADE.DELAY - .IN } both ${ fadeIn }, ${ SLIDE.DURATION } ${ SLIDE.EASING } both ${ slideFromRight } + ${ FADE.DURATION }ms ${ FADE.EASING } ${ FADE.DELAY + .IN }ms both ${ fadeIn }, ${ SLIDE.DURATION }ms ${ SLIDE.EASING } both ${ slideFromRight } `, out: css` - ${ FADE.DURATION } ${ FADE.EASING } ${ FADE.DELAY - .IN } both ${ fadeOut }, ${ SLIDE.DURATION } ${ SLIDE.EASING } both ${ slideToLeft } + ${ FADE.DURATION }ms ${ FADE.EASING } ${ FADE.DELAY + .IN }ms both ${ fadeOut }, ${ SLIDE.DURATION }ms ${ SLIDE.EASING } both ${ slideToLeft } `, }, backwards: { in: css` - ${ FADE.DURATION } ${ FADE.EASING } ${ FADE.DELAY - .IN } both ${ fadeIn }, ${ SLIDE.DURATION } ${ SLIDE.EASING } both ${ slideFromLeft } + ${ FADE.DURATION }ms ${ FADE.EASING } ${ FADE.DELAY + .IN }ms both ${ fadeIn }, ${ SLIDE.DURATION }ms ${ SLIDE.EASING } both ${ slideFromLeft } `, out: css` - ${ FADE.DURATION } ${ FADE.EASING } ${ FADE.DELAY - .OUT } both ${ fadeOut }, ${ SLIDE.DURATION } ${ SLIDE.EASING } both ${ slideToRight } + ${ FADE.DURATION }ms ${ FADE.EASING } ${ FADE.DELAY + .OUT }ms both ${ fadeOut }, ${ SLIDE.DURATION }ms ${ SLIDE.EASING } both ${ slideToRight } `, }, };