Update Tooltip.tsx
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode, useState, useRef, useEffect } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
|
||||||
interface TooltipProps {
|
interface TooltipProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -13,24 +14,95 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
|||||||
placement = "top",
|
placement = "top",
|
||||||
className = "",
|
className = "",
|
||||||
}) => {
|
}) => {
|
||||||
const placementClasses = {
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
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",
|
const triggerRef = useRef<HTMLDivElement>(null);
|
||||||
bottom:
|
const tooltipRef = useRef<HTMLSpanElement>(null);
|
||||||
"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",
|
const getPositionStyle = () => {
|
||||||
right:
|
if (!triggerRef.current) return {};
|
||||||
"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 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 (
|
return (
|
||||||
<div className={`relative group inline-flex ${className}`} style={{ zIndex: 1 }}>
|
<>
|
||||||
{children}
|
<div
|
||||||
<span
|
ref={triggerRef}
|
||||||
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]}`}
|
className={`relative inline-flex ${className}`}
|
||||||
|
onMouseEnter={() => setIsVisible(true)}
|
||||||
|
onMouseLeave={() => setIsVisible(false)}
|
||||||
>
|
>
|
||||||
{text}
|
{children}
|
||||||
</span>
|
</div>
|
||||||
</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
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user