UNPKG

@patreon/studio

Version:

Patreon Studio Design System

123 lines (122 loc) 5.67 kB
import { useEffect, useRef, useState } from 'react'; import { css } from 'styled-components'; /** * This hook is used to manage the transition phases of a component that is being mounted or unmounted, * and provides a way to animate the component during these transitions. * * @param isActive - A boolean flag that determines if the component is currently active or not, e.g. for a dialog whether it's open or closed. * @param animationDuration - The duration of the animation in milliseconds. * @param onAnimationComplete - A callback function that is called when the animation is complete. * * @returns An object with the following properties: * - isMounted: A boolean flag that determines if the component should be mounted * - transitionPhase: A flag that represents the current transition phase. * * @deprecated This hook is deprecated and will be removed in a future release. Use the `Overlay` family of components instead. */ export function useMountTransition({ isActive, animationDuration, onAnimationComplete }) { const [transitionPhase, setTransitionPhase] = useState('complete'); const [isMounted, setIsMounted] = useState(isActive); // here we store timer references and callbacks in refs so that they // can be accessed in the useEffect functions without dependencies const startedTimerRef = useRef(); const startedCallback = useRef(() => { setTransitionPhase('started'); }); const completeTimerRef = useRef(); const completeCallback = useRef(({ isActive: isCallbackOpen, onAnimationComplete: onCallbackAnimationComplete }) => { setTransitionPhase('complete'); // if the component is closing and the callback is complete, then we can unmount the component if (!isCallbackOpen) { setIsMounted(false); } onCallbackAnimationComplete(); }); // 1. kick off the transition when the isActive flag changes useEffect(() => { // when opening the component we want to immediately mount the component // so that we can setup the initial state of the transition if (isActive) { setTransitionPhase('setup'); setIsMounted(true); } // when closing the component we want to wait until the animation // is complete before unmounting the component. setup the transition phase here if (isMounted && !isActive) { setTransitionPhase('setup'); } }, [isMounted, isActive]); // 2. wait for setup to complete before starting the transition useEffect(() => { // we need to give setup a single tick to allow the browser to render the initial state // before starting the transition animation. this allows us to animate the component after // the initial render which may change the component's visibility. if (transitionPhase === 'setup') { const tick = () => startedCallback.current(); startedTimerRef.current = window.setTimeout(tick); return () => window.clearTimeout(startedTimerRef.current); } return undefined; }, [transitionPhase]); // 3. wait for the transition to complete before executing the complete callback useEffect(() => { // when the transition phase is started we should wait for the animation to complete // based on the animation duration before calling the complete callback if (transitionPhase === 'started') { const tick = () => completeCallback.current({ isActive, onAnimationComplete }); completeTimerRef.current = window.setTimeout(tick, animationDuration); return () => window.clearTimeout(completeTimerRef.current); } return undefined; }, [isActive, transitionPhase, onAnimationComplete, animationDuration]); return { isMounted, transitionPhase, }; } /** * The `mountTransition` function is used in conjunction with the `useMountTransition` hook to * generate the CSS for animating a component when it is mounted or unmounted. This function * should be used in a styled component to apply the transition styles. * @param isActive - A boolean flag that determines if the component is active * @param transitionPhase - A flag that represents the current transition phase. * @param transition - The CSS transition styles to apply to the component during animation. * @param mounted - The CSS styles to apply to the component when it is mounted. * @param unmounted - The CSS styles to apply to the component when it is unmounted. * * @returns The CSS styles to apply to the component during the transition. * * @deprecated This function is deprecated and will be removed in a future release. Use the `Overlay` family of components instead. */ export function cssForMountTransition({ isActive, transitionPhase, transition, mounted, unmounted, }) { // when the component is opening we want to immediately apply the unmounted styles // before transitioning to the mounted styles. when the component is closing we want // to immediately apply the mounted styles before transitioning to the unmounted styles. if (isActive) { if (transitionPhase === 'setup') { return css ` ${unmounted} `; } else { return css ` ${transition} ${mounted} `; } } else { if (transitionPhase === 'setup') { return css ` ${mounted} `; } else { return css ` ${transition} ${unmounted} `; } } } //# sourceMappingURL=index.js.map