( ref: RefObject<HTMLElement | null>, isReady: boolean = true )
| 15 | import {useLayoutEffect} from './useLayoutEffect'; |
| 16 | |
| 17 | export function useEnterAnimation( |
| 18 | ref: RefObject<HTMLElement | null>, |
| 19 | isReady: boolean = true |
| 20 | ): boolean { |
| 21 | let [isEntering, setEntering] = useState(true); |
| 22 | let isAnimationReady = isEntering && isReady; |
| 23 | |
| 24 | // There are two cases for entry animations: |
| 25 | // 1. CSS @keyframes. The `animation` property is set during the isEntering state, and it is removed after the animation finishes. |
| 26 | // 2. CSS transitions. The initial styles are applied during the isEntering state, and removed immediately, causing the transition to occur. |
| 27 | // |
| 28 | // In the second case, cancel any transitions that were triggered prior to the isEntering = false state (when the transition is supposed to start). |
| 29 | // This can happen when isReady starts as false (e.g. popovers prior to placement calculation). |
| 30 | useLayoutEffect(() => { |
| 31 | if (isAnimationReady && ref.current && 'getAnimations' in ref.current) { |
| 32 | for (let animation of ref.current.getAnimations()) { |
| 33 | if (animation instanceof CSSTransition) { |
| 34 | animation.cancel(); |
| 35 | } |
| 36 | } |
| 37 | } |
| 38 | }, [ref, isAnimationReady]); |
| 39 | |
| 40 | useAnimation( |
| 41 | ref, |
| 42 | isAnimationReady, |
| 43 | useCallback(() => setEntering(false), []) |
| 44 | ); |
| 45 | return isAnimationReady; |
| 46 | } |
| 47 | |
| 48 | export function useExitAnimation(ref: RefObject<HTMLElement | null>, isOpen: boolean): boolean { |
| 49 | let [exitState, setExitState] = useState<'closed' | 'open' | 'exiting'>( |
no test coverage detected