import { useEffect, useState } from 'react'; /** * A helper component for managing the rendering of components that * need to stay in the DOM a bit longer to finish their CSS exit animation. * * In the future, replace this component with plain CSS once that is feasible. * This will require broader support for `transition-behavior: allow-discrete` * and https://developer.mozilla.org/en-US/docs/Web/CSS/overlay. */ export const ExitAnimationWrapper: React.FC<{ /** * Set this to true to indicate that the nested component should be rendered */ isActive: boolean; /** * How long the component should be rendered after `isActive` was set to `false` */ delayMs?: number; /** * Set this to true to also delay the entry of the nested component until after * another one has exited full. */ withEntryDelay?: boolean; /** * Render prop that provides the nested component with the `delayedIsActive` flag */ children: (delayedIsActive: boolean) => React.ReactNode; }> = ({ isActive = false, delayMs = 500, withEntryDelay, children }) => { const [delayedIsActive, setDelayedIsActive] = useState( isActive && !withEntryDelay, ); useEffect(() => { const withDelay = !isActive || withEntryDelay; const timeout = setTimeout( () => { setDelayedIsActive(isActive); }, withDelay ? delayMs : 0, ); return () => { clearTimeout(timeout); }; }, [isActive, delayMs, withEntryDelay]); if (!isActive && !delayedIsActive) { return null; } return children(isActive && delayedIsActive); };