diff --git a/packages/react-core/src/components/Backdrop/Backdrop.tsx b/packages/react-core/src/components/Backdrop/Backdrop.tsx index 3dea142179b..8d38edea35e 100644 --- a/packages/react-core/src/components/Backdrop/Backdrop.tsx +++ b/packages/react-core/src/components/Backdrop/Backdrop.tsx @@ -1,6 +1,5 @@ import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Backdrop/backdrop'; -import stylesAnimated from '@patternfly/react-styles/css/components/BackdropAnimations/backdrop-animations'; import { useHasAnimations } from '../../helpers'; export interface BackdropProps extends React.HTMLProps { @@ -28,9 +27,8 @@ export const Backdrop: React.FunctionComponent = ({ {...props} className={css( styles.backdrop, - hasAnimations && stylesAnimated.backdropAnimated, - hasAnimations && isVisible === true && stylesAnimated.backdropAnimatedVisible, - hasAnimations && isVisible !== true && stylesAnimated.backdropAnimatedHidden, + hasAnimations && styles.modifiers.animate, + hasAnimations && isVisible === true && styles.modifiers.show, className )} > diff --git a/packages/react-core/src/components/Modal/ModalBox.tsx b/packages/react-core/src/components/Modal/ModalBox.tsx index 17d8a0b3a8d..93c65932af1 100644 --- a/packages/react-core/src/components/Modal/ModalBox.tsx +++ b/packages/react-core/src/components/Modal/ModalBox.tsx @@ -1,6 +1,6 @@ import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/ModalBox/modal-box'; -import stylesAnimated from '@patternfly/react-styles/css/components/ModalAnimations/modal-animations'; +// import stylesAnimated from '@patternfly/react-styles/css/components/ModalAnimations/modal-animations'; import topSpacer from '@patternfly/react-tokens/dist/esm/c_modal_box_m_align_top_spacer'; export interface ModalBoxProps extends React.HTMLProps { @@ -53,9 +53,8 @@ export const ModalBox: React.FunctionComponent = ({ aria-modal="true" className={css( styles.modalBox, - hasAnimations && stylesAnimated.modalAnimated, - hasAnimations && isOpen === true && stylesAnimated.modalAnimatedOpen, - hasAnimations && isOpen !== true && stylesAnimated.modalAnimatedClosed, + hasAnimations && styles.modifiers.animate, + hasAnimations && isOpen === true && styles.modifiers.open, className, position === 'top' && styles.modifiers.alignTop, variant === 'large' && styles.modifiers.lg, diff --git a/packages/react-core/src/components/Modal/ModalContent.tsx b/packages/react-core/src/components/Modal/ModalContent.tsx index 499959b4ab9..bf38aa0dc0f 100644 --- a/packages/react-core/src/components/Modal/ModalContent.tsx +++ b/packages/react-core/src/components/Modal/ModalContent.tsx @@ -1,3 +1,4 @@ +import { useEffect, useState } from 'react'; import { FocusTrap } from '../../helpers'; import bullsEyeStyles from '@patternfly/react-styles/css/layouts/Bullseye/bullseye'; import { css } from '@patternfly/react-styles'; @@ -78,8 +79,20 @@ export const ModalContent: React.FunctionComponent = ({ ...props }: ModalContentProps) => { const hasAnimations = useHasAnimations(hasAnimationsProp); + // Keeps the modal in the DOM while the close animation runs. When animations are enabled we defer + // unmounting until the backdrop's transition ends (see onTransitionEnd below) instead of removing + // it immediately when isOpen becomes false. + const [isRendered, setIsRendered] = useState(isOpen); - if (!isOpen && !hasAnimations) { + useEffect(() => { + if (isOpen) { + setIsRendered(true); + } else if (!hasAnimations) { + setIsRendered(false); + } + }, [isOpen, hasAnimations]); + + if (!isRendered) { return null; } @@ -126,7 +139,23 @@ export const ModalContent: React.FunctionComponent = ({ } return ( - + { + // Only unmount once the backdrop's own closing transition finishes. Guarding on the + // target prevents bubbled transitions from child elements from triggering this early. + if (!isOpen && event.target === event.currentTarget) { + setIsRendered(false); + } + } + : undefined + } + >