Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 17x 2x 2x 17x 15x 15x 205x 205x 205x 4x 1x 1x 1x 4x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 205x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 205x 205x 205x 205x 1x 1x | 'use client';
import { useState, ReactNode } from 'react';
import { cn } from '@/lib/core';
export interface TooltipProps {
children: ReactNode;
content: ReactNode;
position?: 'top' | 'bottom' | 'left' | 'right';
className?: string;
delay?: number;
}
/**
* Tooltip - Display additional information on hover
*
* @example
* ```tsx
* <Tooltip content="Rating: 4.5 out of 5">
* <StarRating rating={4.5} />
* </Tooltip>
* ```
*/
export function Tooltip({
children,
content,
position = 'top',
className,
delay = 0,
}: TooltipProps) {
const [isVisible, setIsVisible] = useState(false);
const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout | null>(null);
const showTooltip = () => {
if (delay > 0) {
const id = setTimeout(() => setIsVisible(true), delay);
setTimeoutId(id);
} else {
setIsVisible(true);
}
};
const hideTooltip = () => {
if (timeoutId) {
clearTimeout(timeoutId);
setTimeoutId(null);
}
setIsVisible(false);
};
const positionClasses = {
top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
left: 'right-full top-1/2 -translate-y-1/2 mr-2',
right: 'left-full top-1/2 -translate-y-1/2 ml-2',
};
const arrowClasses = {
top: 'top-full left-1/2 -translate-x-1/2 border-t-gray-900 dark:border-t-gray-700 border-x-transparent border-b-transparent',
bottom: 'bottom-full left-1/2 -translate-x-1/2 border-b-gray-900 dark:border-b-gray-700 border-x-transparent border-t-transparent',
left: 'left-full top-1/2 -translate-y-1/2 border-l-gray-900 dark:border-l-gray-700 border-y-transparent border-r-transparent',
right: 'right-full top-1/2 -translate-y-1/2 border-r-gray-900 dark:border-r-gray-700 border-y-transparent border-l-transparent',
};
return (
<div
className="relative inline-flex"
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
onFocus={showTooltip}
onBlur={hideTooltip}
>
{children}
{isVisible && content && (
<div
role="tooltip"
className={cn(
'absolute z-[100] px-2 py-1 text-xs font-medium text-white bg-gray-900 dark:bg-gray-700 rounded shadow-lg whitespace-nowrap',
positionClasses[position],
className
)}
>
{content}
<span
className={cn(
'absolute w-0 h-0 border-4',
arrowClasses[position]
)}
/>
</div>
)}
</div>
);
}
export default Tooltip;
|