You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
53 lines
1.6 KiB
53 lines
1.6 KiB
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(false); |
|
|
|
useEffect(() => { |
|
if (isActive && !withEntryDelay) { |
|
setDelayedIsActive(true); |
|
|
|
return () => ''; |
|
} else { |
|
const timeout = setTimeout(() => { |
|
setDelayedIsActive(isActive); |
|
}, delayMs); |
|
|
|
return () => { |
|
clearTimeout(timeout); |
|
}; |
|
} |
|
}, [isActive, delayMs, withEntryDelay]); |
|
|
|
if (!isActive && !delayedIsActive) { |
|
return null; |
|
} |
|
|
|
return children(isActive && delayedIsActive); |
|
};
|
|
|