import { useState, useRef, useEffect, type ReactNode } from 'react'; interface Props { content: string; children: ReactNode; } export const Tooltip = ({ content, children }: Props) => { const [show, setShow] = useState(false); const containerRef = useRef(null); const tooltipRef = useRef(null); const [positionStyle, setPositionStyle] = useState({ left: '50%', transform: 'translateX(-50%)', }); useEffect(() => { const handleClickOutside = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setShow(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); useEffect(() => { if (!show) { return; } // Measure and adjust positioning to prevent overflow const adjustPosition = () => { if (tooltipRef.current) { const rect = tooltipRef.current.getBoundingClientRect(); const windowWidth = window.innerWidth; const padding = 12; // safety margin from screen edges if (rect.right > windowWidth - padding) { setPositionStyle({ right: '0px', left: 'auto', transform: 'none', }); } else if (rect.left < padding) { setPositionStyle({ left: '0px', transform: 'none', }); } } }; // Run adjustment immediately adjustPosition(); // Also adjust on resize window.addEventListener('resize', adjustPosition); return () => window.removeEventListener('resize', adjustPosition); }, [show]); return (
{ setPositionStyle({ left: '50%', transform: 'translateX(-50%)' }); setShow(true); }} onMouseLeave={() => setShow(false)} onClick={(e) => { e.stopPropagation(); if (!show) { setPositionStyle({ left: '50%', transform: 'translateX(-50%)' }); } setShow(!show); }} > {children} {show && (
{content}
)}
); };