Update Tooltip.tsx

This commit is contained in:
Desktop
2025-11-12 22:34:28 +05:00
parent d254ac3b94
commit 676ac098da

View File

@@ -1,4 +1,5 @@
import { ReactNode } from "react";
import { ReactNode, useState, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
interface TooltipProps {
children: ReactNode;
@@ -13,24 +14,95 @@ export const Tooltip: React.FC<TooltipProps> = ({
placement = "top",
className = "",
}) => {
const placementClasses = {
top: "bottom-full left-1/2 mb-2 -translate-x-1/2 before:top-full before:left-1/2 before:-translate-x-1/2 before:-mt-1 before:border-t-gray-900",
bottom:
"top-full left-1/2 mt-2 -translate-x-1/2 before:bottom-full before:left-1/2 before:-translate-x-1/2 before:-mb-1 before:border-b-gray-900",
left: "right-full top-1/2 mr-2 -translate-y-1/2 before:left-full before:top-1/2 before:-translate-y-1/2 before:-ml-1 before:border-l-gray-900",
right:
"left-full top-1/2 ml-2 -translate-y-1/2 before:right-full before:top-1/2 before:-translate-y-1/2 before:-mr-1 before:border-r-gray-900",
const [isVisible, setIsVisible] = useState(false);
const triggerRef = useRef<HTMLDivElement>(null);
const tooltipRef = useRef<HTMLSpanElement>(null);
const getPositionStyle = () => {
if (!triggerRef.current) return {};
const triggerRect = triggerRef.current.getBoundingClientRect();
let top = 0;
let left = 0;
let transform = "";
switch (placement) {
case "top":
top = triggerRect.top - 8; // Will be adjusted by transform
left = triggerRect.left + triggerRect.width / 2;
transform = "translate(-50%, -100%)";
break;
case "bottom":
top = triggerRect.bottom + 8;
left = triggerRect.left + triggerRect.width / 2;
transform = "translateX(-50%)";
break;
case "left":
top = triggerRect.top + triggerRect.height / 2;
left = triggerRect.left - 8;
transform = "translate(-100%, -50%)";
break;
case "right":
top = triggerRect.top + triggerRect.height / 2;
left = triggerRect.right + 8;
transform = "translateY(-50%)";
break;
}
return {
top: `${top}px`,
left: `${left}px`,
transform,
};
};
useEffect(() => {
if (isVisible && tooltipRef.current) {
// Force a re-render to update position after tooltip is mounted
const timeout = setTimeout(() => {
if (tooltipRef.current) {
tooltipRef.current.style.visibility = 'visible';
}
}, 0);
return () => clearTimeout(timeout);
}
}, [isVisible]);
return (
<div className={`relative group inline-flex ${className}`} style={{ zIndex: 1 }}>
{children}
<span
className={`absolute z-[99999] px-3 py-1.5 text-xs font-medium text-white bg-gray-900 rounded-lg opacity-0 pointer-events-none group-hover:opacity-100 transition-opacity whitespace-nowrap before:absolute before:border-4 before:border-transparent before:content-[''] ${placementClasses[placement]}`}
<>
<div
ref={triggerRef}
className={`relative inline-flex ${className}`}
onMouseEnter={() => setIsVisible(true)}
onMouseLeave={() => setIsVisible(false)}
>
{text}
</span>
</div>
{children}
</div>
{isVisible &&
createPortal(
<span
ref={tooltipRef}
className="fixed z-[999999] px-3 py-1.5 text-xs font-medium text-white bg-gray-900 rounded-lg pointer-events-none whitespace-nowrap"
style={getPositionStyle()}
>
{text}
{/* Arrow */}
<span
className={`absolute ${
placement === "top"
? "top-full left-1/2 -translate-x-1/2 -mt-1 w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-t-[6px] border-t-gray-900"
: placement === "bottom"
? "bottom-full left-1/2 -translate-x-1/2 -mb-1 w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-b-[6px] border-b-gray-900"
: placement === "left"
? "left-full top-1/2 -translate-y-1/2 -ml-1 w-0 h-0 border-t-[6px] border-t-transparent border-b-[6px] border-b-transparent border-l-[6px] border-l-gray-900"
: "right-full top-1/2 -translate-y-1/2 -mr-1 w-0 h-0 border-t-[6px] border-t-transparent border-b-[6px] border-b-transparent border-r-[6px] border-r-gray-900"
}`}
/>
</span>,
document.body
)}
</>
);
};