CSSTransition.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. "use strict";
  2. exports.__esModule = true;
  3. exports.default = void 0;
  4. var _propTypes = _interopRequireDefault(require("prop-types"));
  5. var _addClass2 = _interopRequireDefault(require("dom-helpers/addClass"));
  6. var _removeClass = _interopRequireDefault(require("dom-helpers/removeClass"));
  7. var _react = _interopRequireDefault(require("react"));
  8. var _Transition = _interopRequireDefault(require("./Transition"));
  9. var _PropTypes = require("./utils/PropTypes");
  10. var _reflow = require("./utils/reflow");
  11. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  12. function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
  13. function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
  14. function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
  15. var _addClass = function addClass(node, classes) {
  16. return node && classes && classes.split(' ').forEach(function (c) {
  17. return (0, _addClass2.default)(node, c);
  18. });
  19. };
  20. var removeClass = function removeClass(node, classes) {
  21. return node && classes && classes.split(' ').forEach(function (c) {
  22. return (0, _removeClass.default)(node, c);
  23. });
  24. };
  25. /**
  26. * A transition component inspired by the excellent
  27. * [ng-animate](https://docs.angularjs.org/api/ngAnimate) library, you should
  28. * use it if you're using CSS transitions or animations. It's built upon the
  29. * [`Transition`](https://reactcommunity.org/react-transition-group/transition)
  30. * component, so it inherits all of its props.
  31. *
  32. * `CSSTransition` applies a pair of class names during the `appear`, `enter`,
  33. * and `exit` states of the transition. The first class is applied and then a
  34. * second `*-active` class in order to activate the CSS transition. After the
  35. * transition, matching `*-done` class names are applied to persist the
  36. * transition state.
  37. *
  38. * ```jsx
  39. * function App() {
  40. * const [inProp, setInProp] = useState(false);
  41. * return (
  42. * <div>
  43. * <CSSTransition in={inProp} timeout={200} classNames="my-node">
  44. * <div>
  45. * {"I'll receive my-node-* classes"}
  46. * </div>
  47. * </CSSTransition>
  48. * <button type="button" onClick={() => setInProp(true)}>
  49. * Click to Enter
  50. * </button>
  51. * </div>
  52. * );
  53. * }
  54. * ```
  55. *
  56. * When the `in` prop is set to `true`, the child component will first receive
  57. * the class `example-enter`, then the `example-enter-active` will be added in
  58. * the next tick. `CSSTransition` [forces a
  59. * reflow](https://github.com/reactjs/react-transition-group/blob/5007303e729a74be66a21c3e2205e4916821524b/src/CSSTransition.js#L208-L215)
  60. * between before adding the `example-enter-active`. This is an important trick
  61. * because it allows us to transition between `example-enter` and
  62. * `example-enter-active` even though they were added immediately one after
  63. * another. Most notably, this is what makes it possible for us to animate
  64. * _appearance_.
  65. *
  66. * ```css
  67. * .my-node-enter {
  68. * opacity: 0;
  69. * }
  70. * .my-node-enter-active {
  71. * opacity: 1;
  72. * transition: opacity 200ms;
  73. * }
  74. * .my-node-exit {
  75. * opacity: 1;
  76. * }
  77. * .my-node-exit-active {
  78. * opacity: 0;
  79. * transition: opacity 200ms;
  80. * }
  81. * ```
  82. *
  83. * `*-active` classes represent which styles you want to animate **to**, so it's
  84. * important to add `transition` declaration only to them, otherwise transitions
  85. * might not behave as intended! This might not be obvious when the transitions
  86. * are symmetrical, i.e. when `*-enter-active` is the same as `*-exit`, like in
  87. * the example above (minus `transition`), but it becomes apparent in more
  88. * complex transitions.
  89. *
  90. * **Note**: If you're using the
  91. * [`appear`](http://reactcommunity.org/react-transition-group/transition#Transition-prop-appear)
  92. * prop, make sure to define styles for `.appear-*` classes as well.
  93. */
  94. var CSSTransition = /*#__PURE__*/function (_React$Component) {
  95. _inheritsLoose(CSSTransition, _React$Component);
  96. function CSSTransition() {
  97. var _this;
  98. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  99. args[_key] = arguments[_key];
  100. }
  101. _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
  102. _this.appliedClasses = {
  103. appear: {},
  104. enter: {},
  105. exit: {}
  106. };
  107. _this.onEnter = function (maybeNode, maybeAppearing) {
  108. var _this$resolveArgument = _this.resolveArguments(maybeNode, maybeAppearing),
  109. node = _this$resolveArgument[0],
  110. appearing = _this$resolveArgument[1];
  111. _this.removeClasses(node, 'exit');
  112. _this.addClass(node, appearing ? 'appear' : 'enter', 'base');
  113. if (_this.props.onEnter) {
  114. _this.props.onEnter(maybeNode, maybeAppearing);
  115. }
  116. };
  117. _this.onEntering = function (maybeNode, maybeAppearing) {
  118. var _this$resolveArgument2 = _this.resolveArguments(maybeNode, maybeAppearing),
  119. node = _this$resolveArgument2[0],
  120. appearing = _this$resolveArgument2[1];
  121. var type = appearing ? 'appear' : 'enter';
  122. _this.addClass(node, type, 'active');
  123. if (_this.props.onEntering) {
  124. _this.props.onEntering(maybeNode, maybeAppearing);
  125. }
  126. };
  127. _this.onEntered = function (maybeNode, maybeAppearing) {
  128. var _this$resolveArgument3 = _this.resolveArguments(maybeNode, maybeAppearing),
  129. node = _this$resolveArgument3[0],
  130. appearing = _this$resolveArgument3[1];
  131. var type = appearing ? 'appear' : 'enter';
  132. _this.removeClasses(node, type);
  133. _this.addClass(node, type, 'done');
  134. if (_this.props.onEntered) {
  135. _this.props.onEntered(maybeNode, maybeAppearing);
  136. }
  137. };
  138. _this.onExit = function (maybeNode) {
  139. var _this$resolveArgument4 = _this.resolveArguments(maybeNode),
  140. node = _this$resolveArgument4[0];
  141. _this.removeClasses(node, 'appear');
  142. _this.removeClasses(node, 'enter');
  143. _this.addClass(node, 'exit', 'base');
  144. if (_this.props.onExit) {
  145. _this.props.onExit(maybeNode);
  146. }
  147. };
  148. _this.onExiting = function (maybeNode) {
  149. var _this$resolveArgument5 = _this.resolveArguments(maybeNode),
  150. node = _this$resolveArgument5[0];
  151. _this.addClass(node, 'exit', 'active');
  152. if (_this.props.onExiting) {
  153. _this.props.onExiting(maybeNode);
  154. }
  155. };
  156. _this.onExited = function (maybeNode) {
  157. var _this$resolveArgument6 = _this.resolveArguments(maybeNode),
  158. node = _this$resolveArgument6[0];
  159. _this.removeClasses(node, 'exit');
  160. _this.addClass(node, 'exit', 'done');
  161. if (_this.props.onExited) {
  162. _this.props.onExited(maybeNode);
  163. }
  164. };
  165. _this.resolveArguments = function (maybeNode, maybeAppearing) {
  166. return _this.props.nodeRef ? [_this.props.nodeRef.current, maybeNode] // here `maybeNode` is actually `appearing`
  167. : [maybeNode, maybeAppearing];
  168. };
  169. _this.getClassNames = function (type) {
  170. var classNames = _this.props.classNames;
  171. var isStringClassNames = typeof classNames === 'string';
  172. var prefix = isStringClassNames && classNames ? classNames + "-" : '';
  173. var baseClassName = isStringClassNames ? "" + prefix + type : classNames[type];
  174. var activeClassName = isStringClassNames ? baseClassName + "-active" : classNames[type + "Active"];
  175. var doneClassName = isStringClassNames ? baseClassName + "-done" : classNames[type + "Done"];
  176. return {
  177. baseClassName: baseClassName,
  178. activeClassName: activeClassName,
  179. doneClassName: doneClassName
  180. };
  181. };
  182. return _this;
  183. }
  184. var _proto = CSSTransition.prototype;
  185. _proto.addClass = function addClass(node, type, phase) {
  186. var className = this.getClassNames(type)[phase + "ClassName"];
  187. var _this$getClassNames = this.getClassNames('enter'),
  188. doneClassName = _this$getClassNames.doneClassName;
  189. if (type === 'appear' && phase === 'done' && doneClassName) {
  190. className += " " + doneClassName;
  191. } // This is to force a repaint,
  192. // which is necessary in order to transition styles when adding a class name.
  193. if (phase === 'active') {
  194. if (node) (0, _reflow.forceReflow)(node);
  195. }
  196. if (className) {
  197. this.appliedClasses[type][phase] = className;
  198. _addClass(node, className);
  199. }
  200. };
  201. _proto.removeClasses = function removeClasses(node, type) {
  202. var _this$appliedClasses$ = this.appliedClasses[type],
  203. baseClassName = _this$appliedClasses$.base,
  204. activeClassName = _this$appliedClasses$.active,
  205. doneClassName = _this$appliedClasses$.done;
  206. this.appliedClasses[type] = {};
  207. if (baseClassName) {
  208. removeClass(node, baseClassName);
  209. }
  210. if (activeClassName) {
  211. removeClass(node, activeClassName);
  212. }
  213. if (doneClassName) {
  214. removeClass(node, doneClassName);
  215. }
  216. };
  217. _proto.render = function render() {
  218. var _this$props = this.props,
  219. _ = _this$props.classNames,
  220. props = _objectWithoutPropertiesLoose(_this$props, ["classNames"]);
  221. return /*#__PURE__*/_react.default.createElement(_Transition.default, _extends({}, props, {
  222. onEnter: this.onEnter,
  223. onEntered: this.onEntered,
  224. onEntering: this.onEntering,
  225. onExit: this.onExit,
  226. onExiting: this.onExiting,
  227. onExited: this.onExited
  228. }));
  229. };
  230. return CSSTransition;
  231. }(_react.default.Component);
  232. CSSTransition.defaultProps = {
  233. classNames: ''
  234. };
  235. CSSTransition.propTypes = process.env.NODE_ENV !== "production" ? _extends({}, _Transition.default.propTypes, {
  236. /**
  237. * The animation classNames applied to the component as it appears, enters,
  238. * exits or has finished the transition. A single name can be provided, which
  239. * will be suffixed for each stage, e.g. `classNames="fade"` applies:
  240. *
  241. * - `fade-appear`, `fade-appear-active`, `fade-appear-done`
  242. * - `fade-enter`, `fade-enter-active`, `fade-enter-done`
  243. * - `fade-exit`, `fade-exit-active`, `fade-exit-done`
  244. *
  245. * A few details to note about how these classes are applied:
  246. *
  247. * 1. They are _joined_ with the ones that are already defined on the child
  248. * component, so if you want to add some base styles, you can use
  249. * `className` without worrying that it will be overridden.
  250. *
  251. * 2. If the transition component mounts with `in={false}`, no classes are
  252. * applied yet. You might be expecting `*-exit-done`, but if you think
  253. * about it, a component cannot finish exiting if it hasn't entered yet.
  254. *
  255. * 2. `fade-appear-done` and `fade-enter-done` will _both_ be applied. This
  256. * allows you to define different behavior for when appearing is done and
  257. * when regular entering is done, using selectors like
  258. * `.fade-enter-done:not(.fade-appear-done)`. For example, you could apply
  259. * an epic entrance animation when element first appears in the DOM using
  260. * [Animate.css](https://daneden.github.io/animate.css/). Otherwise you can
  261. * simply use `fade-enter-done` for defining both cases.
  262. *
  263. * Each individual classNames can also be specified independently like:
  264. *
  265. * ```js
  266. * classNames={{
  267. * appear: 'my-appear',
  268. * appearActive: 'my-active-appear',
  269. * appearDone: 'my-done-appear',
  270. * enter: 'my-enter',
  271. * enterActive: 'my-active-enter',
  272. * enterDone: 'my-done-enter',
  273. * exit: 'my-exit',
  274. * exitActive: 'my-active-exit',
  275. * exitDone: 'my-done-exit',
  276. * }}
  277. * ```
  278. *
  279. * If you want to set these classes using CSS Modules:
  280. *
  281. * ```js
  282. * import styles from './styles.css';
  283. * ```
  284. *
  285. * you might want to use camelCase in your CSS file, that way could simply
  286. * spread them instead of listing them one by one:
  287. *
  288. * ```js
  289. * classNames={{ ...styles }}
  290. * ```
  291. *
  292. * @type {string | {
  293. * appear?: string,
  294. * appearActive?: string,
  295. * appearDone?: string,
  296. * enter?: string,
  297. * enterActive?: string,
  298. * enterDone?: string,
  299. * exit?: string,
  300. * exitActive?: string,
  301. * exitDone?: string,
  302. * }}
  303. */
  304. classNames: _PropTypes.classNamesShape,
  305. /**
  306. * A `<Transition>` callback fired immediately after the 'enter' or 'appear' class is
  307. * applied.
  308. *
  309. * **Note**: when `nodeRef` prop is passed, `node` is not passed.
  310. *
  311. * @type Function(node: HtmlElement, isAppearing: bool)
  312. */
  313. onEnter: _propTypes.default.func,
  314. /**
  315. * A `<Transition>` callback fired immediately after the 'enter-active' or
  316. * 'appear-active' class is applied.
  317. *
  318. * **Note**: when `nodeRef` prop is passed, `node` is not passed.
  319. *
  320. * @type Function(node: HtmlElement, isAppearing: bool)
  321. */
  322. onEntering: _propTypes.default.func,
  323. /**
  324. * A `<Transition>` callback fired immediately after the 'enter' or
  325. * 'appear' classes are **removed** and the `done` class is added to the DOM node.
  326. *
  327. * **Note**: when `nodeRef` prop is passed, `node` is not passed.
  328. *
  329. * @type Function(node: HtmlElement, isAppearing: bool)
  330. */
  331. onEntered: _propTypes.default.func,
  332. /**
  333. * A `<Transition>` callback fired immediately after the 'exit' class is
  334. * applied.
  335. *
  336. * **Note**: when `nodeRef` prop is passed, `node` is not passed
  337. *
  338. * @type Function(node: HtmlElement)
  339. */
  340. onExit: _propTypes.default.func,
  341. /**
  342. * A `<Transition>` callback fired immediately after the 'exit-active' is applied.
  343. *
  344. * **Note**: when `nodeRef` prop is passed, `node` is not passed
  345. *
  346. * @type Function(node: HtmlElement)
  347. */
  348. onExiting: _propTypes.default.func,
  349. /**
  350. * A `<Transition>` callback fired immediately after the 'exit' classes
  351. * are **removed** and the `exit-done` class is added to the DOM node.
  352. *
  353. * **Note**: when `nodeRef` prop is passed, `node` is not passed
  354. *
  355. * @type Function(node: HtmlElement)
  356. */
  357. onExited: _propTypes.default.func
  358. }) : {};
  359. var _default = CSSTransition;
  360. exports.default = _default;
  361. module.exports = exports.default;