glide-design-system
Version:
Glide design system is an open-source React component library. It offers numerous benefits that make them essential tools for design and development teams.
144 lines (135 loc) • 4.29 kB
JavaScript
import React, { useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import ReactDOM from "react-dom";
/**
* Menu that wraps MenuItems
* @param {*} open A boolean flag to control the visibility of the menu. If true, the menu is displayed; if false, the menu is hidden.
* @param {*} onClose A function to be called when the menu should be closed or hidden. It is typically used to set the open prop to false when the user clicks outside the menu.
* @param {*} position The position of the menu relative to the anchorEl element
* @param {*} children The content of the menu, which can be any valid React elements or components.
* @param {*} anchorEl The element to which the menu is anchored. It can be any valid React element.
* @param {*} style An object containing custom styles to be applied to the container of the menu.
*/
export const Menu = ({
open,
onClose,
position = "bottom",
children,
anchorEl,
style,
className,
id,
name,
...props
}) => {
const [newPosition, setPosition] = useState(null);
const menuChildRef = useRef(null);
useEffect(() => {
if (open && anchorEl) {
if (open) {
document.body.style.overflowY = "hidden";
}
const anchorElRect =
ReactDOM.findDOMNode(anchorEl).getBoundingClientRect();
const updatedPosition = {
top: anchorElRect.top,
left: anchorElRect.left,
bottom: anchorElRect.bottom,
right: anchorElRect.right,
height: anchorElRect.height,
width: anchorElRect.width,
};
setPosition(updatedPosition);
}
return () => {
document.body.style.overflowY = "";
};
}, [open, anchorEl]);
let updatedPosition = null;
const calpositionHandler = () => {
if (open && anchorEl) {
if (open) {
document.body.style.overflowY = "hidden";
}
const anchorElRect =
ReactDOM.findDOMNode(anchorEl).getBoundingClientRect();
updatedPosition = {
top: anchorElRect.top,
left: anchorElRect.left,
bottom: anchorElRect.bottom,
right: anchorElRect.right,
height: anchorElRect.height,
width: anchorElRect.width,
};
}
};
calpositionHandler();
// using useState()
// const combinedStyle = {
// top:
// position === "top" || position === "topLeft" || position === "topRight"
// ? Math.abs(newPosition?.top - menuChildRef?.current?.offsetHeight - 5)
// : newPosition && newPosition?.bottom + 5,
// left:
// (position === "topRight" ||
// position === "bottomRight" ||
// position === "top" ||
// position === "bottom") &&
// newPosition
// ? newPosition?.left
// : (position === "topLeft" || position === "bottomLeft") && newPosition
// ? Math.abs(newPosition?.right - menuChildRef?.current?.offsetWidth)
// : newPosition?.left,
// ...style,
// };
//using let
const combinedStyle = {
top:
position === "top" || position === "topLeft" || position === "topRight"
? Math.abs(
updatedPosition?.top - menuChildRef?.current?.offsetHeight - 5
)
: updatedPosition && updatedPosition?.bottom + 5,
left:
(position === "topRight" ||
position === "bottomRight" ||
position === "top" ||
position === "bottom") &&
updatedPosition
? updatedPosition?.left
: (position === "topLeft" || position === "bottomLeft") &&
updatedPosition
? Math.abs(updatedPosition?.right - menuChildRef?.current?.offsetWidth)
: updatedPosition?.left,
...style,
};
return (
<div
id={id}
data-testid={id}
name={name}
className={open ? "menuParentContainer" : "menuContainerNoEffect"}
>
<div
onClick={() => {
onClose();
}}
className="menuModalContainer"
></div>
<div
ref={menuChildRef}
className={`menuChildContainer ${className ? className : ""}`}
style={combinedStyle}
{...props}
>
{children}
</div>
</div>
);
};
Menu.propTypes = {
position: PropTypes.string,
onClose: PropTypes.func,
open: PropTypes.bool,
anchorEl: PropTypes.object,
};