Portal.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  2. import * as React from 'react';
  3. import { createPortal } from 'react-dom';
  4. import canUseDom from "rc-util/es/Dom/canUseDom";
  5. import warning from "rc-util/es/warning";
  6. import { supportRef, useComposeRef } from "rc-util/es/ref";
  7. import OrderContext from "./Context";
  8. import useDom from "./useDom";
  9. import useScrollLocker from "./useScrollLocker";
  10. import { inlineMock } from "./mock";
  11. var getPortalContainer = function getPortalContainer(getContainer) {
  12. if (getContainer === false) {
  13. return false;
  14. }
  15. if (!canUseDom() || !getContainer) {
  16. return null;
  17. }
  18. if (typeof getContainer === 'string') {
  19. return document.querySelector(getContainer);
  20. }
  21. if (typeof getContainer === 'function') {
  22. return getContainer();
  23. }
  24. return getContainer;
  25. };
  26. var Portal = /*#__PURE__*/React.forwardRef(function (props, ref) {
  27. var open = props.open,
  28. autoLock = props.autoLock,
  29. getContainer = props.getContainer,
  30. debug = props.debug,
  31. _props$autoDestroy = props.autoDestroy,
  32. autoDestroy = _props$autoDestroy === void 0 ? true : _props$autoDestroy,
  33. children = props.children;
  34. var _React$useState = React.useState(open),
  35. _React$useState2 = _slicedToArray(_React$useState, 2),
  36. shouldRender = _React$useState2[0],
  37. setShouldRender = _React$useState2[1];
  38. var mergedRender = shouldRender || open;
  39. // ========================= Warning =========================
  40. if (process.env.NODE_ENV !== 'production') {
  41. warning(canUseDom() || !open, "Portal only work in client side. Please call 'useEffect' to show Portal instead default render in SSR.");
  42. }
  43. // ====================== Should Render ======================
  44. React.useEffect(function () {
  45. if (autoDestroy || open) {
  46. setShouldRender(open);
  47. }
  48. }, [open, autoDestroy]);
  49. // ======================== Container ========================
  50. var _React$useState3 = React.useState(function () {
  51. return getPortalContainer(getContainer);
  52. }),
  53. _React$useState4 = _slicedToArray(_React$useState3, 2),
  54. innerContainer = _React$useState4[0],
  55. setInnerContainer = _React$useState4[1];
  56. React.useEffect(function () {
  57. var customizeContainer = getPortalContainer(getContainer);
  58. // Tell component that we check this in effect which is safe to be `null`
  59. setInnerContainer(customizeContainer !== null && customizeContainer !== void 0 ? customizeContainer : null);
  60. });
  61. var _useDom = useDom(mergedRender && !innerContainer, debug),
  62. _useDom2 = _slicedToArray(_useDom, 2),
  63. defaultContainer = _useDom2[0],
  64. queueCreate = _useDom2[1];
  65. var mergedContainer = innerContainer !== null && innerContainer !== void 0 ? innerContainer : defaultContainer;
  66. // ========================= Locker ==========================
  67. useScrollLocker(autoLock && open && canUseDom() && (mergedContainer === defaultContainer || mergedContainer === document.body));
  68. // =========================== Ref ===========================
  69. var childRef = null;
  70. if (children && supportRef(children) && ref) {
  71. var _ref = children;
  72. childRef = _ref.ref;
  73. }
  74. var mergedRef = useComposeRef(childRef, ref);
  75. // ========================= Render ==========================
  76. // Do not render when nothing need render
  77. // When innerContainer is `undefined`, it may not ready since user use ref in the same render
  78. if (!mergedRender || !canUseDom() || innerContainer === undefined) {
  79. return null;
  80. }
  81. // Render inline
  82. var renderInline = mergedContainer === false || inlineMock();
  83. var reffedChildren = children;
  84. if (ref) {
  85. reffedChildren = /*#__PURE__*/React.cloneElement(children, {
  86. ref: mergedRef
  87. });
  88. }
  89. return /*#__PURE__*/React.createElement(OrderContext.Provider, {
  90. value: queueCreate
  91. }, renderInline ? reffedChildren : /*#__PURE__*/createPortal(reffedChildren, mergedContainer));
  92. });
  93. if (process.env.NODE_ENV !== 'production') {
  94. Portal.displayName = 'Portal';
  95. }
  96. export default Portal;