UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

44 lines (43 loc) 1.7 kB
import useIsomorphicLayoutEffect from "../utils/useIsomorphicLayoutEffect.js"; import { PortalContext } from "./PortalContext.js"; import { DEFAULT_PORTAL_CONTAINER_NAME, ensureDefaultPortal, getPortalRoot } from "./portalRoot.js"; import React, { useContext } from "react"; import { createPortal } from "react-dom"; //#region src/Portal/Portal.tsx /** * Creates a React Portal, placing all children in a separate physical DOM root node. * @see https://reactjs.org/docs/portals.html */ const Portal = ({ children, onMount, containerName: _containerName }) => { const { portalContainerName } = useContext(PortalContext); const elementRef = React.useRef(null); if (!elementRef.current) { const div = document.createElement("div"); div.setAttribute("data-component", "Portal"); div.style.position = "relative"; div.style.zIndex = "1"; elementRef.current = div; } const element = elementRef.current; useIsomorphicLayoutEffect(() => { let containerName = _containerName !== null && _containerName !== void 0 ? _containerName : portalContainerName; if (containerName === void 0) { containerName = DEFAULT_PORTAL_CONTAINER_NAME; ensureDefaultPortal(); } const parentElement = getPortalRoot(containerName); if (!parentElement) throw new Error(`Portal container '${containerName}' is not yet registered. Container must be registered with registerPortalRoot before use.`); parentElement.appendChild(element); onMount === null || onMount === void 0 || onMount(); return () => { parentElement.removeChild(element); }; }, [ element, _containerName, portalContainerName ]); return /*#__PURE__*/ createPortal(children, element); }; //#endregion export { Portal };