PortalWrapper.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. "use strict";
  2. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = void 0;
  8. exports.getOpenCount = getOpenCount;
  9. var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
  10. var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
  11. var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
  12. var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
  13. var _createSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/createSuper"));
  14. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  15. var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  16. var React = _interopRequireWildcard(require("react"));
  17. var _raf = _interopRequireDefault(require("./raf"));
  18. var _Portal = _interopRequireDefault(require("./Portal"));
  19. var _canUseDom = _interopRequireDefault(require("./Dom/canUseDom"));
  20. var _switchScrollingEffect = _interopRequireDefault(require("./switchScrollingEffect"));
  21. var _setStyle = _interopRequireDefault(require("./setStyle"));
  22. var _scrollLocker = _interopRequireDefault(require("./Dom/scrollLocker"));
  23. /* eslint-disable no-underscore-dangle,react/require-default-props */
  24. var openCount = 0;
  25. var supportDom = (0, _canUseDom.default)();
  26. /** @private Test usage only */
  27. function getOpenCount() {
  28. return process.env.NODE_ENV === 'test' ? openCount : 0;
  29. }
  30. // https://github.com/ant-design/ant-design/issues/19340
  31. // https://github.com/ant-design/ant-design/issues/19332
  32. var cacheOverflow = {};
  33. var getParent = function getParent(getContainer) {
  34. if (!supportDom) {
  35. return null;
  36. }
  37. if (getContainer) {
  38. if (typeof getContainer === 'string') {
  39. return document.querySelectorAll(getContainer)[0];
  40. }
  41. if (typeof getContainer === 'function') {
  42. return getContainer();
  43. }
  44. if ((0, _typeof2.default)(getContainer) === 'object' && getContainer instanceof window.HTMLElement) {
  45. return getContainer;
  46. }
  47. }
  48. return document.body;
  49. };
  50. var PortalWrapper = /*#__PURE__*/function (_React$Component) {
  51. (0, _inherits2.default)(PortalWrapper, _React$Component);
  52. var _super = (0, _createSuper2.default)(PortalWrapper);
  53. function PortalWrapper(props) {
  54. var _this;
  55. (0, _classCallCheck2.default)(this, PortalWrapper);
  56. _this = _super.call(this, props);
  57. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "container", void 0);
  58. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "componentRef", /*#__PURE__*/React.createRef());
  59. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "rafId", void 0);
  60. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "scrollLocker", void 0);
  61. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "renderComponent", void 0);
  62. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateScrollLocker", function (prevProps) {
  63. var _ref = prevProps || {},
  64. prevVisible = _ref.visible;
  65. var _this$props = _this.props,
  66. getContainer = _this$props.getContainer,
  67. visible = _this$props.visible;
  68. if (visible && visible !== prevVisible && supportDom && getParent(getContainer) !== _this.scrollLocker.getContainer()) {
  69. _this.scrollLocker.reLock({
  70. container: getParent(getContainer)
  71. });
  72. }
  73. });
  74. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateOpenCount", function (prevProps) {
  75. var _ref2 = prevProps || {},
  76. prevVisible = _ref2.visible,
  77. prevGetContainer = _ref2.getContainer;
  78. var _this$props2 = _this.props,
  79. visible = _this$props2.visible,
  80. getContainer = _this$props2.getContainer;
  81. // Update count
  82. if (visible !== prevVisible && supportDom && getParent(getContainer) === document.body) {
  83. if (visible && !prevVisible) {
  84. openCount += 1;
  85. } else if (prevProps) {
  86. openCount -= 1;
  87. }
  88. }
  89. // Clean up container if needed
  90. var getContainerIsFunc = typeof getContainer === 'function' && typeof prevGetContainer === 'function';
  91. if (getContainerIsFunc ? getContainer.toString() !== prevGetContainer.toString() : getContainer !== prevGetContainer) {
  92. _this.removeCurrentContainer();
  93. }
  94. });
  95. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "attachToParent", function () {
  96. var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  97. if (force || _this.container && !_this.container.parentNode) {
  98. var parent = getParent(_this.props.getContainer);
  99. if (parent) {
  100. parent.appendChild(_this.container);
  101. return true;
  102. }
  103. return false;
  104. }
  105. return true;
  106. });
  107. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getContainer", function () {
  108. if (!supportDom) {
  109. return null;
  110. }
  111. if (!_this.container) {
  112. _this.container = document.createElement('div');
  113. _this.attachToParent(true);
  114. }
  115. _this.setWrapperClassName();
  116. return _this.container;
  117. });
  118. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "setWrapperClassName", function () {
  119. var wrapperClassName = _this.props.wrapperClassName;
  120. if (_this.container && wrapperClassName && wrapperClassName !== _this.container.className) {
  121. _this.container.className = wrapperClassName;
  122. }
  123. });
  124. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "removeCurrentContainer", function () {
  125. var _this$container;
  126. // Portal will remove from `parentNode`.
  127. // Let's handle this again to avoid refactor issue.
  128. (_this$container = _this.container) === null || _this$container === void 0 || (_this$container = _this$container.parentNode) === null || _this$container === void 0 || _this$container.removeChild(_this.container);
  129. });
  130. /**
  131. * Enhance ./switchScrollingEffect
  132. * 1. Simulate document body scroll bar with
  133. * 2. Record body has overflow style and recover when all of PortalWrapper invisible
  134. * 3. Disable body scroll when PortalWrapper has open
  135. *
  136. * @memberof PortalWrapper
  137. */
  138. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "switchScrollingEffect", function () {
  139. if (openCount === 1 && !Object.keys(cacheOverflow).length) {
  140. (0, _switchScrollingEffect.default)();
  141. // Must be set after switchScrollingEffect
  142. cacheOverflow = (0, _setStyle.default)({
  143. overflow: 'hidden',
  144. overflowX: 'hidden',
  145. overflowY: 'hidden'
  146. });
  147. } else if (!openCount) {
  148. (0, _setStyle.default)(cacheOverflow);
  149. cacheOverflow = {};
  150. (0, _switchScrollingEffect.default)(true);
  151. }
  152. });
  153. _this.scrollLocker = new _scrollLocker.default({
  154. container: getParent(props.getContainer)
  155. });
  156. return _this;
  157. }
  158. (0, _createClass2.default)(PortalWrapper, [{
  159. key: "componentDidMount",
  160. value: function componentDidMount() {
  161. var _this2 = this;
  162. this.updateOpenCount();
  163. if (!this.attachToParent()) {
  164. this.rafId = (0, _raf.default)(function () {
  165. _this2.forceUpdate();
  166. });
  167. }
  168. }
  169. }, {
  170. key: "componentDidUpdate",
  171. value: function componentDidUpdate(prevProps) {
  172. this.updateOpenCount(prevProps);
  173. this.updateScrollLocker(prevProps);
  174. this.setWrapperClassName();
  175. this.attachToParent();
  176. }
  177. }, {
  178. key: "componentWillUnmount",
  179. value: function componentWillUnmount() {
  180. var _this$props3 = this.props,
  181. visible = _this$props3.visible,
  182. getContainer = _this$props3.getContainer;
  183. if (supportDom && getParent(getContainer) === document.body) {
  184. // 离开时不会 render, 导到离开时数值不变,改用 func 。。
  185. openCount = visible && openCount ? openCount - 1 : openCount;
  186. }
  187. this.removeCurrentContainer();
  188. _raf.default.cancel(this.rafId);
  189. }
  190. }, {
  191. key: "render",
  192. value: function render() {
  193. var _this$props4 = this.props,
  194. children = _this$props4.children,
  195. forceRender = _this$props4.forceRender,
  196. visible = _this$props4.visible;
  197. var portal = null;
  198. var childProps = {
  199. getOpenCount: function getOpenCount() {
  200. return openCount;
  201. },
  202. getContainer: this.getContainer,
  203. switchScrollingEffect: this.switchScrollingEffect,
  204. scrollLocker: this.scrollLocker
  205. };
  206. if (forceRender || visible || this.componentRef.current) {
  207. portal = /*#__PURE__*/React.createElement(_Portal.default, {
  208. getContainer: this.getContainer,
  209. ref: this.componentRef
  210. }, children(childProps));
  211. }
  212. return portal;
  213. }
  214. }]);
  215. return PortalWrapper;
  216. }(React.Component);
  217. var _default = exports.default = PortalWrapper;