index.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. }) => ReactNode
  16. animationState: "enter" | "leave"
  17. onAnimationEnd?: () => void;
  18. onAnimationStart?: () => void;
  19. }
  20. interface AnimationState {
  21. currentClassName: string
  22. extraStyle: CSSProperties
  23. }
  24. class CSSAnimation extends React.Component<AnimationProps, AnimationState> {
  25. constructor(props) {
  26. super(props);
  27. this.state = {
  28. currentClassName: this.props.startClassName,
  29. extraStyle: {}
  30. };
  31. }
  32. componentDidUpdate(prevProps: Readonly<AnimationProps>, prevState: Readonly<AnimationState>, snapshot?: any) {
  33. const changedKeys = Object.keys(this.props).filter(key => !isEqual(this.props[key], prevProps[key]));
  34. if (changedKeys.includes("animationState")) {
  35. }
  36. if (changedKeys.includes("startClassName")) {
  37. this.setState({
  38. currentClassName: this.props.startClassName,
  39. extraStyle: {}
  40. }, this.props.onAnimationStart ?? noop);
  41. }
  42. }
  43. handleAnimationStart = () => {
  44. this.props.onAnimationStart?.();
  45. }
  46. handleAnimationEnd = () => {
  47. this.setState({
  48. currentClassName: this.props.endClassName,
  49. extraStyle: {}
  50. }, () => {
  51. this.props.onAnimationEnd?.();
  52. });
  53. }
  54. render() {
  55. return this.props.children({
  56. animationClassName: this.state.currentClassName ?? "",
  57. animationStyle: this.state.extraStyle,
  58. animationEventsNeedBind: {
  59. onAnimationStart: this.handleAnimationStart,
  60. onAnimationEnd: this.handleAnimationEnd
  61. }
  62. });
  63. }
  64. }
  65. const mergeAnimationFunction = (eventHandleFunctions: AnimationEventsNeedBind[]) => {
  66. //merge function in objects
  67. const mergedFunction = {};
  68. eventHandleFunctions.forEach(eventHandleFunction => {
  69. Object.keys(eventHandleFunction).forEach(key => {
  70. if (mergedFunction[key]) {
  71. const oldFunction = mergedFunction[key];
  72. mergedFunction[key] = (e) => {
  73. eventHandleFunction[key](e);
  74. oldFunction(e);
  75. };
  76. } else {
  77. mergedFunction[key] = eventHandleFunction[key];
  78. }
  79. });
  80. });
  81. return mergedFunction;
  82. };
  83. export { mergeAnimationFunction };
  84. export default CSSAnimation;