Skip to content

Commit 331edab

Browse files
committed
Use setTimeout instead of requestAnimationFrame to fix auto-position issue
1 parent 88bd96b commit 331edab

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

src/packages/tour/position.cy.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
describe("Intro.js tooltip position with scrollable container", () => {
2+
beforeEach(() => {
3+
cy.visit("./cypress/setup/index.html");
4+
5+
// Add scrollable container and target element dynamically
6+
cy.document().then((doc) => {
7+
const container = doc.createElement("div");
8+
container.id = "scrollable-container";
9+
container.style.cssText =
10+
"height: 600px; overflow-y: auto; border: 2px solid gray; margin-bottom: 20px;";
11+
12+
const inner = doc.createElement("div");
13+
inner.style.height = "1000px";
14+
inner.style.position = "relative";
15+
16+
const target = doc.createElement("div");
17+
target.id = "target-element";
18+
target.style.cssText =
19+
"margin-top: 800px; background-color: yellow; padding: 10px;";
20+
target.setAttribute("data-intro", "Scrollable test element");
21+
target.textContent = "Step Element (scrollable test)";
22+
23+
inner.appendChild(target);
24+
container.appendChild(inner);
25+
doc.body.prepend(container);
26+
27+
// Add start tour button
28+
let btn = doc.getElementById("start-tour");
29+
if (!btn) {
30+
btn = doc.createElement("button");
31+
btn.id = "start-tour";
32+
btn.textContent = "Start Tour";
33+
btn.style.display = "block";
34+
btn.className = "btn btn-success mb-4";
35+
doc.body.prepend(btn);
36+
}
37+
});
38+
39+
// Inject Intro.js script and initialize tour
40+
cy.window().then((win) => {
41+
return new Promise((resolve) => {
42+
const script = win.document.createElement("script");
43+
script.src = "https://unpkg.com/intro.js/minified/intro.min.js";
44+
script.onload = () => {
45+
const tour = win.introJs.tour();
46+
tour.setOptions({
47+
steps: [
48+
{ element: "#target-element", intro: "Scrollable test tooltip" },
49+
{
50+
element: "#target-element",
51+
intro: "Scrollable test tooltip 2",
52+
},
53+
],
54+
scrollToElement: true,
55+
scrollTo: "element",
56+
tooltipPosition: "bottom",
57+
});
58+
win.__testTour = tour;
59+
resolve();
60+
};
61+
win.document.head.appendChild(script);
62+
});
63+
});
64+
});
65+
66+
it("scrolls and ensures tooltip is correctly positioned near target", () => {
67+
// Scroll target into view within the container
68+
cy.get("#scrollable-container").scrollTo("top");
69+
cy.get("#target-element")
70+
.scrollIntoView({ block: "center" })
71+
.should("be.visible");
72+
73+
// Start the tour
74+
cy.window().then((win) => {
75+
win.__testTour.start();
76+
});
77+
78+
// Wait for tooltip
79+
cy.get(".introjs-tooltip", { timeout: 5000 }).should("be.visible");
80+
81+
// Verify tooltip placement
82+
cy.get("#target-element").then(($target) => {
83+
const targetRect = $target[0].getBoundingClientRect();
84+
85+
cy.get(".introjs-tooltip").then(($tooltip) => {
86+
const tooltipRect = $tooltip[0].getBoundingClientRect();
87+
88+
cy.log("Target Rect:", JSON.stringify(targetRect));
89+
cy.log("Tooltip Rect:", JSON.stringify(tooltipRect));
90+
91+
// Ensure not overlapping
92+
const horizontallySeparate =
93+
tooltipRect.right < targetRect.left ||
94+
tooltipRect.left > targetRect.right;
95+
const verticallySeparate =
96+
tooltipRect.bottom < targetRect.top ||
97+
tooltipRect.top > targetRect.bottom;
98+
expect(horizontallySeparate || verticallySeparate).to.be.true;
99+
100+
// Ensure tooltip is close to target (±10px tolerance)
101+
const verticalDistance = Math.min(
102+
Math.abs(tooltipRect.top - targetRect.bottom),
103+
Math.abs(targetRect.top - tooltipRect.bottom)
104+
);
105+
expect(verticalDistance).to.be.lessThan(15);
106+
});
107+
});
108+
});
109+
});

src/packages/tour/position.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ export const setPositionRelativeToStep = (
1111
step: TourStep,
1212
padding: number
1313
) => {
14-
requestAnimationFrame(() => {
14+
setTimeout(() => {
1515
setPositionRelativeTo(
1616
relativeElement,
1717
element,
1818
step.element as HTMLElement,
1919
step.position === "floating" ? 0 : padding
2020
);
21-
});
21+
}, 0);
2222
};

0 commit comments

Comments
 (0)