tududi/frontend/components/Shared/Tooltip.tsx
Chris e3dcb49efa
Fix bug 661 (#682)
* Limit project card text length

* Fix projects issues

* fixup! Fix projects issues
2025-12-08 16:14:10 +02:00

75 lines
2 KiB
TypeScript

import React, { useEffect, useRef, useState } from 'react';
interface TooltipProps {
content: React.ReactNode;
children: React.ReactNode;
className?: string;
position?: 'top' | 'bottom';
}
const Tooltip: React.FC<TooltipProps> = ({
content,
children,
className = '',
position = 'top',
}) => {
const [isVisible, setIsVisible] = useState(false);
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const delay = 300;
if (!content) {
return <span className={className}>{children}</span>;
}
const positionClasses =
position === 'top'
? 'bottom-full mb-2 origin-bottom'
: 'top-full mt-2 origin-top';
const visibilityClasses = isVisible
? 'opacity-100 scale-100'
: 'pointer-events-none opacity-0 scale-95';
const showWithDelay = () => {
timerRef.current = setTimeout(() => {
setIsVisible(true);
}, delay);
};
const hideTooltip = () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
setIsVisible(false);
};
useEffect(
() => () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
},
[]
);
return (
<span
className={`relative inline-flex ${className}`}
onMouseEnter={showWithDelay}
onMouseLeave={hideTooltip}
onFocus={showWithDelay}
onBlur={hideTooltip}
>
{children}
<span
role="tooltip"
className={`absolute left-1/2 z-20 -translate-x-1/2 whitespace-pre-line rounded-md bg-gray-900 px-3 py-2 text-xs font-medium text-white shadow-2xl transition-all duration-150 ease-out dark:bg-gray-800 ${positionClasses} ${visibilityClasses}`}
>
{content}
</span>
</span>
);
};
export default Tooltip;