index.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React, {CSSProperties, ReactNode} from 'react';
  2. import {isEqual, noop} from "lodash";
  3. interface AnimationEventsNeedBind {
  4. onAnimationStart?: (e: React.AnimationEvent) => void
  5. onAnimationEnd?: (e: React.AnimationEvent) => void
  6. [key: string]: (e: any) => void;
  7. }
  8. interface AnimationProps {
  9. startClassName?: string;
  10. endClassName?: string;
  11. children: ({}: {
  12. animationClassName: string,
  13. animationStyle: CSSProperties,
  14. animationEventsNeedBind: AnimationEventsNeedBind,
  15. isAnimating: boolean
  16. }) => ReactNode
  17. animationState: "enter" | "leave"
  18. onAnimationEnd?: () => void;
  19. onAnimationStart?: () => void;
  20. motion?: boolean;
  21. replayKey?: string;
  22. }
  23. interface AnimationState {
  24. currentClassName: string
  25. extraStyle: CSSProperties,
  26. isAnimating: boolean
  27. }
  28. class CSSAnimation extends React.Component<AnimationProps, AnimationState> {
  29. static defaultProps = {
  30. motion: true,
  31. replayKey: "",
  32. }
  33. constructor(props) {
  34. super(props);
  35. this.state = {
  36. currentClassName: this.props.startClassName,
  37. extraStyle: {},
  38. isAnimating: true
  39. };
  40. }
  41. componentDidUpdate(prevProps: Readonly<AnimationProps>, prevState: Readonly<AnimationState>, snapshot?: any) {
  42. const changedKeys = Object.keys(this.props).filter(key => !isEqual(this.props[key], prevProps[key]));
  43. if (changedKeys.includes("animationState")) {
  44. }
  45. if (changedKeys.includes("startClassName") || changedKeys.includes('replayKey') || changedKeys.includes("motion")) {
  46. this.setState({
  47. currentClassName: this.props.startClassName,
  48. extraStyle: {},
  49. isAnimating: true
  50. }, () => {
  51. this.props.onAnimationStart?.();
  52. if (!this.props.motion) {
  53. this.props.onAnimationEnd?.();
  54. }
  55. });
  56. }
  57. }
  58. handleAnimationStart = () => {
  59. this.props.onAnimationStart?.();
  60. }
  61. handleAnimationEnd = () => {
  62. this.setState({
  63. currentClassName: this.props.endClassName,
  64. extraStyle: {},
  65. isAnimating: false
  66. }, () => {
  67. this.props.onAnimationEnd?.();
  68. });
  69. }
  70. render() {
  71. if (this.props.motion) {
  72. return this.props.children({
  73. animationClassName: this.state.currentClassName ?? "",
  74. animationStyle: this.state.extraStyle,
  75. animationEventsNeedBind: {
  76. onAnimationStart: this.handleAnimationStart,
  77. onAnimationEnd: this.handleAnimationEnd
  78. },
  79. isAnimating: this.state.isAnimating
  80. });
  81. } else {
  82. return this.props.children({
  83. animationClassName: "",
  84. animationStyle: {},
  85. animationEventsNeedBind: {},
  86. isAnimating: this.state.isAnimating
  87. })
  88. }
  89. }
  90. }
  91. // const mergeAnimationFunction = (eventHandleFunctions: AnimationEventsNeedBind[]) => {
  92. // //merge function in objects
  93. // const mergedFunction = {};
  94. // eventHandleFunctions.forEach(eventHandleFunction => {
  95. // Object.keys(eventHandleFunction).forEach(key => {
  96. // if (mergedFunction[key]) {
  97. // const oldFunction = mergedFunction[key];
  98. // mergedFunction[key] = (e) => {
  99. // eventHandleFunction[key](e);
  100. // oldFunction(e);
  101. // };
  102. // } else {
  103. // mergedFunction[key] = eventHandleFunction[key];
  104. // }
  105. // });
  106. // });
  107. // return mergedFunction;
  108. // };
  109. // export { mergeAnimationFunction };
  110. export default CSSAnimation;