UNPKG

@shopify/polaris

Version:

Shopify’s product component library

61 lines (60 loc) 2.21 kB
import React from 'react'; import { createPortal } from 'react-dom'; import { createUniqueIDFactory } from '@shopify/javascript-utilities/other'; import { ThemeContext } from '../../utilities/theme'; import { portal } from '../shared'; const getUniqueID = createUniqueIDFactory('portal-'); export class Portal extends React.PureComponent { constructor() { super(...arguments); this.state = { isMounted: false }; this.portalNode = null; this.portalId = this.props.idPrefix !== '' ? `${this.props.idPrefix}-${getUniqueID()}` : getUniqueID(); } componentDidMount() { this.portalNode = document.createElement('div'); this.portalNode.setAttribute(portal.props[0], this.portalId); if (this.context != null) { const { cssCustomProperties } = this.context; if (cssCustomProperties != null) { this.portalNode.setAttribute('style', cssCustomProperties); } else { this.portalNode.removeAttribute('style'); } } document.body.appendChild(this.portalNode); this.setState({ isMounted: true }); } componentDidUpdate(_, prevState) { const { onPortalCreated = noop } = this.props; if (this.portalNode && this.context != null) { const { cssCustomProperties, textColor } = this.context; if (cssCustomProperties != null) { const style = `${cssCustomProperties};color:${textColor};`; this.portalNode.setAttribute('style', style); } else { this.portalNode.removeAttribute('style'); } } if (!prevState.isMounted && this.state.isMounted) { onPortalCreated(); } } componentWillUnmount() { if (this.portalNode) { document.body.removeChild(this.portalNode); } } render() { return this.portalNode && this.state.isMounted ? createPortal(this.props.children, this.portalNode) : null; } } Portal.defaultProps = { idPrefix: '' }; Portal.contextType = ThemeContext; function noop() { }