Skip to content

Commit 18e7685

Browse files
authored
fix the tooltip position (#547)
1 parent 0b7966f commit 18e7685

File tree

1 file changed

+68
-1
lines changed

1 file changed

+68
-1
lines changed

apps/obsidian/src/utils/tagNodeHandler.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,75 @@ export class TagNodeHandler {
379379
}
380380

381381
let hoverTimeout: number | null = null;
382+
let currentMouseY = 0;
383+
let currentMouseX = 0;
384+
385+
// Track mouse position to determine which part of multi-line tag is hovered
386+
const handleMouseMove = (e: MouseEvent) => {
387+
currentMouseY = e.clientY;
388+
currentMouseX = e.clientX;
389+
390+
// Update tooltip position if it's already visible
391+
if (this.currentTooltip) {
392+
updateTooltipPosition();
393+
}
394+
};
395+
396+
const getClosestRect = (): DOMRect => {
397+
const range = document.createRange();
398+
range.selectNodeContents(tagElement);
399+
const clientRects = range.getClientRects();
400+
401+
if (clientRects.length > 0) {
402+
// If tag spans multiple lines, find the rect closest to mouse position
403+
if (clientRects.length > 1) {
404+
let closestRect: DOMRect | null = null;
405+
let minDistance = Infinity;
406+
407+
for (let i = 0; i < clientRects.length; i++) {
408+
const r = clientRects.item(i);
409+
if (!r) continue;
410+
411+
// Calculate distance from mouse position to center of this rect
412+
const rectCenterY = r.top + r.height / 2;
413+
const rectCenterX = r.left + r.width / 2;
414+
const distanceY = Math.abs(currentMouseY - rectCenterY);
415+
const distanceX = Math.abs(currentMouseX - rectCenterX);
416+
// Weight Y distance more heavily since we care more about vertical proximity
417+
const distance = distanceY * 2 + distanceX;
418+
419+
if (distance < minDistance) {
420+
minDistance = distance;
421+
closestRect = r;
422+
}
423+
}
424+
425+
return (
426+
closestRect ||
427+
clientRects.item(clientRects.length - 1) ||
428+
tagElement.getBoundingClientRect()
429+
);
430+
} else {
431+
// Single line tag - use the only rect
432+
return clientRects.item(0) || tagElement.getBoundingClientRect();
433+
}
434+
}
435+
436+
return tagElement.getBoundingClientRect();
437+
};
438+
439+
const updateTooltipPosition = () => {
440+
if (!this.currentTooltip) return;
441+
442+
const rect = getClosestRect();
443+
this.currentTooltip.style.top = `${rect.top - TOOLTIP_OFFSET}px`;
444+
this.currentTooltip.style.left = `${rect.left + rect.width / 2}px`;
445+
};
382446

383447
const showTooltip = () => {
384448
if (this.currentTooltip) return;
385449

386-
const rect = tagElement.getBoundingClientRect();
450+
const rect = getClosestRect();
387451

388452
this.currentTooltip = document.createElement("div");
389453
this.currentTooltip.className = "discourse-tag-popover";
@@ -443,6 +507,8 @@ export class TagNodeHandler {
443507
hoverTimeout = window.setTimeout(showTooltip, HOVER_DELAY);
444508
});
445509

510+
tagElement.addEventListener("mousemove", handleMouseMove);
511+
446512
tagElement.addEventListener("mouseleave", (e) => {
447513
if (hoverTimeout) {
448514
clearTimeout(hoverTimeout);
@@ -456,6 +522,7 @@ export class TagNodeHandler {
456522
});
457523

458524
const cleanup = () => {
525+
tagElement.removeEventListener("mousemove", handleMouseMove);
459526
if (hoverTimeout) {
460527
clearTimeout(hoverTimeout);
461528
}

0 commit comments

Comments
 (0)