@atlaskit/portal
Version:
A wrapper for rendering components in React portals.
44 lines (43 loc) • 1.86 kB
JavaScript
import React, { Suspense, useState } from 'react';
import { createPortal } from 'react-dom';
import { ThemeProvider } from '@atlaskit/app-provider/theme-provider';
import { useColorMode } from '@atlaskit/app-provider/use-color-mode';
import { useIsInsideThemeProvider } from '@atlaskit/app-provider/use-is-inside-theme-provider';
import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect';
import { createAtlaskitPortal } from '../utils/create-atlaskit-portal';
import { createPortalParent } from '../utils/create-portal-parent';
export default function InternalPortalNew(props) {
const {
zIndex,
children
} = props;
const [atlaskitPortal, setAtlaskitPortal] = useState(null);
const colorMode = useColorMode();
const isInsideThemeProvider = useIsInsideThemeProvider();
useIsomorphicLayoutEffect(() => {
const tempPortalContainer = createAtlaskitPortal(zIndex);
setAtlaskitPortal(tempPortalContainer);
const portalParent = createPortalParent();
if (!tempPortalContainer || !portalParent) {
return;
}
portalParent.appendChild(tempPortalContainer);
return () => {
if (tempPortalContainer) {
portalParent.removeChild(tempPortalContainer);
}
setAtlaskitPortal(null);
};
}, [zIndex]);
/**
* We wrap portal children with a Suspense boundary because in React 18 concurrent,
* if you suspend from _within_ a portal to a Suspense boundary _outside_ the portal,
* our portal gets in an infinite loop of rendering.
*/
const suspendedChildren = /*#__PURE__*/React.createElement(Suspense, {
fallback: null
}, isInsideThemeProvider ? /*#__PURE__*/React.createElement(ThemeProvider, {
defaultColorMode: colorMode
}, children) : children);
return atlaskitPortal ? /*#__PURE__*/createPortal(suspendedChildren, atlaskitPortal) : null;
}