useStatus.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _typeof = require("@babel/runtime/helpers/typeof");
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = useStatus;
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  10. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  11. var _rcUtil = require("rc-util");
  12. var _useState5 = _interopRequireDefault(require("rc-util/lib/hooks/useState"));
  13. var _useSyncState3 = _interopRequireDefault(require("rc-util/lib/hooks/useSyncState"));
  14. var _react = _interopRequireWildcard(require("react"));
  15. var React = _react;
  16. var _interface = require("../interface");
  17. var _useDomMotionEvents3 = _interopRequireDefault(require("./useDomMotionEvents"));
  18. var _useIsomorphicLayoutEffect = _interopRequireDefault(require("./useIsomorphicLayoutEffect"));
  19. var _useStepQueue3 = _interopRequireWildcard(require("./useStepQueue"));
  20. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
  21. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  22. function useStatus(supportMotion, visible, getElement, _ref) {
  23. var _ref$motionEnter = _ref.motionEnter,
  24. motionEnter = _ref$motionEnter === void 0 ? true : _ref$motionEnter,
  25. _ref$motionAppear = _ref.motionAppear,
  26. motionAppear = _ref$motionAppear === void 0 ? true : _ref$motionAppear,
  27. _ref$motionLeave = _ref.motionLeave,
  28. motionLeave = _ref$motionLeave === void 0 ? true : _ref$motionLeave,
  29. motionDeadline = _ref.motionDeadline,
  30. motionLeaveImmediately = _ref.motionLeaveImmediately,
  31. onAppearPrepare = _ref.onAppearPrepare,
  32. onEnterPrepare = _ref.onEnterPrepare,
  33. onLeavePrepare = _ref.onLeavePrepare,
  34. onAppearStart = _ref.onAppearStart,
  35. onEnterStart = _ref.onEnterStart,
  36. onLeaveStart = _ref.onLeaveStart,
  37. onAppearActive = _ref.onAppearActive,
  38. onEnterActive = _ref.onEnterActive,
  39. onLeaveActive = _ref.onLeaveActive,
  40. onAppearEnd = _ref.onAppearEnd,
  41. onEnterEnd = _ref.onEnterEnd,
  42. onLeaveEnd = _ref.onLeaveEnd,
  43. onVisibleChanged = _ref.onVisibleChanged;
  44. // Used for outer render usage to avoid `visible: false & status: none` to render nothing
  45. var _useState = (0, _useState5.default)(),
  46. _useState2 = (0, _slicedToArray2.default)(_useState, 2),
  47. asyncVisible = _useState2[0],
  48. setAsyncVisible = _useState2[1];
  49. var _useSyncState = (0, _useSyncState3.default)(_interface.STATUS_NONE),
  50. _useSyncState2 = (0, _slicedToArray2.default)(_useSyncState, 2),
  51. getStatus = _useSyncState2[0],
  52. setStatus = _useSyncState2[1];
  53. var _useState3 = (0, _useState5.default)(null),
  54. _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
  55. style = _useState4[0],
  56. setStyle = _useState4[1];
  57. var currentStatus = getStatus();
  58. var mountedRef = (0, _react.useRef)(false);
  59. var deadlineRef = (0, _react.useRef)(null);
  60. // =========================== Dom Node ===========================
  61. function getDomElement() {
  62. return getElement();
  63. }
  64. // ========================== Motion End ==========================
  65. var activeRef = (0, _react.useRef)(false);
  66. /**
  67. * Clean up status & style
  68. */
  69. function updateMotionEndStatus() {
  70. setStatus(_interface.STATUS_NONE);
  71. setStyle(null, true);
  72. }
  73. var onInternalMotionEnd = (0, _rcUtil.useEvent)(function (event) {
  74. var status = getStatus();
  75. // Do nothing since not in any transition status.
  76. // This may happen when `motionDeadline` trigger.
  77. if (status === _interface.STATUS_NONE) {
  78. return;
  79. }
  80. var element = getDomElement();
  81. if (event && !event.deadline && event.target !== element) {
  82. // event exists
  83. // not initiated by deadline
  84. // transitionEnd not fired by inner elements
  85. return;
  86. }
  87. var currentActive = activeRef.current;
  88. var canEnd;
  89. if (status === _interface.STATUS_APPEAR && currentActive) {
  90. canEnd = onAppearEnd === null || onAppearEnd === void 0 ? void 0 : onAppearEnd(element, event);
  91. } else if (status === _interface.STATUS_ENTER && currentActive) {
  92. canEnd = onEnterEnd === null || onEnterEnd === void 0 ? void 0 : onEnterEnd(element, event);
  93. } else if (status === _interface.STATUS_LEAVE && currentActive) {
  94. canEnd = onLeaveEnd === null || onLeaveEnd === void 0 ? void 0 : onLeaveEnd(element, event);
  95. }
  96. // Only update status when `canEnd` and not destroyed
  97. if (currentActive && canEnd !== false) {
  98. updateMotionEndStatus();
  99. }
  100. });
  101. var _useDomMotionEvents = (0, _useDomMotionEvents3.default)(onInternalMotionEnd),
  102. _useDomMotionEvents2 = (0, _slicedToArray2.default)(_useDomMotionEvents, 1),
  103. patchMotionEvents = _useDomMotionEvents2[0];
  104. // ============================= Step =============================
  105. var getEventHandlers = function getEventHandlers(targetStatus) {
  106. switch (targetStatus) {
  107. case _interface.STATUS_APPEAR:
  108. return (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, _interface.STEP_PREPARE, onAppearPrepare), _interface.STEP_START, onAppearStart), _interface.STEP_ACTIVE, onAppearActive);
  109. case _interface.STATUS_ENTER:
  110. return (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, _interface.STEP_PREPARE, onEnterPrepare), _interface.STEP_START, onEnterStart), _interface.STEP_ACTIVE, onEnterActive);
  111. case _interface.STATUS_LEAVE:
  112. return (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, _interface.STEP_PREPARE, onLeavePrepare), _interface.STEP_START, onLeaveStart), _interface.STEP_ACTIVE, onLeaveActive);
  113. default:
  114. return {};
  115. }
  116. };
  117. var eventHandlers = React.useMemo(function () {
  118. return getEventHandlers(currentStatus);
  119. }, [currentStatus]);
  120. var _useStepQueue = (0, _useStepQueue3.default)(currentStatus, !supportMotion, function (newStep) {
  121. // Only prepare step can be skip
  122. if (newStep === _interface.STEP_PREPARE) {
  123. var onPrepare = eventHandlers[_interface.STEP_PREPARE];
  124. if (!onPrepare) {
  125. return _useStepQueue3.SkipStep;
  126. }
  127. return onPrepare(getDomElement());
  128. }
  129. // Rest step is sync update
  130. if (step in eventHandlers) {
  131. var _eventHandlers$step;
  132. setStyle(((_eventHandlers$step = eventHandlers[step]) === null || _eventHandlers$step === void 0 ? void 0 : _eventHandlers$step.call(eventHandlers, getDomElement(), null)) || null);
  133. }
  134. if (step === _interface.STEP_ACTIVE && currentStatus !== _interface.STATUS_NONE) {
  135. // Patch events when motion needed
  136. patchMotionEvents(getDomElement());
  137. if (motionDeadline > 0) {
  138. clearTimeout(deadlineRef.current);
  139. deadlineRef.current = setTimeout(function () {
  140. onInternalMotionEnd({
  141. deadline: true
  142. });
  143. }, motionDeadline);
  144. }
  145. }
  146. if (step === _interface.STEP_PREPARED) {
  147. updateMotionEndStatus();
  148. }
  149. return _useStepQueue3.DoStep;
  150. }),
  151. _useStepQueue2 = (0, _slicedToArray2.default)(_useStepQueue, 2),
  152. startStep = _useStepQueue2[0],
  153. step = _useStepQueue2[1];
  154. var active = (0, _useStepQueue3.isActive)(step);
  155. activeRef.current = active;
  156. // ============================ Status ============================
  157. var visibleRef = (0, _react.useRef)(null);
  158. // Update with new status
  159. (0, _useIsomorphicLayoutEffect.default)(function () {
  160. // When use Suspense, the `visible` will repeat trigger,
  161. // But not real change of the `visible`, we need to skip it.
  162. // https://github.com/ant-design/ant-design/issues/44379
  163. if (mountedRef.current && visibleRef.current === visible) {
  164. return;
  165. }
  166. setAsyncVisible(visible);
  167. var isMounted = mountedRef.current;
  168. mountedRef.current = true;
  169. // if (!supportMotion) {
  170. // return;
  171. // }
  172. var nextStatus;
  173. // Appear
  174. if (!isMounted && visible && motionAppear) {
  175. nextStatus = _interface.STATUS_APPEAR;
  176. }
  177. // Enter
  178. if (isMounted && visible && motionEnter) {
  179. nextStatus = _interface.STATUS_ENTER;
  180. }
  181. // Leave
  182. if (isMounted && !visible && motionLeave || !isMounted && motionLeaveImmediately && !visible && motionLeave) {
  183. nextStatus = _interface.STATUS_LEAVE;
  184. }
  185. var nextEventHandlers = getEventHandlers(nextStatus);
  186. // Update to next status
  187. if (nextStatus && (supportMotion || nextEventHandlers[_interface.STEP_PREPARE])) {
  188. setStatus(nextStatus);
  189. startStep();
  190. } else {
  191. // Set back in case no motion but prev status has prepare step
  192. setStatus(_interface.STATUS_NONE);
  193. }
  194. visibleRef.current = visible;
  195. }, [visible]);
  196. // ============================ Effect ============================
  197. // Reset when motion changed
  198. (0, _react.useEffect)(function () {
  199. if (
  200. // Cancel appear
  201. currentStatus === _interface.STATUS_APPEAR && !motionAppear ||
  202. // Cancel enter
  203. currentStatus === _interface.STATUS_ENTER && !motionEnter ||
  204. // Cancel leave
  205. currentStatus === _interface.STATUS_LEAVE && !motionLeave) {
  206. setStatus(_interface.STATUS_NONE);
  207. }
  208. }, [motionAppear, motionEnter, motionLeave]);
  209. (0, _react.useEffect)(function () {
  210. return function () {
  211. mountedRef.current = false;
  212. clearTimeout(deadlineRef.current);
  213. };
  214. }, []);
  215. // Trigger `onVisibleChanged`
  216. var firstMountChangeRef = React.useRef(false);
  217. (0, _react.useEffect)(function () {
  218. // [visible & motion not end] => [!visible & motion end] still need trigger onVisibleChanged
  219. if (asyncVisible) {
  220. firstMountChangeRef.current = true;
  221. }
  222. if (asyncVisible !== undefined && currentStatus === _interface.STATUS_NONE) {
  223. // Skip first render is invisible since it's nothing changed
  224. if (firstMountChangeRef.current || asyncVisible) {
  225. onVisibleChanged === null || onVisibleChanged === void 0 || onVisibleChanged(asyncVisible);
  226. }
  227. firstMountChangeRef.current = true;
  228. }
  229. }, [asyncVisible, currentStatus]);
  230. // ============================ Styles ============================
  231. var mergedStyle = style;
  232. if (eventHandlers[_interface.STEP_PREPARE] && step === _interface.STEP_START) {
  233. mergedStyle = (0, _objectSpread2.default)({
  234. transition: 'none'
  235. }, mergedStyle);
  236. }
  237. return [currentStatus, step, mergedStyle, asyncVisible !== null && asyncVisible !== void 0 ? asyncVisible : visible];
  238. }