Skip to content

Commit e2242eb

Browse files
committed
Flip popover when needed
1 parent 0dc7913 commit e2242eb

File tree

1 file changed

+52
-9
lines changed

1 file changed

+52
-9
lines changed

src/frontend/src/lib/components/ui/Popover.svelte

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,46 +37,89 @@
3737
3838
$effect(() => {
3939
let tracking = true;
40+
4041
const track = () => {
4142
if (nonNullish(anchorRef) && nonNullish(popoverRef)) {
4243
const anchorRect = anchorRef.getBoundingClientRect();
4344
const popoverRect = popoverRef.getBoundingClientRect();
4445
46+
// Available space around the anchor
47+
const spaceAbove = anchorRect.top;
48+
const spaceBelow = window.innerHeight - anchorRect.bottom;
49+
const spaceLeft = anchorRect.left;
50+
const spaceRight = window.innerWidth - anchorRect.right;
51+
52+
// Determine flipped direction if needed
53+
let finalDirection = direction;
54+
55+
// Vertical flip
56+
if (
57+
direction === "down" &&
58+
spaceBelow < popoverRect.height &&
59+
spaceAbove > spaceBelow
60+
) {
61+
finalDirection = "up";
62+
} else if (
63+
direction === "up" &&
64+
spaceAbove < popoverRect.height &&
65+
spaceBelow > spaceAbove
66+
) {
67+
finalDirection = "down";
68+
}
69+
70+
// Horizontal flip
71+
if (
72+
direction === "right" &&
73+
spaceRight < popoverRect.width &&
74+
spaceLeft > spaceRight
75+
) {
76+
finalDirection = "left";
77+
} else if (
78+
direction === "left" &&
79+
spaceLeft < popoverRect.width &&
80+
spaceRight > spaceLeft
81+
) {
82+
finalDirection = "right";
83+
}
84+
85+
// Compute top position
4586
popoverRef.style.top = {
4687
up: `calc(${anchorRect.top - popoverRect.height}px - ${distance})`,
47-
right: {
88+
down: `calc(${anchorRect.bottom}px + ${distance})`,
89+
left: {
4890
start: `${anchorRect.top}px`,
4991
center: `${anchorRect.top + anchorRect.height * 0.5 - popoverRect.height * 0.5}px`,
5092
end: `${anchorRect.bottom - popoverRect.height}px`,
5193
}[align],
52-
down: `calc(${anchorRect.bottom}px + ${distance})`,
53-
left: {
94+
right: {
5495
start: `${anchorRect.top}px`,
5596
center: `${anchorRect.top + anchorRect.height * 0.5 - popoverRect.height * 0.5}px`,
5697
end: `${anchorRect.bottom - popoverRect.height}px`,
5798
}[align],
58-
}[direction];
99+
}[finalDirection];
59100
101+
// Compute left position
60102
popoverRef.style.left = {
61103
up: {
62104
start: `${anchorRect.left}px`,
63105
center: `${anchorRect.left + anchorRect.width * 0.5 - popoverRect.width * 0.5}px`,
64106
end: `${anchorRect.right - popoverRect.width}px`,
65107
}[align],
66-
right: `calc(${anchorRect.right}px + ${distance})`,
67108
down: {
68109
start: `${anchorRect.left}px`,
69110
center: `${anchorRect.left + anchorRect.width * 0.5 - popoverRect.width * 0.5}px`,
70111
end: `${anchorRect.right - popoverRect.width}px`,
71112
}[align],
72113
left: `calc(${anchorRect.left - popoverRect.width}px - ${distance})`,
73-
}[direction];
74-
}
75-
if (tracking) {
76-
requestAnimationFrame(track);
114+
right: `calc(${anchorRect.right}px + ${distance})`,
115+
}[finalDirection];
77116
}
117+
118+
if (tracking) requestAnimationFrame(track);
78119
};
120+
79121
requestAnimationFrame(track);
122+
80123
return () => {
81124
tracking = false;
82125
};

0 commit comments

Comments
 (0)