UNPKG

@mui/x-charts

Version:

The community edition of MUI X Charts components.

76 lines (72 loc) 2.77 kB
'use client'; import * as React from 'react'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import { ANIMATION_DURATION_MS, ANIMATION_TIMING_FUNCTION_JS } from "./animation.js"; import { Transition } from "./Transition.js"; import { shallowEqual } from "../shallowEqual.js"; /** Animates a ref. The animation can be skipped by setting {@link skip} to true. * * If possible, prefer {@link useAnimate}. * * - If {@link skip} is false, a transition will be started. * - If {@link skip} is true and no transition is in progress, no transition will be started and {@link applyProps} will * never be called. * - If {@link skip} becomes true and a transition is in progress, the transition will immediately end and * {@link applyProps} be called with the final value. * */ export function useAnimateInternal(props, { createInterpolator, applyProps, skip, initialProps = props }) { const lastInterpolatedPropsRef = React.useRef(initialProps); const transitionRef = React.useRef(null); const elementRef = React.useRef(null); const lastPropsRef = React.useRef(props); useEnhancedEffect(() => { lastPropsRef.current = props; }, [props]); useEnhancedEffect(() => { if (skip) { transitionRef.current?.finish(); transitionRef.current = null; elementRef.current = null; lastInterpolatedPropsRef.current = props; } }, [props, skip]); const animate = React.useCallback(element => { const lastInterpolatedProps = lastInterpolatedPropsRef.current; const interpolate = createInterpolator(lastInterpolatedProps, props); transitionRef.current = new Transition(ANIMATION_DURATION_MS, ANIMATION_TIMING_FUNCTION_JS, t => { const interpolatedProps = interpolate(t); lastInterpolatedPropsRef.current = interpolatedProps; applyProps(element, interpolatedProps); }); }, [applyProps, createInterpolator, props]); const setRef = React.useCallback(element => { if (element === null) { transitionRef.current?.stop(); return; } const lastElement = elementRef.current; if (lastElement === element) { // If it's the same element and same props, resume the transition. if (shallowEqual(lastPropsRef.current, props)) { transitionRef.current?.resume(); return; } // If props aren't the same, stop the transition and start a new animation. transitionRef.current?.stop(); } // If it's a different element, stop the transition of the last element and start a new animation. if (lastElement) { transitionRef.current?.stop(); } elementRef.current = element; if (transitionRef.current || !skip) { animate(element); } }, [animate, props, skip]); return setRef; }