"use client" import * as React from "react" import { cn } from "@/lib/utils" interface TooltipProps { children: React.ReactNode content: React.ReactNode className?: string delayDuration?: number side?: "top" | "right" | "bottom" | "left" } const Tooltip = React.forwardRef( ({ children, content, className, delayDuration = 200, side = "top" }, ref) => { const [isVisible, setIsVisible] = React.useState(false) const [position, setPosition] = React.useState({ top: 0, left: 0 }) const tooltipRef = React.useRef(null) const timeoutRef = React.useRef() const handleMouseEnter = (e: React.MouseEvent) => { timeoutRef.current = setTimeout(() => { const rect = (e.target as HTMLElement).getBoundingClientRect() const tooltipRect = tooltipRef.current?.getBoundingClientRect() if (tooltipRect) { let top = 0 let left = 0 switch (side) { case "top": top = rect.top - tooltipRect.height - 8 left = rect.left + (rect.width - tooltipRect.width) / 2 break case "bottom": top = rect.bottom + 8 left = rect.left + (rect.width - tooltipRect.width) / 2 break case "left": top = rect.top + (rect.height - tooltipRect.height) / 2 left = rect.left - tooltipRect.width - 8 break case "right": top = rect.top + (rect.height - tooltipRect.height) / 2 left = rect.right + 8 break } setPosition({ top, left }) setIsVisible(true) } }, delayDuration) } const handleMouseLeave = () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current) } setIsVisible(false) } React.useEffect(() => { return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current) } } }, []) return (
{children} {isVisible && (
{content}
)}
) }, ) Tooltip.displayName = "Tooltip" // 为了保持 API 兼容性,我们导出相同的组件名称 export const TooltipProvider = ({ children }: { children: React.ReactNode }) => children export const TooltipTrigger = React.forwardRef>((props, ref) => (
)) TooltipTrigger.displayName = "TooltipTrigger" export const TooltipContent = React.forwardRef>((props, ref) => (
)) TooltipContent.displayName = "TooltipContent" export { Tooltip }