Untitled

 avatar
unknown
plain_text
a year ago
5.4 kB
6
Indexable
export type Player = {
    /// Plays the animation
    play: () => void;
    /// Sets the direction of play
    setDirection: (direction: "forward" | "reverse") => void;
    /// Pauses the animation
    pause: () => void;
    /// Stops animation playback
    stop: () => void;
};

export const useAnimation = () => {
    const lottieRef = useRef<Player | null>(null);

    const play = () => {
        lottieRef.current?.play();
    };

    const setDirection = (direction: "forward" | "reverse") => {
        console.log("setDirection in useAnimation");
        lottieRef.current?.setDirection(direction);
    };

    const pause = () => {
        lottieRef.current?.pause();
    };

    const stop = () => {
        lottieRef.current?.stop();
    };

    lottieRef.current = {
        pause,
        play,
        setDirection,
        stop,
    };

    return {
        control: lottieRef,
        pause,
        play,
        setDirection,
        stop,
    };
};

export const Animation = ({
    animateOnViewportEnter,
    aspectRatio,
    delay = 0,
    height = "auto",
    loop = false,
    maxHeight,
    maxWidth,
    name,
    width = "100%",
    control,
}: AnimationProps) => {
    const ref = useRef<HTMLDivElement | null>(null);
    const internalLottieRef = useRef<LottiePlayer | null>(null);

    const handleViewEnter = (inView: boolean) => {
        if (inView) {
            internalLottieRef.current?.play();
        }
    };

    useImperativeHandle(
        control,
        () => {
            return {
                pause: () => {
                    internalLottieRef.current?.pause();
                },
                play: () => {
                    internalLottieRef.current?.play();
                },
                setDirection: (direction: "forward" | "reverse") => {
                    console.log("setDirection in Animation");
                    internalLottieRef.current?.setDirection(direction === "forward" ? 1 : -1);
                },
                stop: () => {
                    internalLottieRef.current?.stop();
                },
            };
        },
        [],
    );

    useEffect(() => {
        const loadLottie = async () => {
            const { default: lottie } = await import(
                /* webpackChunkName: "lottie-web" */ "lottie-web/build/player/lottie_light"
            );

            lottie.setLocationHref(window.location.href);

            if (!ref.current) {
                return;
            }

            ref.current.innerHTML = "";
            internalLottieRef.current = lottie;

            const data = await import(`@ds/assets/animations/${name}.json`);

            internalLottieRef.current.loadAnimation({
                animationData: data,
                autoplay: false,
                container: ref.current,
                loop,
                renderer: "svg",
            });

            const play = () => internalLottieRef.current?.play();

            if (delay) {
                setTimeout(play, delay);
            }
            if (!animateOnViewportEnter && !control) {
                play();
            }
        };
        loadLottie();
    }, [animateOnViewportEnter, delay, control, loop, name]);

    const containerStyles: SxProps = {
        aspectRatio,
        maxHeight,
        maxWidth,
        svg: {
            height: `${typeof height === "number" ? `${height}px` : height} !important`,
            width: `${typeof width === "number" ? `${width}px` : width} !important`,
        },
    };

    const content = <Box aria-hidden={true} display="flex" ref={ref} sx={containerStyles} />;

    if (!animateOnViewportEnter) {
        return content;
    }

    return (
        <InView onChange={handleViewEnter} triggerOnce={true}>
            {content}
        </InView>
    );
};


export const Face = ({ name, onClick, children }: FaceProps) => {
    const { control, play, setDirection, pause } = useAnimation();

    const handleMouseEnter = () => {
        console.log("handleMouseEnter")   
        setDirection("forward");
        
        play();
    };

    const handleMouseLeave = () => {
        pause();
        setDirection("reverse");
        play();
    };

    const handleClick = () => {
        onClick?.();
    };

    return (
        <BoxRipple
            alignItems="center"
            display="flex"
            flexDirection="column"
            gap="space12"
            onClick={handleClick}
            onMouseEnter={handleMouseEnter}
            onMouseLeave={handleMouseLeave}
            width={56}
        >
                <Animation
                    control={control}
                    height={48}
                    name={`AnimationSurvey${name}HoverOn48x48`}
                    width={48}
                />
            <Text variant="standard-bold">{children}</Text>
        </BoxRipple>
    );
};


jak używam powyzszego komponentu Face, w ten sposób


to dostaje błąd
Uncaught RangeError: Maximum call stack size exceeded
    at Object.setDirection
i w konsoli widzę że "setDirection in useAnimation"
zostało wywołane kilka tysięcy razy, skąd ten błąd? bo z kolei "handleMouseEnter" zostało zalogowane raz 
Editor is loading...
Leave a Comment