Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

407 строки
14 KiB

  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.MotionPropTypes = undefined;
  6. var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
  7. var _defineProperty3 = _interopRequireDefault(_defineProperty2);
  8. var _extends2 = require('babel-runtime/helpers/extends');
  9. var _extends3 = _interopRequireDefault(_extends2);
  10. var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
  11. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  12. var _createClass2 = require('babel-runtime/helpers/createClass');
  13. var _createClass3 = _interopRequireDefault(_createClass2);
  14. var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
  15. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  16. var _inherits2 = require('babel-runtime/helpers/inherits');
  17. var _inherits3 = _interopRequireDefault(_inherits2);
  18. exports.genCSSMotion = genCSSMotion;
  19. var _react = require('react');
  20. var _react2 = _interopRequireDefault(_react);
  21. var _propTypes = require('prop-types');
  22. var _propTypes2 = _interopRequireDefault(_propTypes);
  23. var _reactLifecyclesCompat = require('react-lifecycles-compat');
  24. var _findDOMNode = require('rc-util/lib/Dom/findDOMNode');
  25. var _findDOMNode2 = _interopRequireDefault(_findDOMNode);
  26. var _classnames = require('classnames');
  27. var _classnames2 = _interopRequireDefault(_classnames);
  28. var _raf = require('raf');
  29. var _raf2 = _interopRequireDefault(_raf);
  30. var _motion = require('./util/motion');
  31. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  32. var STATUS_NONE = 'none'; /* eslint-disable react/default-props-match-prop-types, react/no-multi-comp */
  33. var STATUS_APPEAR = 'appear';
  34. var STATUS_ENTER = 'enter';
  35. var STATUS_LEAVE = 'leave';
  36. var MotionPropTypes = exports.MotionPropTypes = {
  37. eventProps: _propTypes2['default'].object, // Internal usage. Only pass by CSSMotionList
  38. visible: _propTypes2['default'].bool,
  39. children: _propTypes2['default'].func,
  40. motionName: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].object]),
  41. motionAppear: _propTypes2['default'].bool,
  42. motionEnter: _propTypes2['default'].bool,
  43. motionLeave: _propTypes2['default'].bool,
  44. motionLeaveImmediately: _propTypes2['default'].bool, // Trigger leave motion immediately
  45. motionDeadline: _propTypes2['default'].number,
  46. removeOnLeave: _propTypes2['default'].bool,
  47. leavedClassName: _propTypes2['default'].string,
  48. onAppearStart: _propTypes2['default'].func,
  49. onAppearActive: _propTypes2['default'].func,
  50. onAppearEnd: _propTypes2['default'].func,
  51. onEnterStart: _propTypes2['default'].func,
  52. onEnterActive: _propTypes2['default'].func,
  53. onEnterEnd: _propTypes2['default'].func,
  54. onLeaveStart: _propTypes2['default'].func,
  55. onLeaveActive: _propTypes2['default'].func,
  56. onLeaveEnd: _propTypes2['default'].func
  57. };
  58. /**
  59. * `transitionSupport` is used for none transition test case.
  60. * Default we use browser transition event support check.
  61. */
  62. function genCSSMotion(config) {
  63. var transitionSupport = config;
  64. var forwardRef = !!_react2['default'].forwardRef;
  65. if (typeof config === 'object') {
  66. transitionSupport = config.transitionSupport;
  67. forwardRef = 'forwardRef' in config ? config.forwardRef : forwardRef;
  68. }
  69. function isSupportTransition(props) {
  70. return !!(props.motionName && transitionSupport);
  71. }
  72. var CSSMotion = function (_React$Component) {
  73. (0, _inherits3['default'])(CSSMotion, _React$Component);
  74. function CSSMotion() {
  75. (0, _classCallCheck3['default'])(this, CSSMotion);
  76. var _this = (0, _possibleConstructorReturn3['default'])(this, (CSSMotion.__proto__ || Object.getPrototypeOf(CSSMotion)).call(this));
  77. _this.onDomUpdate = function () {
  78. var _this$state = _this.state,
  79. status = _this$state.status,
  80. newStatus = _this$state.newStatus;
  81. var _this$props = _this.props,
  82. onAppearStart = _this$props.onAppearStart,
  83. onEnterStart = _this$props.onEnterStart,
  84. onLeaveStart = _this$props.onLeaveStart,
  85. onAppearActive = _this$props.onAppearActive,
  86. onEnterActive = _this$props.onEnterActive,
  87. onLeaveActive = _this$props.onLeaveActive,
  88. motionAppear = _this$props.motionAppear,
  89. motionEnter = _this$props.motionEnter,
  90. motionLeave = _this$props.motionLeave;
  91. if (!isSupportTransition(_this.props)) {
  92. return;
  93. }
  94. // Event injection
  95. var $ele = _this.getElement();
  96. if (_this.$cacheEle !== $ele) {
  97. _this.removeEventListener(_this.$cacheEle);
  98. _this.addEventListener($ele);
  99. _this.$cacheEle = $ele;
  100. }
  101. // Init status
  102. if (newStatus && status === STATUS_APPEAR && motionAppear) {
  103. _this.updateStatus(onAppearStart, null, null, function () {
  104. _this.updateActiveStatus(onAppearActive, STATUS_APPEAR);
  105. });
  106. } else if (newStatus && status === STATUS_ENTER && motionEnter) {
  107. _this.updateStatus(onEnterStart, null, null, function () {
  108. _this.updateActiveStatus(onEnterActive, STATUS_ENTER);
  109. });
  110. } else if (newStatus && status === STATUS_LEAVE && motionLeave) {
  111. _this.updateStatus(onLeaveStart, null, null, function () {
  112. _this.updateActiveStatus(onLeaveActive, STATUS_LEAVE);
  113. });
  114. }
  115. };
  116. _this.onMotionEnd = function (event) {
  117. var _this$state2 = _this.state,
  118. status = _this$state2.status,
  119. statusActive = _this$state2.statusActive;
  120. var _this$props2 = _this.props,
  121. onAppearEnd = _this$props2.onAppearEnd,
  122. onEnterEnd = _this$props2.onEnterEnd,
  123. onLeaveEnd = _this$props2.onLeaveEnd;
  124. if (status === STATUS_APPEAR && statusActive) {
  125. _this.updateStatus(onAppearEnd, { status: STATUS_NONE }, event);
  126. } else if (status === STATUS_ENTER && statusActive) {
  127. _this.updateStatus(onEnterEnd, { status: STATUS_NONE }, event);
  128. } else if (status === STATUS_LEAVE && statusActive) {
  129. _this.updateStatus(onLeaveEnd, { status: STATUS_NONE }, event);
  130. }
  131. };
  132. _this.setNodeRef = function (node) {
  133. var internalRef = _this.props.internalRef;
  134. _this.node = node;
  135. if (typeof internalRef === 'function') {
  136. internalRef(node);
  137. } else if (internalRef && 'current' in internalRef) {
  138. internalRef.current = node;
  139. }
  140. };
  141. _this.getElement = function () {
  142. try {
  143. return (0, _findDOMNode2['default'])(_this.node || _this);
  144. } catch (e) {
  145. /**
  146. * Fallback to cache element.
  147. * This is only happen when `motionDeadline` trigger but element removed.
  148. */
  149. return _this.$cacheEle;
  150. }
  151. };
  152. _this.addEventListener = function ($ele) {
  153. if (!$ele) return;
  154. $ele.addEventListener(_motion.transitionEndName, _this.onMotionEnd);
  155. $ele.addEventListener(_motion.animationEndName, _this.onMotionEnd);
  156. };
  157. _this.removeEventListener = function ($ele) {
  158. if (!$ele) return;
  159. $ele.removeEventListener(_motion.transitionEndName, _this.onMotionEnd);
  160. $ele.removeEventListener(_motion.animationEndName, _this.onMotionEnd);
  161. };
  162. _this.updateStatus = function (styleFunc, additionalState, event, callback) {
  163. var statusStyle = styleFunc ? styleFunc(_this.getElement(), event) : null;
  164. if (statusStyle === false || _this._destroyed) return;
  165. var nextStep = void 0;
  166. if (callback) {
  167. nextStep = function nextStep() {
  168. _this.nextFrame(callback);
  169. };
  170. }
  171. _this.setState((0, _extends3['default'])({
  172. statusStyle: typeof statusStyle === 'object' ? statusStyle : null,
  173. newStatus: false
  174. }, additionalState), nextStep); // Trigger before next frame & after `componentDidMount`
  175. };
  176. _this.updateActiveStatus = function (styleFunc, currentStatus) {
  177. // `setState` use `postMessage` to trigger at the end of frame.
  178. // Let's use requestAnimationFrame to update new state in next frame.
  179. _this.nextFrame(function () {
  180. var status = _this.state.status;
  181. if (status !== currentStatus) return;
  182. var motionDeadline = _this.props.motionDeadline;
  183. _this.updateStatus(styleFunc, { statusActive: true });
  184. if (motionDeadline > 0) {
  185. setTimeout(function () {
  186. _this.onMotionEnd({
  187. deadline: true
  188. });
  189. }, motionDeadline);
  190. }
  191. });
  192. };
  193. _this.nextFrame = function (func) {
  194. _this.cancelNextFrame();
  195. _this.raf = (0, _raf2['default'])(func);
  196. };
  197. _this.cancelNextFrame = function () {
  198. if (_this.raf) {
  199. _raf2['default'].cancel(_this.raf);
  200. _this.raf = null;
  201. }
  202. };
  203. _this.state = {
  204. status: STATUS_NONE,
  205. statusActive: false,
  206. newStatus: false,
  207. statusStyle: null
  208. };
  209. _this.$cacheEle = null;
  210. _this.node = null;
  211. _this.raf = null;
  212. return _this;
  213. }
  214. (0, _createClass3['default'])(CSSMotion, [{
  215. key: 'componentDidMount',
  216. value: function componentDidMount() {
  217. this.onDomUpdate();
  218. }
  219. }, {
  220. key: 'componentDidUpdate',
  221. value: function componentDidUpdate() {
  222. this.onDomUpdate();
  223. }
  224. }, {
  225. key: 'componentWillUnmount',
  226. value: function componentWillUnmount() {
  227. this._destroyed = true;
  228. this.removeEventListener(this.$cacheEle);
  229. this.cancelNextFrame();
  230. }
  231. }, {
  232. key: 'render',
  233. value: function render() {
  234. var _classNames;
  235. var _state = this.state,
  236. status = _state.status,
  237. statusActive = _state.statusActive,
  238. statusStyle = _state.statusStyle;
  239. var _props = this.props,
  240. children = _props.children,
  241. motionName = _props.motionName,
  242. visible = _props.visible,
  243. removeOnLeave = _props.removeOnLeave,
  244. leavedClassName = _props.leavedClassName,
  245. eventProps = _props.eventProps;
  246. if (!children) return null;
  247. if (status === STATUS_NONE || !isSupportTransition(this.props)) {
  248. if (visible) {
  249. return children((0, _extends3['default'])({}, eventProps), this.setNodeRef);
  250. } else if (!removeOnLeave) {
  251. return children((0, _extends3['default'])({}, eventProps, { className: leavedClassName }), this.setNodeRef);
  252. }
  253. return null;
  254. }
  255. return children((0, _extends3['default'])({}, eventProps, {
  256. className: (0, _classnames2['default'])((_classNames = {}, (0, _defineProperty3['default'])(_classNames, (0, _motion.getTransitionName)(motionName, status), status !== STATUS_NONE), (0, _defineProperty3['default'])(_classNames, (0, _motion.getTransitionName)(motionName, status + '-active'), status !== STATUS_NONE && statusActive), (0, _defineProperty3['default'])(_classNames, motionName, typeof motionName === 'string'), _classNames)),
  257. style: statusStyle
  258. }), this.setNodeRef);
  259. }
  260. }], [{
  261. key: 'getDerivedStateFromProps',
  262. value: function getDerivedStateFromProps(props, _ref) {
  263. var prevProps = _ref.prevProps,
  264. prevStatus = _ref.status;
  265. if (!isSupportTransition(props)) return {};
  266. var visible = props.visible,
  267. motionAppear = props.motionAppear,
  268. motionEnter = props.motionEnter,
  269. motionLeave = props.motionLeave,
  270. motionLeaveImmediately = props.motionLeaveImmediately;
  271. var newState = {
  272. prevProps: props
  273. };
  274. // Clean up status if prop set to false
  275. if (prevStatus === STATUS_APPEAR && !motionAppear || prevStatus === STATUS_ENTER && !motionEnter || prevStatus === STATUS_LEAVE && !motionLeave) {
  276. newState.status = STATUS_NONE;
  277. newState.statusActive = false;
  278. newState.newStatus = false;
  279. }
  280. // Appear
  281. if (!prevProps && visible && motionAppear) {
  282. newState.status = STATUS_APPEAR;
  283. newState.statusActive = false;
  284. newState.newStatus = true;
  285. }
  286. // Enter
  287. if (prevProps && !prevProps.visible && visible && motionEnter) {
  288. newState.status = STATUS_ENTER;
  289. newState.statusActive = false;
  290. newState.newStatus = true;
  291. }
  292. // Leave
  293. if (prevProps && prevProps.visible && !visible && motionLeave || !prevProps && motionLeaveImmediately && !visible && motionLeave) {
  294. newState.status = STATUS_LEAVE;
  295. newState.statusActive = false;
  296. newState.newStatus = true;
  297. }
  298. return newState;
  299. }
  300. }]);
  301. return CSSMotion;
  302. }(_react2['default'].Component);
  303. CSSMotion.propTypes = (0, _extends3['default'])({}, MotionPropTypes, {
  304. internalRef: _propTypes2['default'].oneOfType([_propTypes2['default'].object, _propTypes2['default'].func])
  305. });
  306. CSSMotion.defaultProps = {
  307. visible: true,
  308. motionEnter: true,
  309. motionAppear: true,
  310. motionLeave: true,
  311. removeOnLeave: true
  312. };
  313. (0, _reactLifecyclesCompat.polyfill)(CSSMotion);
  314. if (!forwardRef) {
  315. return CSSMotion;
  316. }
  317. return _react2['default'].forwardRef(function (props, ref) {
  318. return _react2['default'].createElement(CSSMotion, (0, _extends3['default'])({ internalRef: ref }, props));
  319. });
  320. }
  321. exports['default'] = genCSSMotion(_motion.supportTransition);