@patreon/studio
Version:
Patreon Studio Design System
123 lines (122 loc) • 5.67 kB
JavaScript
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