Skip to content

Commit 0dc19a3

Browse files
committed
fix(pat scroll-marker): Use the correct scroll container.
The scroll container was potentially wrong and is a parent of the hash-link target contents and not a parent of the navigation where pat-scrol-container (or pat-navigation) are defined upon.
1 parent fcbdabb commit 0dc19a3

File tree

2 files changed

+134
-8
lines changed

2 files changed

+134
-8
lines changed

src/pat/scroll-marker/scroll-marker.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ class Pattern extends BasePattern {
5050
)
5151
);
5252

53-
this.scroll_container = dom.find_scroll_container(this.el, "y", window);
53+
// Find a possible scroll container based on the first target/content
54+
// element in the observables map.
55+
// Note, a Map's values method returns an iterator.
56+
const first_target = this.observables.values().next()?.value.target;
57+
this.scroll_container = dom.find_scroll_container(first_target, "y", window);
5458
// window.innerHeight or el.clientHeight
5559
const scroll_container_height =
5660
typeof this.scroll_container.innerHeight !== "undefined"

src/pat/scroll-marker/scroll-marker.test.js

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,35 @@ import Pattern from "./scroll-marker";
22
import events from "../../core/events";
33
import utils from "../../core/utils";
44

5-
async function create_scroll_marker({ options = {} } = {}) {
5+
async function create_scroll_marker({
6+
options = {},
7+
scroll_container_main = false,
8+
} = {}) {
69
document.body.innerHTML = `
710
<nav class="pat-scroll-marker">
811
<a href="#id1">link 1</a>
912
<a href="#id2">link 2</a>
1013
<a href="#id3">link 3</a>
1114
</nav>
1215
13-
<section id="id1">
14-
</section>
16+
<main>
17+
<section id="id1">
18+
</section>
1519
16-
<section id="id2">
17-
</section>
20+
<section id="id2">
21+
</section>
1822
19-
<section id="id3">
20-
</section>
23+
<section id="id3">
24+
</section>
25+
</main>
2126
`;
2227
const el = document.querySelector(".pat-scroll-marker");
2328

29+
const main = document.querySelector("main");
30+
if (scroll_container_main) {
31+
main.style["overflow-y"] = "auto";
32+
}
33+
2434
const nav_id1 = document.querySelector("[href='#id1']");
2535
const nav_id2 = document.querySelector("[href='#id2']");
2636
const nav_id3 = document.querySelector("[href='#id3']");
@@ -31,6 +41,14 @@ async function create_scroll_marker({ options = {} } = {}) {
3141

3242
// id1 not, id2 fully, id3 partly visible
3343

44+
jest.spyOn(main, "clientHeight", "get").mockReturnValue(100);
45+
jest.spyOn(main, "getBoundingClientRect").mockImplementation(() => {
46+
return {
47+
top: 0,
48+
bottom: 100,
49+
};
50+
});
51+
3452
jest.replaceProperty(window, "innerHeight", 100);
3553
jest.spyOn(id1, "getBoundingClientRect").mockImplementation(() => {
3654
return {
@@ -72,6 +90,7 @@ async function create_scroll_marker({ options = {} } = {}) {
7290
id1: id1,
7391
id2: id2,
7492
id3: id3,
93+
main: main,
7594
};
7695
}
7796

@@ -177,4 +196,107 @@ describe("pat-scroll-marker", () => {
177196
expect(id3.classList.contains("scroll-marker-current")).toBe(false);
178197
});
179198
});
199+
200+
describe("2: Test on element as scroll container", () => {
201+
it("2.1: default values, id3 is current", async () => {
202+
// With the default values the baseline is in the middle and the
203+
// content element side's are calculated from the top. id3 is therefore
204+
// the current one, as it's top is nearer to the middle than the top of
205+
// id2.
206+
207+
const { instance, nav_id1, nav_id2, nav_id3, id1, id2, id3, main } =
208+
await create_scroll_marker({ scroll_container_main: true });
209+
210+
// Without any overflow settings in other containers, the scroll
211+
// container is the window object.
212+
expect(instance.scroll_container).toBe(main);
213+
214+
expect(nav_id1.classList.contains("in-view")).toBe(false);
215+
expect(nav_id2.classList.contains("in-view")).toBe(true);
216+
expect(nav_id3.classList.contains("in-view")).toBe(true);
217+
218+
expect(nav_id1.classList.contains("current")).toBe(false);
219+
expect(nav_id2.classList.contains("current")).toBe(false);
220+
expect(nav_id3.classList.contains("current")).toBe(true);
221+
222+
expect(id1.classList.contains("scroll-marker-current")).toBe(false);
223+
expect(id2.classList.contains("scroll-marker-current")).toBe(false);
224+
expect(id3.classList.contains("scroll-marker-current")).toBe(true);
225+
});
226+
227+
it("2.2: distance 0, id2 is current", async () => {
228+
const { nav_id1, nav_id2, nav_id3, id1, id2, id3 } =
229+
await create_scroll_marker({
230+
options: {
231+
distance: 0,
232+
},
233+
scroll_container_main: true,
234+
});
235+
236+
expect(nav_id1.classList.contains("in-view")).toBe(false);
237+
expect(nav_id2.classList.contains("in-view")).toBe(true);
238+
expect(nav_id3.classList.contains("in-view")).toBe(true);
239+
240+
expect(nav_id1.classList.contains("current")).toBe(false);
241+
expect(nav_id2.classList.contains("current")).toBe(true);
242+
expect(nav_id3.classList.contains("current")).toBe(false);
243+
244+
expect(id1.classList.contains("scroll-marker-current")).toBe(false);
245+
expect(id2.classList.contains("scroll-marker-current")).toBe(true);
246+
expect(id3.classList.contains("scroll-marker-current")).toBe(false);
247+
});
248+
249+
it("2.3: distance 50, side bottom, id2 is current", async () => {
250+
const { nav_id1, nav_id2, nav_id3, id1, id2, id3 } =
251+
await create_scroll_marker({
252+
options: {
253+
distance: "50%",
254+
side: "bottom",
255+
},
256+
scroll_container_main: true,
257+
});
258+
259+
expect(nav_id1.classList.contains("in-view")).toBe(false);
260+
expect(nav_id2.classList.contains("in-view")).toBe(true);
261+
expect(nav_id3.classList.contains("in-view")).toBe(true);
262+
263+
expect(nav_id1.classList.contains("current")).toBe(false);
264+
expect(nav_id2.classList.contains("current")).toBe(true);
265+
expect(nav_id3.classList.contains("current")).toBe(false);
266+
267+
expect(id1.classList.contains("scroll-marker-current")).toBe(false);
268+
expect(id2.classList.contains("scroll-marker-current")).toBe(true);
269+
expect(id3.classList.contains("scroll-marker-current")).toBe(false);
270+
});
271+
272+
it("2.4: distance 50, side top, visibility: most-visible, id2 is current", async () => {
273+
// Here we have again the default values, this time explicitly set.
274+
// Only the visibility is set to most-visible, which means that id2 is
275+
// the current one,
276+
//
277+
const { nav_id1, nav_id2, nav_id3, id1, id2, id3 } =
278+
await create_scroll_marker({
279+
options: {
280+
distance: "50%",
281+
side: "top",
282+
visibility: "most-visible",
283+
},
284+
scroll_container_main: true,
285+
});
286+
287+
console.log(document.body.innerHTML);
288+
289+
expect(nav_id1.classList.contains("in-view")).toBe(false);
290+
expect(nav_id2.classList.contains("in-view")).toBe(true);
291+
expect(nav_id3.classList.contains("in-view")).toBe(true);
292+
293+
expect(nav_id1.classList.contains("current")).toBe(false);
294+
expect(nav_id2.classList.contains("current")).toBe(true);
295+
expect(nav_id3.classList.contains("current")).toBe(false);
296+
297+
expect(id1.classList.contains("scroll-marker-current")).toBe(false);
298+
expect(id2.classList.contains("scroll-marker-current")).toBe(true);
299+
expect(id3.classList.contains("scroll-marker-current")).toBe(false);
300+
});
301+
});
180302
});

0 commit comments

Comments
 (0)