el.xwx.moe/components/ClickAwayHandler.tsx

74 lines
1.8 KiB
TypeScript
Raw Normal View History

import React, { useRef, useEffect, ReactNode, RefObject } from "react";
2023-03-22 18:11:54 -05:00
type Props = {
children: ReactNode;
onClickOutside: Function;
2023-02-18 21:32:02 -06:00
className?: string;
2023-10-28 06:20:35 -05:00
style?: React.CSSProperties;
2023-10-28 11:50:11 -05:00
onMount?: (rect: DOMRect) => void;
2023-03-22 18:11:54 -05:00
};
2024-04-20 09:49:06 -05:00
function getZIndex(element: HTMLElement): number {
let zIndex = 0;
while (element) {
const zIndexStyle = window
.getComputedStyle(element)
.getPropertyValue("z-index");
const numericZIndex = Number(zIndexStyle);
if (zIndexStyle !== "auto" && !isNaN(numericZIndex)) {
zIndex = numericZIndex;
break;
}
element = element.parentElement as HTMLElement;
}
return zIndex;
}
function useOutsideAlerter(
ref: RefObject<HTMLElement>,
onClickOutside: Function
) {
useEffect(() => {
2024-04-20 09:49:06 -05:00
function handleClickOutside(event: MouseEvent) {
const clickedElement = event.target as HTMLElement;
if (ref.current && !ref.current.contains(clickedElement)) {
const refZIndex = getZIndex(ref.current);
const clickedZIndex = getZIndex(clickedElement);
if (clickedZIndex <= refZIndex) {
onClickOutside(event);
}
}
}
2024-04-20 09:49:06 -05:00
2023-05-22 07:20:48 -05:00
document.addEventListener("mousedown", handleClickOutside);
return () => {
2023-05-22 07:20:48 -05:00
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, onClickOutside]);
}
export default function ClickAwayHandler({
children,
onClickOutside,
className,
2023-10-28 06:20:35 -05:00
style,
2023-10-28 11:50:11 -05:00
onMount,
}: Props) {
2023-10-28 11:50:11 -05:00
const wrapperRef = useRef<HTMLDivElement | null>(null);
useOutsideAlerter(wrapperRef, onClickOutside);
2023-10-28 11:50:11 -05:00
useEffect(() => {
if (wrapperRef.current && onMount) {
const rect = wrapperRef.current.getBoundingClientRect();
onMount(rect); // Pass the bounding rectangle to the parent
}
}, []);
2023-02-18 21:32:02 -06:00
return (
2023-10-28 06:20:35 -05:00
<div ref={wrapperRef} className={className} style={style}>
2023-02-18 21:32:02 -06:00
{children}
</div>
);
}