66 lines
1.6 KiB
JavaScript
66 lines
1.6 KiB
JavaScript
import React, { useEffect, useRef, useState } from "react";
|
|
|
|
const HoverPopup = ({ title, content, children }) => {
|
|
const [visible, setVisible] = useState(false);
|
|
const triggerRef = useRef(null);
|
|
const popupRef = useRef(null);
|
|
|
|
// Toggle on hover or click
|
|
const handleMouseEnter = () => setVisible(true);
|
|
const handleClick = () => setVisible((prev) => !prev);
|
|
|
|
// Hide on outside click
|
|
useEffect(() => {
|
|
const handleDocumentClick = (e) => {
|
|
if (
|
|
!popupRef.current?.contains(e.target) &&
|
|
!triggerRef.current?.contains(e.target)
|
|
) {
|
|
setVisible(false);
|
|
}
|
|
};
|
|
|
|
if (visible) {
|
|
document.addEventListener("click", handleDocumentClick);
|
|
}
|
|
|
|
return () => {
|
|
document.removeEventListener("click", handleDocumentClick);
|
|
};
|
|
}, [visible]);
|
|
|
|
return (
|
|
<div
|
|
className="d-inline-block position-relative"
|
|
ref={triggerRef}
|
|
onMouseEnter={handleMouseEnter}
|
|
onClick={handleClick}
|
|
style={{ cursor: "pointer" }}
|
|
>
|
|
{children}
|
|
|
|
{visible && (
|
|
<div
|
|
ref={popupRef}
|
|
className="bg-white border rounded shadow-sm py-1 px-2 text-start text-lowercase"
|
|
style={{
|
|
position: "absolute",
|
|
top: "100%",
|
|
left: "50%",
|
|
transform: "translateX(-50%)",
|
|
zIndex: 1050,
|
|
minWidth: "220px",
|
|
marginTop: "8px",
|
|
}}
|
|
>
|
|
{title && <h6 className="mb-2 text-capitalize">{title}</h6>}
|
|
<div className="text-capitalize">{content}</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default HoverPopup;
|
|
|