import React, { useEffect, useRef, useState } from "react";
import { useClickAway } from "react-use";
import styles from "./NavDropdown.module.scss";
import { createPortal } from "react-dom";
const NavDropdown = ({ items, children }) => {
const [isOpened, setIsOpened] = useState(false);
const [listStyle, setListStyle] = useState({});
const buttonRef = useRef(null);
const listRef = useRef(null);
const handleDotsClick = (e) => {
setIsOpened((prev) => !prev);
};
const updatePosition = () => {
if (isOpened && buttonRef.current && listRef.current) {
const buttonRect = buttonRef.current.getBoundingClientRect();
const listRect = listRef.current.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const viewportWidth = document.body.offsetWidth;
let top = buttonRect.bottom;
let left = buttonRect.left;
if (top + listRect.height > viewportHeight) {
top = buttonRect.top - listRect.height;
}
if (left + listRect.width > viewportWidth) {
left = viewportWidth - listRect.width;
}
setListStyle({
top: `${top + window.scrollY}px`,
left: `${left + window.scrollX}px`,
});
}
};
useClickAway(listRef, () => {
setIsOpened(false);
});
useEffect(() => {
if (isOpened) {
updatePosition();
}
}, [isOpened]);
useEffect(() => {
if (!isOpened) return;
const handleResize = () => updatePosition();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, [isOpened]);
return (
<div className={styles["nav-dropdown"]}>
{React.cloneElement(children, {
ref: buttonRef,
onClick: (e) => {
if (children.props.onClick) {
children.props.onClick(e);
}
handleDotsClick();
},
})}
{isOpened &&
createPortal(
<ul
ref={listRef}
className={styles["nav-dropdown__list"]}
style={{ ...listStyle }}
>
{items.map((item, index) => {
return (
<li key={index}>
<a
href="#"
className={styles["nav-dropdown__link"]}
>
{item.text}
</a>
</li>
);
})}
</ul>,
document.body
)}
</div>
);
};
export default NavDropdown;
.nav-dropdown {
&__list {
position: absolute;
top: -9999px;
left: -9999px;
background: #fff;
border: 1px solid #f3f3f3;
border-radius: 5px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
padding: 10px 0;
max-width: 100vw;
}
&__link {
display: block;
padding: 5px 10px;
&:hover {
background: #f3f3f3;
}
}
}
0 комментариев