/*
Copyright (c) 2018-2020 Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// @flow
/* global document */
import * as React from 'react';
import ReactDOM from 'react-dom';
import {styled} from '../styles/index.js';
import {LayersContext, Consumer} from './layers-manager.js';
import type {LayerPropsT, LayerComponentPropsT, LayerStateT} from './types.js';
const Container = styled<{$zIndex?: number}>('div', ({$zIndex}) => ({
position: 'absolute',
top: 0,
left: 0,
right: 0,
zIndex: $zIndex || null,
}));
class LayerComponent extends React.Component<
LayerComponentPropsT,
LayerStateT,
> {
static contextType: typeof LayersContext = LayersContext;
state = {container: null};
componentDidMount() {
this.context.addEscapeHandler(this.onEscape);
this.context.addDocClickHandler(this.onDocumentClick);
const {onMount, mountNode, host: layersManagerHost} = this.props;
if (mountNode) {
onMount && onMount();
return;
}
// There was no LayersManager added if this.props.host === undefined.
// Use document.body is the case no LayersManager is used.
const hasLayersManager = layersManagerHost !== undefined;
if (__DEV__) {
if (!hasLayersManager) {
console.warn(
'`LayersManager` was not found. This occurs if you are attempting to use a component requiring `Layer` without using the `BaseProvider` at the root of your app. Please visit https://baseweb.design/components/base-provider/ for more information',
);
}
}
const host = hasLayersManager ? layersManagerHost : document.body;
if (host) {
this.addContainer(host);
}
}
componentDidUpdate(prevProps) {
const {host, mountNode} = this.props;
if (mountNode) {
return;
}
if (host && host !== prevProps.host && prevProps.host === null) {
this.addContainer(host);
}
}
componentWillUnmount() {
this.context.removeEscapeHandler(this.onEscape);
this.context.removeDocClickHandler(this.onDocumentClick);
if (this.props.onUnmount) {
this.props.onUnmount();
}
const host = this.props.host;
const container = this.state.container;
if (host && container) {
if (host.contains(container)) {
host.removeChild(container);
}
}
}
onEscape = () => {
if (this.props.onEscape) {
this.props.onEscape();
}
};
onDocumentClick = (event: MouseEvent) => {
if (this.props.onDocumentClick) {
this.props.onDocumentClick(event);
}
};
addContainer(host) {
const {index, mountNode, onMount} = this.props;
// Do nothing if mountNode is provided
if (mountNode) {
return;
}
if (host) {
const container = host.ownerDocument.createElement('div');
// `host` is an DOM node, but not a React component
const sibling = typeof index === 'number' ? host.children[index] : null;
sibling
? host.insertBefore(container, sibling)
: host.appendChild(container);
this.setState({container}, () => {
onMount && onMount();
});
}
}
render() {
const {container} = this.state;
const {children, mountNode, zIndex} = this.props;
// Only adding an additional wrapper when a layer has z-index to be set
const childrenToRender = zIndex ? (
{children}
) : (
children
);
if (__BROWSER__) {
if (mountNode || container) {
// $FlowFixMe
return ReactDOM.createPortal(childrenToRender, mountNode || container);
}
return null;
}
return null;
}
}
export default function Layer(props: LayerPropsT) {
return (
{({host, zIndex}) => (
)}
);
}
declare var __DEV__: boolean;
declare var __NODE__: boolean;
declare var __BROWSER__: boolean;