SwitchTransition.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. "use strict";
  2. exports.__esModule = true;
  3. exports.default = exports.modes = void 0;
  4. var _react = _interopRequireDefault(require("react"));
  5. var _propTypes = _interopRequireDefault(require("prop-types"));
  6. var _Transition = require("./Transition");
  7. var _TransitionGroupContext = _interopRequireDefault(require("./TransitionGroupContext"));
  8. var _leaveRenders, _enterRenders;
  9. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  10. function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
  11. function areChildrenDifferent(oldChildren, newChildren) {
  12. if (oldChildren === newChildren) return false;
  13. if (_react.default.isValidElement(oldChildren) && _react.default.isValidElement(newChildren) && oldChildren.key != null && oldChildren.key === newChildren.key) {
  14. return false;
  15. }
  16. return true;
  17. }
  18. /**
  19. * Enum of modes for SwitchTransition component
  20. * @enum { string }
  21. */
  22. var modes = {
  23. out: 'out-in',
  24. in: 'in-out'
  25. };
  26. exports.modes = modes;
  27. var callHook = function callHook(element, name, cb) {
  28. return function () {
  29. var _element$props;
  30. element.props[name] && (_element$props = element.props)[name].apply(_element$props, arguments);
  31. cb();
  32. };
  33. };
  34. var leaveRenders = (_leaveRenders = {}, _leaveRenders[modes.out] = function (_ref) {
  35. var current = _ref.current,
  36. changeState = _ref.changeState;
  37. return _react.default.cloneElement(current, {
  38. in: false,
  39. onExited: callHook(current, 'onExited', function () {
  40. changeState(_Transition.ENTERING, null);
  41. })
  42. });
  43. }, _leaveRenders[modes.in] = function (_ref2) {
  44. var current = _ref2.current,
  45. changeState = _ref2.changeState,
  46. children = _ref2.children;
  47. return [current, _react.default.cloneElement(children, {
  48. in: true,
  49. onEntered: callHook(children, 'onEntered', function () {
  50. changeState(_Transition.ENTERING);
  51. })
  52. })];
  53. }, _leaveRenders);
  54. var enterRenders = (_enterRenders = {}, _enterRenders[modes.out] = function (_ref3) {
  55. var children = _ref3.children,
  56. changeState = _ref3.changeState;
  57. return _react.default.cloneElement(children, {
  58. in: true,
  59. onEntered: callHook(children, 'onEntered', function () {
  60. changeState(_Transition.ENTERED, _react.default.cloneElement(children, {
  61. in: true
  62. }));
  63. })
  64. });
  65. }, _enterRenders[modes.in] = function (_ref4) {
  66. var current = _ref4.current,
  67. children = _ref4.children,
  68. changeState = _ref4.changeState;
  69. return [_react.default.cloneElement(current, {
  70. in: false,
  71. onExited: callHook(current, 'onExited', function () {
  72. changeState(_Transition.ENTERED, _react.default.cloneElement(children, {
  73. in: true
  74. }));
  75. })
  76. }), _react.default.cloneElement(children, {
  77. in: true
  78. })];
  79. }, _enterRenders);
  80. /**
  81. * A transition component inspired by the [vue transition modes](https://vuejs.org/v2/guide/transitions.html#Transition-Modes).
  82. * You can use it when you want to control the render between state transitions.
  83. * Based on the selected mode and the child's key which is the `Transition` or `CSSTransition` component, the `SwitchTransition` makes a consistent transition between them.
  84. *
  85. * If the `out-in` mode is selected, the `SwitchTransition` waits until the old child leaves and then inserts a new child.
  86. * If the `in-out` mode is selected, the `SwitchTransition` inserts a new child first, waits for the new child to enter and then removes the old child.
  87. *
  88. * **Note**: If you want the animation to happen simultaneously
  89. * (that is, to have the old child removed and a new child inserted **at the same time**),
  90. * you should use
  91. * [`TransitionGroup`](https://reactcommunity.org/react-transition-group/transition-group)
  92. * instead.
  93. *
  94. * ```jsx
  95. * function App() {
  96. * const [state, setState] = useState(false);
  97. * return (
  98. * <SwitchTransition>
  99. * <CSSTransition
  100. * key={state ? "Goodbye, world!" : "Hello, world!"}
  101. * addEndListener={(node, done) => node.addEventListener("transitionend", done, false)}
  102. * classNames='fade'
  103. * >
  104. * <button onClick={() => setState(state => !state)}>
  105. * {state ? "Goodbye, world!" : "Hello, world!"}
  106. * </button>
  107. * </CSSTransition>
  108. * </SwitchTransition>
  109. * );
  110. * }
  111. * ```
  112. *
  113. * ```css
  114. * .fade-enter{
  115. * opacity: 0;
  116. * }
  117. * .fade-exit{
  118. * opacity: 1;
  119. * }
  120. * .fade-enter-active{
  121. * opacity: 1;
  122. * }
  123. * .fade-exit-active{
  124. * opacity: 0;
  125. * }
  126. * .fade-enter-active,
  127. * .fade-exit-active{
  128. * transition: opacity 500ms;
  129. * }
  130. * ```
  131. */
  132. var SwitchTransition = /*#__PURE__*/function (_React$Component) {
  133. _inheritsLoose(SwitchTransition, _React$Component);
  134. function SwitchTransition() {
  135. var _this;
  136. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  137. args[_key] = arguments[_key];
  138. }
  139. _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
  140. _this.state = {
  141. status: _Transition.ENTERED,
  142. current: null
  143. };
  144. _this.appeared = false;
  145. _this.changeState = function (status, current) {
  146. if (current === void 0) {
  147. current = _this.state.current;
  148. }
  149. _this.setState({
  150. status: status,
  151. current: current
  152. });
  153. };
  154. return _this;
  155. }
  156. var _proto = SwitchTransition.prototype;
  157. _proto.componentDidMount = function componentDidMount() {
  158. this.appeared = true;
  159. };
  160. SwitchTransition.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) {
  161. if (props.children == null) {
  162. return {
  163. current: null
  164. };
  165. }
  166. if (state.status === _Transition.ENTERING && props.mode === modes.in) {
  167. return {
  168. status: _Transition.ENTERING
  169. };
  170. }
  171. if (state.current && areChildrenDifferent(state.current, props.children)) {
  172. return {
  173. status: _Transition.EXITING
  174. };
  175. }
  176. return {
  177. current: _react.default.cloneElement(props.children, {
  178. in: true
  179. })
  180. };
  181. };
  182. _proto.render = function render() {
  183. var _this$props = this.props,
  184. children = _this$props.children,
  185. mode = _this$props.mode,
  186. _this$state = this.state,
  187. status = _this$state.status,
  188. current = _this$state.current;
  189. var data = {
  190. children: children,
  191. current: current,
  192. changeState: this.changeState,
  193. status: status
  194. };
  195. var component;
  196. switch (status) {
  197. case _Transition.ENTERING:
  198. component = enterRenders[mode](data);
  199. break;
  200. case _Transition.EXITING:
  201. component = leaveRenders[mode](data);
  202. break;
  203. case _Transition.ENTERED:
  204. component = current;
  205. }
  206. return /*#__PURE__*/_react.default.createElement(_TransitionGroupContext.default.Provider, {
  207. value: {
  208. isMounting: !this.appeared
  209. }
  210. }, component);
  211. };
  212. return SwitchTransition;
  213. }(_react.default.Component);
  214. SwitchTransition.propTypes = process.env.NODE_ENV !== "production" ? {
  215. /**
  216. * Transition modes.
  217. * `out-in`: Current element transitions out first, then when complete, the new element transitions in.
  218. * `in-out`: New element transitions in first, then when complete, the current element transitions out.
  219. *
  220. * @type {'out-in'|'in-out'}
  221. */
  222. mode: _propTypes.default.oneOf([modes.in, modes.out]),
  223. /**
  224. * Any `Transition` or `CSSTransition` component.
  225. */
  226. children: _propTypes.default.oneOfType([_propTypes.default.element.isRequired])
  227. } : {};
  228. SwitchTransition.defaultProps = {
  229. mode: modes.out
  230. };
  231. var _default = SwitchTransition;
  232. exports.default = _default;