diff options
| author | Fuwn <[email protected]> | 2026-04-19 11:04:12 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-04-19 11:04:12 +0000 |
| commit | 28860bb88da4c08e3ba383adc9c23ae3689310b6 (patch) | |
| tree | 4bffd765ca23d412b2065179f4e60993b824ca1a /src/lib/Tooltip/tooltip.ts | |
| parent | Revert "fix(tooltip): park measurement node off-screen to stop body resize" (diff) | |
| download | due.moe-28860bb88da4c08e3ba383adc9c23ae3689310b6.tar.xz due.moe-28860bb88da4c08e3ba383adc9c23ae3689310b6.zip | |
fix(tooltip): use fixed positioning and snappy cursor tracking
Body grew on hover because the absolutely-positioned tooltip was appended to
document.body without top/left, so its static-flow position extended
body.scrollWidth/scrollHeight during layout measurement.
Switch both the use:tooltip directive and LinkedTooltip's measurement div to
position:fixed, which is relative to the viewport and does not contribute to
the body's scroll area. The directive now also uses clientX/clientY (dropping
the scrollY offset for the pin branch), removes the 100ms mousemove debounce,
and drops the top/left transition so the tooltip tracks the cursor without
feeling laggy or sliding in from the page top.
Diffstat (limited to 'src/lib/Tooltip/tooltip.ts')
| -rw-r--r-- | src/lib/Tooltip/tooltip.ts | 22 |
1 files changed, 8 insertions, 14 deletions
diff --git a/src/lib/Tooltip/tooltip.ts b/src/lib/Tooltip/tooltip.ts index 5772c33f..8c846a78 100644 --- a/src/lib/Tooltip/tooltip.ts +++ b/src/lib/Tooltip/tooltip.ts @@ -3,9 +3,7 @@ const tooltip = (element: HTMLElement) => { const offset = 10; const tooltipTransitionTime = 200; const tooltipHideDelay = 10; - const debounceDelay = 100; let hideTimeout: number | null = null; - let debounceTimer: number | null = null; if (element.dataset.tooltipDisable === "true") return; @@ -13,13 +11,14 @@ const tooltip = (element: HTMLElement) => { if (!tooltipDiv) { tooltipDiv = document.createElement("div"); - tooltipDiv.style.position = "absolute"; + tooltipDiv.style.position = "fixed"; + tooltipDiv.style.top = "-9999px"; + tooltipDiv.style.left = "-9999px"; tooltipDiv.style.zIndex = "1000"; tooltipDiv.style.opacity = "0"; - tooltipDiv.style.transition = `opacity ${tooltipTransitionTime}ms ease-in-out, top 0.3s ease, left 0.3s ease`; + tooltipDiv.style.transition = `opacity ${tooltipTransitionTime}ms ease-in-out`; tooltipDiv.style.pointerEvents = "none"; tooltipDiv.style.whiteSpace = "nowrap"; - tooltipDiv.style.zIndex = "1000"; tooltipDiv.classList.add("card"); tooltipDiv.classList.add("card-small"); @@ -47,7 +46,7 @@ const tooltip = (element: HTMLElement) => { if (top < 0) top = rect.top + rect.height + offset; tooltipDiv.style.left = `${left}px`; - tooltipDiv.style.top = `${top + window.scrollY}px`; + tooltipDiv.style.top = `${top}px`; return; } @@ -116,18 +115,14 @@ const tooltip = (element: HTMLElement) => { } if (!tooltipDiv) { - showTooltip(title, event.pageX, event.pageY); + showTooltip(title, event.clientX, event.clientY); } } }; const handleMouseMove = (event: MouseEvent) => { - if (debounceTimer !== null) clearTimeout(debounceTimer); - - debounceTimer = window.setTimeout(() => { - if (tooltipDiv && tooltipDiv.style.opacity === "1") - updateTooltipPosition(event.pageX, event.pageY); - }, debounceDelay); + if (tooltipDiv && tooltipDiv.style.opacity === "1") + updateTooltipPosition(event.clientX, event.clientY); }; const handleMouseLeave = () => { @@ -149,7 +144,6 @@ const tooltip = (element: HTMLElement) => { element.removeEventListener("mouseleave", handleMouseLeave); if (hideTimeout !== null) clearTimeout(hideTimeout); - if (debounceTimer !== null) clearTimeout(debounceTimer); if (tooltipDiv && document.body.contains(tooltipDiv)) { document.body.removeChild(tooltipDiv); |