UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

65 lines (64 loc) 2.14 kB
import React from 'react'; import PropTypes from 'react-peek/prop-types'; import ReactDOM from 'react-dom'; import { omitProps } from '../../util/component-types'; import { lucidClassNames } from '../../util/style-helpers'; import classNames from 'classnames'; const cx = lucidClassNames.bind('&-Portal'); const { any, node, string } = PropTypes; class Portal extends React.Component { constructor() { super(...arguments); this.state = { isReady: false, }; this.manuallyCreatedPortal = false; this.portalElement = document.createElement('div'); } componentDidMount() { const { portalId } = this.props; let portalElement; if (portalId) { portalElement = document.getElementById(portalId); } if (!portalElement) { this.manuallyCreatedPortal = true; portalElement = document.createElement('div'); portalElement.id = portalId; document.body.appendChild(portalElement); } this.portalElement = portalElement; this.setState({ isReady: true }); } componentWillUnmount() { if (this.manuallyCreatedPortal) { this.portalElement.remove(); } } render() { return this.state.isReady ? ReactDOM.createPortal(React.createElement("div", Object.assign({ className: classNames(cx('&'), this.props.className) }, omitProps(this.props, undefined, Object.keys(Portal.propTypes))), this.props.children), this.portalElement) : null; } } Portal.displayName = 'Portal'; Portal.peek = { description: ` A Portal component is used to render content in a container that is appended to \`document.body\`. `, categories: ['utility'], }; Portal.propTypes = { children: node ` any valid React children `, className: any ` Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. `, portalId: string ` The \`id\` of the portal element that is appended to \`document.body\`. `, }; export default Portal;