UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

67 lines (66 loc) 3.1 kB
import "../../CommonImports"; import "../../Core/core.css"; import "./Portal.css"; import * as React from "react"; import * as ReactDOM from "react-dom"; import { ObservableValue } from '../../Core/Observable'; import { Observer } from '../../Observer'; /** * The Portal component is used to create a React Portal through a well known component. * This component allows the platform to control where portals are rooted in the document * and ensure these are managed properly. */ export class Portal extends React.Component { constructor(props) { super(props); this.mounted = new ObservableValue(false); this.focusElement = document.activeElement; // Determine the element that will host the portal. let parentElement = this.props.portalElement; if (!parentElement && this.props.portalSelector) { parentElement = document.querySelector(this.props.portalSelector); } if (!parentElement) { parentElement = document.querySelector(".bolt-portal-host"); if (!parentElement) { parentElement = document.createElement("div"); parentElement.className = "bolt-portal-host absolute-fill no-events scroll-hidden"; document.body.appendChild(parentElement); } } if (this.props.parentClassName && !parentElement.classList.contains(this.props.parentClassName)) { parentElement.classList.add(this.props.parentClassName); } this.parentElement = parentElement; // Create the hosting element for the portal. this.hostElement = document.createElement("div"); } render() { this.hostElement.className = ""; this.hostElement.classList.add("bolt-portal"); this.hostElement.classList.add("absolute-fill"); // If custom class's are supplied add them (1 at a time since IE doesnt support multiple args). if (this.props.className) { const classNames = this.props.className.split(" "); for (let className of classNames) { this.hostElement.classList.add(className); } } // NOTE: We dont render the children until after we have mounted the portal. // If the caller needs to access the document while mounting the content this // will ensure the children of the portal are not mounted until the portal // is attached to the DOM. return ReactDOM.createPortal(React.createElement(Observer, { mounted: this.mounted }, (props) => (props.mounted ? this.props.children : null)), this.hostElement); } componentDidMount() { this.parentElement.appendChild(this.hostElement); this.mounted.value = true; } componentWillUnmount() { var _a; this.parentElement.removeChild(this.hostElement); if (!this.props.bypassActiveElementFocusOnUnmount) { (_a = this.focusElement) === null || _a === void 0 ? void 0 : _a.focus(); } } }