enhanced ui
This commit is contained in:
88
frontend/src/components/ui/tooltip/EnhancedTooltip.tsx
Normal file
88
frontend/src/components/ui/tooltip/EnhancedTooltip.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { ReactNode, useState, useRef, useEffect } from "react";
|
||||
|
||||
interface EnhancedTooltipProps {
|
||||
children: ReactNode;
|
||||
content: ReactNode | string;
|
||||
placement?: "top" | "bottom" | "left" | "right";
|
||||
className?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export const EnhancedTooltip: React.FC<EnhancedTooltipProps> = ({
|
||||
children,
|
||||
content,
|
||||
placement = "top",
|
||||
className = "",
|
||||
delay = 200,
|
||||
}) => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [position, setPosition] = useState({ top: 0, left: 0 });
|
||||
const tooltipRef = useRef<HTMLDivElement>(null);
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
const timeoutRef = useRef<NodeJS.Timeout>();
|
||||
|
||||
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 handleMouseEnter = () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setIsVisible(true);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={triggerRef}
|
||||
className={`relative inline-flex ${className}`}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{children}
|
||||
{isVisible && (
|
||||
<div
|
||||
ref={tooltipRef}
|
||||
className={`
|
||||
absolute z-50 px-3 py-2 text-xs font-medium text-white bg-gray-900 rounded-lg
|
||||
opacity-100 pointer-events-none transition-opacity duration-200
|
||||
whitespace-normal max-w-xs shadow-lg
|
||||
before:absolute before:border-4 before:border-transparent before:content-['']
|
||||
${placementClasses[placement]}
|
||||
`}
|
||||
onMouseEnter={() => setIsVisible(true)}
|
||||
onMouseLeave={() => setIsVisible(false)}
|
||||
>
|
||||
{typeof content === "string" ? (
|
||||
<span>{content}</span>
|
||||
) : (
|
||||
<div className="text-white">{content}</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user