From 676ac098daa068cbe946fc2fb34c9d10bff6f383 Mon Sep 17 00:00:00 2001 From: Desktop Date: Wed, 12 Nov 2025 22:34:28 +0500 Subject: [PATCH] Update Tooltip.tsx --- .../src/components/ui/tooltip/Tooltip.tsx | 102 +++++++++++++++--- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/ui/tooltip/Tooltip.tsx b/frontend/src/components/ui/tooltip/Tooltip.tsx index 2e549182..47d2e58c 100644 --- a/frontend/src/components/ui/tooltip/Tooltip.tsx +++ b/frontend/src/components/ui/tooltip/Tooltip.tsx @@ -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 = ({ 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(null); + const tooltipRef = useRef(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 ( -
- {children} - +
setIsVisible(true)} + onMouseLeave={() => setIsVisible(false)} > - {text} - -
+ {children} +
+ {isVisible && + createPortal( + + {text} + {/* Arrow */} + + , + document.body + )} + ); };