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?: () => void; onAnimationStart?: () => void; motion?: boolean; replayKey?: string; } interface AnimationState { currentClassName: string extraStyle: CSSProperties, isAnimating: boolean } class CSSAnimation extends React.Component { static defaultProps = { motion: true, replayKey: "", } constructor(props) { super(props); this.state = { currentClassName: this.props.startClassName, extraStyle: {}, isAnimating: true }; } componentDidUpdate(prevProps: Readonly, prevState: Readonly, 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: {}, isAnimating: true }, () => { this.props.onAnimationStart?.(); if (!this.props.motion) { this.props.onAnimationEnd?.(); } }); } } handleAnimationStart = () => { this.props.onAnimationStart?.(); } handleAnimationEnd = () => { this.setState({ currentClassName: this.props.endClassName, extraStyle: {}, isAnimating: false }, () => { this.props.onAnimationEnd?.(); }); } 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;