| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | import React, { CSSProperties, ReactNode } from 'react';import { isEqual, noop } from "lodash";interface AnimationEventsNeedBind {    onAnimationStart?: (e: React.AnimationEvent) => void;    onAnimationEnd?: (e: React.AnimationEvent) => void;    [key: string]: (e: any) => void}interface AnimationProps {    startClassName?: string;    endClassName?: string;    children: ({ }: {        animationClassName: string;        animationStyle: CSSProperties;        animationEventsNeedBind: AnimationEventsNeedBind;        isAnimating: boolean    }) => ReactNode;    animationState: "enter" | "leave";    onAnimationEnd?: (stoppedByAnother: boolean) => void;    onAnimationStart?: () => void;    motion?: boolean;    replayKey?: string;    fillMode?: "backwards" | "both" | "forwards" | "none"}interface AnimationState {    currentClassName: string;    extraStyle: CSSProperties;    isAnimating: boolean}class CSSAnimation extends React.Component<AnimationProps, AnimationState> {    static defaultProps = {        motion: true,        replayKey: "",    }    constructor(props) {        super(props);        this.state = {            currentClassName: this.props.startClassName,            extraStyle: {                animationFillMode: this.props.fillMode,            },            isAnimating: true        };    }    componentDidMount() {        // The purpose is to shield the impact of the presence or absence of animation on the other semi component life cycle.        // In order to make the component side do not need to manually call the next life cycle function when there is no animation,        // so when there is no animation , it is logically (and only logically) regarded as an animation with a duration of 0.        this.props.onAnimationStart?.();        if (!this.props.motion) {            this.props.onAnimationEnd?.(false);            this.setState({ isAnimating: false });        }    }    componentDidUpdate(prevProps: Readonly<AnimationProps>, prevState: Readonly<AnimationState>, snapshot?: any) {        const changedKeys = Object.keys(this.props).filter(key => !isEqual(this.props[key], prevProps[key]));        if (changedKeys.includes("animationState")) {        }        if (changedKeys.includes("startClassName") || changedKeys.includes('replayKey') || changedKeys.includes("motion")) {            this.setState({                currentClassName: this.props.startClassName,                extraStyle: {                    animationFillMode: this.props.fillMode,                },                isAnimating: true            }, () => {                this.props.onAnimationStart?.();                if (!this.props.motion) {                    this.props.onAnimationEnd?.(this.state.isAnimating);                    this.setState({ isAnimating: false });                }            });        }    }    handleAnimationStart = () => {        this.props.onAnimationStart?.();    }    handleAnimationEnd = () => {        this.setState({            currentClassName: this.props.endClassName,            extraStyle: {                animationFillMode: this.props.fillMode,            },            isAnimating: false        }, () => {            this.props.onAnimationEnd?.(false);        });    }    render() {        if (this.props.motion) {            return this.props.children({                animationClassName: this.state.currentClassName ?? "",                animationStyle: this.state.extraStyle,                animationEventsNeedBind: {                    onAnimationStart: this.handleAnimationStart,                    onAnimationEnd: this.handleAnimationEnd                },                isAnimating: this.state.isAnimating            });        } else {            return this.props.children({                animationClassName: "",                animationStyle: {},                animationEventsNeedBind: {},                isAnimating: this.state.isAnimating            });        }    }}// const mergeAnimationFunction = (eventHandleFunctions: AnimationEventsNeedBind[]) => {//     //merge function in objects//     const mergedFunction = {};//     eventHandleFunctions.forEach(eventHandleFunction => {//         Object.keys(eventHandleFunction).forEach(key => {//             if (mergedFunction[key]) {//                 const oldFunction = mergedFunction[key];//                 mergedFunction[key] = (e) => {//                     eventHandleFunction[key](e);//                     oldFunction(e);//                 };//             } else {//                 mergedFunction[key] = eventHandleFunction[key];//             }//         });//     });//     return mergedFunction;// };// export { mergeAnimationFunction };export default CSSAnimation;
 |