import { useEffect, useRef } from 'react'; import useStableMemo from '@cleartrip/ct-design-use-stable-memo'; import { ContainerRef } from '@cleartrip/ct-design-container'; import { AnimatedStyleWithController, IAnimatedRef, IAnimationOptions } from '../type'; import AnimatedStyle from '../AnimatedStyle/AnimatedStyle'; import { AnimatedStyle as IWebAnimatedStyle } from '../AnimatedStyle/type'; import { makeAnimatedClassNames } from '../utils'; const getAnimatedValue = (animatedStyle: AnimatedStyleWithController[]) => { const firstAnimatedStyle = animatedStyle[0][0].getWebAnimatedStyle(); return firstAnimatedStyle; }; const getIsSpring = (animatedStyle: AnimatedStyleWithController[]) => { let isSpring = false; for (let i = 0; i < animatedStyle.length; i++) { if (animatedStyle[i][0].getWebIsSpring()) { isSpring = true; break; } } return isSpring; }; export const useAnimatedStylesInSequence = (animatedStyles: AnimatedStyleWithController[], deps: unknown[]) => { const { from, config: animatedConfig = {} } = getAnimatedValue(animatedStyles) ?? {}; const fromStylesRef = useRef(makeAnimatedClassNames(from, animatedConfig)[0]); const elementRef = useRef(null); const classListRef = useRef([fromStylesRef.current]); const sequenceIndexRef = useRef(0); const springRef = useRef(null); const setElementRef = (element: React.MutableRefObject) => { elementRef.current = element?.current ?? null; }; const styles = useStableMemo(() => { return new AnimatedStyle(animatedStyles, setElementRef, classListRef, springRef as React.RefObject); }, deps); const controller = { start(animatedStyle?: IAnimationOptions) { if (getIsSpring(animatedStyles)) { springRef.current?.start?.(animatedStyle); return; } animatedStyles[sequenceIndexRef.current][1].start?.(undefined, elementRef); }, }; const handleTransitionEnd = () => { sequenceIndexRef.current++; if (sequenceIndexRef.current < animatedStyles.length) { controller.start(); } }; useEffect(() => { if (animatedConfig?.immediate && sequenceIndexRef.current === 0) { controller.start(); } if (elementRef?.current) { elementRef.current?.addEventListener?.('transitionend', handleTransitionEnd); } return () => { if (elementRef?.current) { elementRef.current?.removeEventListener?.('transitionend', handleTransitionEnd); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return [styles, controller] as unknown as [IWebAnimatedStyle, typeof controller]; };