Participants popup; Actions popover
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
|
||||
interface ActionsPopoverProps {
|
||||
options: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
icon?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
export default function ActionsPopover({ options }: ActionsPopoverProps) {
|
||||
const [isOpened, setIsOpened] = useState(false);
|
||||
const [openUpwards, setOpenUpwards] = useState(false);
|
||||
const popoverRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [menuHeight, setMenuHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
popoverRef.current &&
|
||||
!popoverRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpened(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpened && buttonRef.current) {
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
||||
const spaceAbove = buttonRect.top;
|
||||
|
||||
console.log(spaceBelow, menuHeight, spaceAbove);
|
||||
// Если снизу недостаточно места, но сверху достаточно - открываем вверх
|
||||
if (spaceBelow < menuHeight && spaceAbove > menuHeight) {
|
||||
setOpenUpwards(true);
|
||||
} else {
|
||||
setOpenUpwards(false);
|
||||
}
|
||||
}
|
||||
}, [isOpened, menuHeight, options.length]);
|
||||
|
||||
return (
|
||||
<div className="relative" ref={popoverRef}>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="flex items-center justify-center gap-[0.139vw] size-[1.667vw]"
|
||||
onClick={() => setIsOpened(!isOpened)}
|
||||
>
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
</button>
|
||||
|
||||
{isOpened && (
|
||||
<div
|
||||
ref={(el) => {
|
||||
setMenuHeight(el?.offsetHeight || 0);
|
||||
}}
|
||||
className={`absolute z-10 right-0 w-[13.333vw] bg-white rounded-[1.111vw] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] ${
|
||||
openUpwards ? "bottom-[100%]" : "top-[100%]"
|
||||
}`}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<button
|
||||
className="p-[0.833vw] button-s text-[#7D7D7D] w-full flex items-center gap-[0.556vw]"
|
||||
key={option.label}
|
||||
onClick={option.onClick}
|
||||
disabled={option.disabled}
|
||||
style={{
|
||||
backgroundColor: option.disabled ? "#F6F6F6" : "transparent",
|
||||
opacity: option.disabled ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
<div className="size-[1.111vw] ">{option.icon}</div>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user