StyledTransition.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* eslint-disable eqeqeq */
  2. import React, { Component } from 'react';
  3. import PropTypes from 'prop-types';
  4. import StyledAnimation, { StyledAnimationProps, StyledAnimateStyleType } from './StyledAnimation';
  5. import noop from './utils/noop';
  6. export interface ChildFCType {
  7. animateCls?: string;
  8. animateStyle?: StyledAnimateStyleType;
  9. animateEvents?: (eventProps?: any) => void
  10. }
  11. export interface StyledTransitionProps extends StyledAnimationProps {
  12. state?: string | boolean;
  13. enter?: string;
  14. leave?: string;
  15. children?: React.ReactNode | ((TransitionProps: ChildFCType) => React.ReactNode | any);
  16. willEnter?: (value: any) => void;
  17. didEnter?: (value: any) => void;
  18. willLeave?: (value: any) => void;
  19. didLeave?: (value: any) => void;
  20. onStart?: (value: any) => void;
  21. onRest?: (value: any) => void
  22. }
  23. export interface StyledTransitionState {
  24. state: string | boolean;
  25. lastChildren: React.ReactNode | ((TransitionProps: ChildFCType) => React.ReactNode | any);
  26. currentChildren: React.ReactNode | ((TransitionProps: ChildFCType) => React.ReactNode | any)
  27. }
  28. export default class StyledTransition extends Component<StyledTransitionProps, StyledTransitionState> {
  29. static propTypes = {
  30. state: PropTypes.string,
  31. enter: PropTypes.string,
  32. leave: PropTypes.string,
  33. children: PropTypes.any,
  34. willEnter: PropTypes.func,
  35. didEnter: PropTypes.func,
  36. willLeave: PropTypes.func,
  37. didLeave: PropTypes.func,
  38. onStart: PropTypes.func,
  39. onRest: PropTypes.func,
  40. };
  41. static defaultProps = {
  42. willEnter: noop,
  43. didEnter: noop,
  44. willLeave: noop,
  45. didLeave: noop,
  46. onStart: noop,
  47. onRest: noop,
  48. };
  49. constructor(props = {}) {
  50. super(props);
  51. this.state = {
  52. state: '',
  53. lastChildren: null,
  54. currentChildren: null,
  55. };
  56. }
  57. static getDerivedStateFromProps(props: StyledTransitionProps, state: StyledTransitionState) {
  58. const willUpdateStates: Partial<StyledTransitionState> = {};
  59. if (props.children !== state.currentChildren) {
  60. willUpdateStates.lastChildren = state.currentChildren;
  61. willUpdateStates.currentChildren = props.children;
  62. if (props.children == null) {
  63. willUpdateStates.state = 'leave';
  64. } else {
  65. willUpdateStates.state = 'enter';
  66. }
  67. }
  68. if (props.state != null && props.state !== state.state) {
  69. willUpdateStates.state = props.state;
  70. }
  71. return willUpdateStates;
  72. }
  73. _isControlled = () => [true, false, 'enter', 'leave'].includes(this.props.state);
  74. onRest = (props: any) => {
  75. const { state } = this.state;
  76. if (state === 'enter') {
  77. this.props.didEnter(props);
  78. } else if (state === 'leave') {
  79. this.setState({ currentChildren: null, lastChildren: null });
  80. this.props.didLeave(props);
  81. }
  82. this.props.onRest(props);
  83. };
  84. onStart = (props: any) => {
  85. const { state } = this.state;
  86. if (state === 'enter') {
  87. this.props.willEnter(props);
  88. } else if (state === 'leave') {
  89. this.props.willLeave(props);
  90. }
  91. this.props.onStart(props);
  92. };
  93. render() {
  94. const { enter, leave, ...restProps } = this.props;
  95. const { currentChildren, lastChildren } = this.state;
  96. const isControlled = this._isControlled();
  97. let children, type;
  98. let { state } = this.state;
  99. if (isControlled) {
  100. children = this.props.children;
  101. state = this.props.state;
  102. } else if (currentChildren == null && lastChildren == null) {
  103. return null;
  104. }
  105. if (state === 'enter') {
  106. type = enter;
  107. if (!isControlled) {
  108. children = currentChildren;
  109. }
  110. } else if (state === 'leave') {
  111. type = leave;
  112. if (!isControlled) {
  113. children = lastChildren;
  114. }
  115. }
  116. return (
  117. <StyledAnimation {...restProps} type={type} onStart={this.onStart} onRest={this.onRest}>
  118. {children}
  119. </StyledAnimation>
  120. );
  121. }
  122. }