PromucFlow_constructor/app/client/src/pages/Editor/Popper.tsx

71 lines
2.0 KiB
TypeScript
Raw Normal View History

import React, { useRef, useEffect } from "react";
import styled from "styled-components";
import { createPortal } from "react-dom";
2020-06-04 13:49:22 +00:00
import PopperJS, { Placement, PopperOptions } from "popper.js";
type PopperProps = {
2020-06-04 13:49:22 +00:00
zIndex: number;
isOpen: boolean;
targetNode?: Element;
children: JSX.Element;
2020-06-04 13:49:22 +00:00
placement: Placement;
modifiers?: Partial<PopperOptions["modifiers"]>;
};
2020-06-04 13:49:22 +00:00
const PopperWrapper = styled.div<{ zIndex: number }>`
2020-12-24 04:32:25 +00:00
z-index: ${(props) => props.zIndex};
position: absolute;
`;
/* eslint-disable react/display-name */
export default (props: PopperProps) => {
const contentRef = useRef(null);
useEffect(() => {
const parentElement = props.targetNode && props.targetNode.parentElement;
if (
parentElement &&
parentElement.parentElement &&
props.targetNode &&
props.isOpen
) {
2020-01-08 04:11:23 +00:00
// TODO: To further optimize this, we can go through the popper API
// and figure out a way to keep an app instance level popper instance
// which we can update to have different references when called here.
// However, the performance benefit gained by such an optimization
// remaines to be discovered.
const _popper = new PopperJS(
props.targetNode,
(contentRef.current as unknown) as Element,
{
2020-06-04 13:49:22 +00:00
placement: props.placement,
modifiers: {
flip: {
behavior: ["right", "left", "bottom", "top"],
},
keepTogether: {
enabled: false,
},
arrow: {
enabled: false,
},
preventOverflow: {
enabled: true,
boundariesElement: "viewport",
},
2020-06-04 13:49:22 +00:00
...props.modifiers,
},
},
);
return () => {
_popper.destroy();
};
}
2020-06-04 13:49:22 +00:00
}, [props.targetNode, props.isOpen, props.modifiers, props.placement]);
return createPortal(
2020-06-04 13:49:22 +00:00
<PopperWrapper ref={contentRef} zIndex={props.zIndex}>
{props.children}
</PopperWrapper>,
document.body,
);
};