diff --git a/src/lib/actions/tooltip.ts b/src/lib/actions/tooltip.ts index 717a342..d1a7b16 100644 --- a/src/lib/actions/tooltip.ts +++ b/src/lib/actions/tooltip.ts @@ -12,6 +12,26 @@ function getTooltipEl(): HTMLDivElement { return tooltipEl; } +function clamp(val: number, min: number, max: number) { + return Math.min(Math.max(val, min), max); +} + +function positionTooltip(el: HTMLDivElement, cx: number, cy: number) { + const margin = 6; + // Start with ideal position: just right of and below cursor + let x = cx + 12; + let y = cy + 16; + // Measure after content is set (element is in DOM, opacity-hidden is fine) + const w = el.offsetWidth; + const h = el.offsetHeight; + // Shift left/right only as much as needed + x = clamp(x, margin, window.innerWidth - w - margin); + // Shift up/down only as much as needed + y = clamp(y, margin, window.innerHeight - h - margin); + el.style.left = `${x}px`; + el.style.top = `${y}px`; +} + export function tooltip(node: HTMLElement, text: string) { let timer: ReturnType | null = null; let currentText = text; @@ -22,8 +42,8 @@ export function tooltip(node: HTMLElement, text: string) { if (!currentText) return; const el = getTooltipEl(); el.textContent = currentText; - el.style.left = `${mouseX + 12}px`; - el.style.top = `${mouseY + 16}px`; + // Position before making visible — offsetWidth/Height valid since el is in DOM + positionTooltip(el, mouseX, mouseY); el.classList.add(TOOLTIP_VISIBLE_CLASS); } @@ -38,8 +58,7 @@ export function tooltip(node: HTMLElement, text: string) { mouseX = e.clientX; mouseY = e.clientY; if (!tooltipEl?.classList.contains(TOOLTIP_VISIBLE_CLASS)) return; - tooltipEl.style.left = `${mouseX + 12}px`; - tooltipEl.style.top = `${mouseY + 16}px`; + positionTooltip(tooltipEl, mouseX, mouseY); } function leave() { @@ -56,6 +75,7 @@ export function tooltip(node: HTMLElement, text: string) { currentText = newText; if (tooltipEl?.classList.contains(TOOLTIP_VISIBLE_CLASS)) { tooltipEl.textContent = newText; + positionTooltip(tooltipEl, mouseX, mouseY); } }, destroy() {