Skip to content

Commit cc2c9d6

Browse files
authored
Merge pull request #27 from svelte-plugins/fix-positioning
🐛 fix(position): properly position tooltips with absolute, fixed, and sticky parent elements
2 parents 9c6315c + d1eaf14 commit cc2c9d6

File tree

4 files changed

+71
-48
lines changed

4 files changed

+71
-48
lines changed

docs/package-lock.json

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@svelte-plugins/tooltips",
3-
"version": "2.0.1",
3+
"version": "2.1.0",
44
"license": "MIT",
55
"description": "A simple tooltip action and component designed for Svelte.",
66
"author": "Kieran Boyle (https://github.com/dysfunc)",

src/helpers.js

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,17 @@ export const isElementInViewport = (element, container = null, position) => {
2323
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
2424
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
2525

26-
let isInsideViewport = (
27-
rect.bottom > 0 &&
28-
rect.top < viewportHeight &&
29-
rect.right > 0 &&
30-
rect.left < viewportWidth
31-
);
26+
let isInsideViewport = rect.bottom > 0 && rect.top < viewportHeight && rect.right > 0 && rect.left < viewportWidth;
3227

3328
if (container) {
3429
const containerRect = container.getBoundingClientRect();
3530

3631
if (position === 'top' || position === 'bottom') {
37-
isInsideViewport = (
38-
(containerRect.bottom + containerRect.height) < viewportHeight &&
39-
containerRect.top < viewportHeight
40-
);
32+
isInsideViewport =
33+
containerRect.bottom + containerRect.height < viewportHeight && containerRect.top < viewportHeight;
4134
} else {
42-
isInsideViewport = (
43-
(containerRect.right + containerRect.width) < viewportWidth &&
44-
containerRect.left < viewportWidth
45-
);
35+
isInsideViewport =
36+
containerRect.right + containerRect.width < viewportWidth && containerRect.left < viewportWidth;
4637
}
4738

4839
return isInsideViewport;
@@ -56,25 +47,55 @@ export const computeTooltipPosition = (containerRef, tooltipRef, position, coord
5647
return coords;
5748
}
5849

50+
let cumulativeOffsetTop = 0;
51+
let cumulativeOffsetLeft = 0;
52+
53+
let fixedOffsetTop = 0;
54+
let stickyOffsetTop = 0;
55+
let fixedOffsetLeft = 0;
56+
57+
let currentElement = containerRef;
58+
59+
while (currentElement !== document.body) {
60+
const computedStyle = window.getComputedStyle(currentElement);
61+
const elementPosition = computedStyle.position;
62+
63+
if (elementPosition === 'fixed') {
64+
fixedOffsetTop += currentElement.getBoundingClientRect().top + window.scrollY;
65+
fixedOffsetLeft += currentElement.getBoundingClientRect().left + window.scrollX;
66+
} else if (elementPosition === 'sticky') {
67+
stickyOffsetTop += currentElement.getBoundingClientRect().top;
68+
fixedOffsetLeft += currentElement.getBoundingClientRect().left + window.scrollX;
69+
} else if (elementPosition === 'absolute' || elementPosition === 'relative') {
70+
cumulativeOffsetTop -= parseFloat(computedStyle.top) || 0;
71+
cumulativeOffsetLeft -= parseFloat(computedStyle.left) || 0;
72+
}
73+
74+
currentElement = currentElement.parentElement;
75+
}
76+
5977
const containerRect = containerRef.getBoundingClientRect();
6078
const tooltipRect = tooltipRef.getBoundingClientRect();
6179

80+
let finalTop = containerRect.top + cumulativeOffsetTop + stickyOffsetTop - fixedOffsetTop;
81+
let finalLeft = containerRect.left + cumulativeOffsetLeft - fixedOffsetLeft;
82+
6283
switch (position) {
6384
case 'top':
64-
coords.top = containerRect.top;
65-
coords.left = containerRect.left + (containerRect.width / 2);
85+
coords.top = finalTop;
86+
coords.left = finalLeft + containerRect.width / 2;
6687
break;
6788
case 'bottom':
68-
coords.top = containerRect.top - tooltipRect.height;
69-
coords.left = containerRect.left + (containerRect.width / 2);
89+
coords.top = finalTop - tooltipRect.height;
90+
coords.left = finalLeft + containerRect.width / 2;
7091
break;
7192
case 'left':
72-
coords.left = containerRect.left;
73-
coords.top = containerRect.top + (containerRect.height / 2);
93+
coords.left = finalLeft;
94+
coords.top = finalTop + containerRect.height / 2;
7495
break;
7596
case 'right':
76-
coords.left = containerRect.right - tooltipRect.width;
77-
coords.top = containerRect.top + (containerRect.height / 2);
97+
coords.left = finalLeft + containerRect.width - tooltipRect.width;
98+
coords.top = finalTop + containerRect.height / 2;
7899
break;
79100
}
80101

0 commit comments

Comments
 (0)