From 1f5d176cf3c53e05bb609331785a2db4904ebf91 Mon Sep 17 00:00:00 2001 From: Konv Suu <2583695112@qq.com> Date: Sat, 2 Aug 2025 23:05:53 +0800 Subject: [PATCH 1/2] Improve tooltip positioning with viewport boundary detection --- src/components/ui/tooltip.tsx | 39 +++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index af9c8410e..37f81b389 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -1,7 +1,7 @@ import type React from "react"; import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; -import { cn } from "../../utils/cn"; +import { cn } from "@/utils/cn"; interface TooltipProps { content: string; @@ -18,9 +18,12 @@ export default function Tooltip({ content, children, side = "top", className }: const timeoutRef = useRef(null); const updatePosition = () => { - if (!triggerRef.current) return; + if (!triggerRef.current || !tooltipRef.current) return; const rect = triggerRef.current.getBoundingClientRect(); + const tooltipRect = tooltipRef.current.getBoundingClientRect(); + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; let x = rect.left; let y = rect.top; @@ -44,6 +47,38 @@ export default function Tooltip({ content, children, side = "top", className }: break; } + if (side === "top" || side === "bottom") { + const tooltipWidth = tooltipRect.width; + + if (x - tooltipWidth / 2 < 8) { + x = tooltipWidth / 2 + 8; + } else if (x + tooltipWidth / 2 > viewportWidth - 8) { + x = viewportWidth - tooltipWidth / 2 - 8; + } + + const tooltipHeight = tooltipRect.height; + if (side === "top" && y - tooltipHeight < 8) { + y = rect.bottom + 8; + } else if (side === "bottom" && y + tooltipHeight > viewportHeight - 8) { + y = rect.top - 8; + } + } else { + const tooltipWidth = tooltipRect.width; + const tooltipHeight = tooltipRect.height; + + if (y - tooltipHeight / 2 < 8) { + y = tooltipHeight / 2 + 8; + } else if (y + tooltipHeight / 2 > viewportHeight - 8) { + y = viewportHeight - tooltipHeight / 2 - 8; + } + + if (side === "left" && x - tooltipWidth < 8) { + x = rect.right + 8; + } else if (side === "right" && x + tooltipWidth > viewportWidth - 8) { + x = rect.left - 8; + } + } + setPosition({ x, y }); }; From 01497ed1680ad6ac723fab29c5e60f0962cc6371 Mon Sep 17 00:00:00 2001 From: Konv Suu <2583695112@qq.com> Date: Sat, 2 Aug 2025 23:25:34 +0800 Subject: [PATCH 2/2] Update --- src/components/ui/tooltip.tsx | 42 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index 37f81b389..9e3e8c5ab 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -17,6 +17,8 @@ export default function Tooltip({ content, children, side = "top", className }: const tooltipRef = useRef(null); const timeoutRef = useRef(null); + const TOOLTIP_MARGIN = 8; + const updatePosition = () => { if (!triggerRef.current || !tooltipRef.current) return; @@ -31,18 +33,18 @@ export default function Tooltip({ content, children, side = "top", className }: switch (side) { case "top": x += rect.width / 2; - y -= 8; + y -= TOOLTIP_MARGIN; break; case "bottom": x += rect.width / 2; - y += rect.height + 8; + y += rect.height + TOOLTIP_MARGIN; break; case "left": - x -= 8; + x -= TOOLTIP_MARGIN; y += rect.height / 2; break; case "right": - x += rect.width + 8; + x += rect.width + TOOLTIP_MARGIN; y += rect.height / 2; break; } @@ -50,32 +52,32 @@ export default function Tooltip({ content, children, side = "top", className }: if (side === "top" || side === "bottom") { const tooltipWidth = tooltipRect.width; - if (x - tooltipWidth / 2 < 8) { - x = tooltipWidth / 2 + 8; - } else if (x + tooltipWidth / 2 > viewportWidth - 8) { - x = viewportWidth - tooltipWidth / 2 - 8; + if (x - tooltipWidth / 2 < TOOLTIP_MARGIN) { + x = tooltipWidth / 2 + TOOLTIP_MARGIN; + } else if (x + tooltipWidth / 2 > viewportWidth - TOOLTIP_MARGIN) { + x = viewportWidth - tooltipWidth / 2 - TOOLTIP_MARGIN; } const tooltipHeight = tooltipRect.height; - if (side === "top" && y - tooltipHeight < 8) { - y = rect.bottom + 8; - } else if (side === "bottom" && y + tooltipHeight > viewportHeight - 8) { - y = rect.top - 8; + if (side === "top" && y - tooltipHeight < TOOLTIP_MARGIN) { + y = rect.bottom + TOOLTIP_MARGIN; + } else if (side === "bottom" && y + tooltipHeight > viewportHeight - TOOLTIP_MARGIN) { + y = rect.top - TOOLTIP_MARGIN; } } else { const tooltipWidth = tooltipRect.width; const tooltipHeight = tooltipRect.height; - if (y - tooltipHeight / 2 < 8) { - y = tooltipHeight / 2 + 8; - } else if (y + tooltipHeight / 2 > viewportHeight - 8) { - y = viewportHeight - tooltipHeight / 2 - 8; + if (y - tooltipHeight / 2 < TOOLTIP_MARGIN) { + y = tooltipHeight / 2 + TOOLTIP_MARGIN; + } else if (y + tooltipHeight / 2 > viewportHeight - TOOLTIP_MARGIN) { + y = viewportHeight - tooltipHeight / 2 - TOOLTIP_MARGIN; } - if (side === "left" && x - tooltipWidth < 8) { - x = rect.right + 8; - } else if (side === "right" && x + tooltipWidth > viewportWidth - 8) { - x = rect.left - 8; + if (side === "left" && x - tooltipWidth < TOOLTIP_MARGIN) { + x = rect.right + TOOLTIP_MARGIN; + } else if (side === "right" && x + tooltipWidth > viewportWidth - TOOLTIP_MARGIN) { + x = rect.left - TOOLTIP_MARGIN; } }