Skip to content

Commit 7f37c7a

Browse files
committed
chore: refactor progress bar logic with improved scroll handling, resize observer, and navigation cleanup
1 parent 02057a3 commit 7f37c7a

1 file changed

Lines changed: 44 additions & 52 deletions

File tree

resources/ts/progress-bar.ts

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,53 @@
11
declare global {
22
interface Window {
3-
setupProgressBar: Function;
3+
setupProgressBar: (section: HTMLElement, progressBar: HTMLElement) => void;
44
}
55
}
66

7-
function progressBarAnimation(
8-
section: HTMLElement,
9-
progressBar: HTMLElement,
10-
): void {
11-
let scrollDistance: number = -section.getBoundingClientRect().top;
12-
let progressWidth: number =
13-
(scrollDistance /
14-
(section.getBoundingClientRect().height -
15-
document.documentElement.clientHeight)) *
16-
100;
17-
18-
let value: number = Math.floor(progressWidth);
19-
20-
progressBar.style.width = value + '%';
21-
progressBar.ariaValueNow = value.toString();
22-
23-
if (value < 0) {
24-
progressBar.style.width = '0%';
25-
progressBar.ariaValueNow = '0';
26-
}
7+
function updateProgress(section: HTMLElement, progressBar: HTMLElement): void {
8+
const rect = section.getBoundingClientRect();
9+
const scrollable = rect.height - document.documentElement.clientHeight;
10+
const raw = scrollable > 0 ? (-rect.top / scrollable) * 100 : 100;
11+
const value = Math.max(0, Math.min(100, Math.floor(raw) || 0));
2712

28-
if (value > 100) {
29-
progressBar.style.width = '100%';
30-
progressBar.ariaValueNow = '100';
31-
}
13+
progressBar.style.width = `${value}%`;
14+
progressBar.ariaValueNow = String(value);
3215
}
3316

34-
window.setupProgressBar = function (
35-
section: HTMLElement,
36-
progressBar: HTMLElement,
37-
): void {
38-
if (
39-
document.documentElement.clientHeight >
40-
section.getBoundingClientRect().height
41-
) {
42-
progressBar.style.width = '100%';
43-
progressBar.ariaValueNow = '100';
44-
45-
return;
46-
}
47-
48-
const updateProgressBar = () => progressBarAnimation(section, progressBar);
49-
50-
window.addEventListener('scroll', updateProgressBar);
51-
52-
function clearProgressBarEvent() {
53-
window.removeEventListener('scroll', updateProgressBar);
54-
window.removeEventListener(
55-
'livewire:navigating',
56-
clearProgressBarEvent,
57-
);
58-
}
59-
60-
window.addEventListener('livewire:navigating', clearProgressBarEvent);
17+
window.setupProgressBar = function (section, progressBar) {
18+
let scrollAttached = false;
19+
const onScroll = () => updateProgress(section, progressBar);
20+
21+
const sync = () => {
22+
const sectionHeight = section.getBoundingClientRect().height;
23+
if (sectionHeight <= 0) return;
24+
25+
if (document.documentElement.clientHeight >= sectionHeight) {
26+
progressBar.style.width = '100%';
27+
progressBar.ariaValueNow = '100';
28+
if (scrollAttached) {
29+
document.removeEventListener('scroll', onScroll);
30+
scrollAttached = false;
31+
}
32+
return;
33+
}
34+
35+
if (!scrollAttached) {
36+
document.addEventListener('scroll', onScroll, { passive: true });
37+
scrollAttached = true;
38+
}
39+
updateProgress(section, progressBar);
40+
};
41+
42+
const observer = new ResizeObserver(sync);
43+
observer.observe(section);
44+
window.addEventListener('resize', sync);
45+
46+
document.addEventListener('livewire:navigating', () => {
47+
observer.disconnect();
48+
window.removeEventListener('resize', sync);
49+
if (scrollAttached) {
50+
document.removeEventListener('scroll', onScroll);
51+
}
52+
}, { once: true });
6153
};

0 commit comments

Comments
 (0)