jiti-meet/react/features/toolbox/components/web/DialogPortal.js

100 lines
2.3 KiB
JavaScript
Raw Normal View History

// @flow
import { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
type Props = {
/**
* The component(s) to be displayed within the drawer portal.
*/
children: React$Node,
/**
* Custom class name to apply on the container div.
*/
className?: string,
/**
* Function used to get the refferrence to the container div.
*/
getRef?: Function,
/**
* Function used to get the updated size info of the container on it's resize.
*/
setSize?: Function,
/**
* Custom style to apply to the container div.
*/
style?: Object,
};
/**
* Component meant to render a drawer at the bottom of the screen,
* by creating a portal containing the component's children.
*
* @returns {ReactElement}
*/
function DialogPortal({ children, className, style, getRef, setSize }: Props) {
const [ portalTarget ] = useState(() => {
const portalDiv = document.createElement('div');
return portalDiv;
});
useEffect(() => {
if (style) {
for (const styleProp of Object.keys(style)) {
// https://github.com/facebook/flow/issues/3733
const objStyle: Object = portalTarget.style;
objStyle[styleProp] = style[styleProp];
}
}
if (className) {
portalTarget.className = className;
}
}, [ style, className ]);
useEffect(() => {
if (portalTarget && getRef) {
getRef(portalTarget);
}
}, [ portalTarget ]);
useEffect(() => {
const size = {
width: 1,
height: 1
};
const observer = new ResizeObserver(entries => {
const { contentRect } = entries[0];
if (contentRect.width !== size.width || contentRect.height !== size.height) {
setSize && setSize(contentRect);
}
});
if (document.body) {
document.body.appendChild(portalTarget);
observer.observe(portalTarget);
}
return () => {
observer.unobserve(portalTarget);
if (document.body) {
document.body.removeChild(portalTarget);
}
};
}, []);
return ReactDOM.createPortal(
children,
portalTarget
);
}
export default DialogPortal;