@inizioevoke/astro-core 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as pdfjs from './pdf.min.mjs';
|
|
2
2
|
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
|
3
|
-
import * as ScrollContainer from '../ScrollContainer/
|
|
3
|
+
import * as ScrollContainer from '../ScrollContainer/archive-20260417';
|
|
4
4
|
|
|
5
5
|
pdfjs.GlobalWorkerOptions.workerSrc = './pdf.worker.min.mjs';
|
|
6
6
|
|
|
@@ -1,104 +1,225 @@
|
|
|
1
|
+
export class ScrollContainer {
|
|
2
|
+
#container: HTMLElement;
|
|
3
|
+
#content: HTMLElement;
|
|
4
|
+
#track: HTMLElement;
|
|
5
|
+
#thumb: HTMLElement;
|
|
6
|
+
#isDragging: boolean;
|
|
7
|
+
#startY: number;
|
|
8
|
+
#startScrollTop: number;
|
|
9
|
+
// #enabled: boolean;
|
|
10
|
+
|
|
11
|
+
#mouseupHandler: any = undefined; // [] = [];
|
|
12
|
+
#mousemoveHandler: any = undefined; // [] = [];
|
|
13
|
+
|
|
14
|
+
constructor(container: HTMLElement) { // , { enabled }: { enabled?: boolean } = {}) {
|
|
15
|
+
const _this = this;
|
|
16
|
+
this.#container = container;
|
|
17
|
+
this.#content = container.querySelector('.evo-scroll-content') as HTMLElement;
|
|
18
|
+
this.#track = container.querySelector('.evo-scroll-track') as HTMLElement;
|
|
19
|
+
this.#thumb = container.querySelector('.evo-scroll-thumb') as HTMLElement;
|
|
20
|
+
this.#isDragging = false;
|
|
21
|
+
this.#startY = 0;
|
|
22
|
+
this.#startScrollTop = 0;
|
|
23
|
+
// this.#enabled = enabled ?? true;
|
|
24
|
+
|
|
25
|
+
this.#thumb.addEventListener('mousedown', (e) => {
|
|
26
|
+
_this.#thumbMouseDown(e);
|
|
27
|
+
}, { passive: true });
|
|
28
|
+
|
|
29
|
+
// this.#thumb.addEventListener('mouseup', (e) => {
|
|
30
|
+
// _this.#thumbMouseUp(e);
|
|
31
|
+
// }, { passive: true });
|
|
32
|
+
|
|
33
|
+
this.#content.addEventListener('scroll', () => {
|
|
34
|
+
_this.#scrollContent();
|
|
35
|
+
}, { passive: true });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// enable(flag?: boolean) {
|
|
39
|
+
// this.#enabled = flag ?? true;
|
|
40
|
+
// }
|
|
41
|
+
// get isEnabled() {
|
|
42
|
+
// return this.#enabled === true;
|
|
43
|
+
// }
|
|
44
|
+
|
|
45
|
+
scroll({ left, top, behavior = 'auto' }: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
|
|
46
|
+
const current = this.getScroll();
|
|
47
|
+
if (typeof left == 'string') {
|
|
48
|
+
if (/^[\+\-]=?\d+/.test(left)) {
|
|
49
|
+
left = current.left + parseInt(left.replace(/=/,''), 10);
|
|
50
|
+
} else {
|
|
51
|
+
left = parseInt(left, 10);
|
|
52
|
+
}
|
|
53
|
+
if (isNaN(left)) {
|
|
54
|
+
left = undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (typeof top == 'string') {
|
|
58
|
+
if (/^[\+\-]=?\d+/.test(top)) {
|
|
59
|
+
top = current.top + parseInt(top.replace(/=/,''), 10);
|
|
60
|
+
} else {
|
|
61
|
+
top = parseInt(top, 10);
|
|
62
|
+
}
|
|
63
|
+
if (isNaN(top)) {
|
|
64
|
+
top = undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
left = left ?? current.left;
|
|
68
|
+
top = top ?? current.top;
|
|
69
|
+
if (left < 0) {
|
|
70
|
+
left = 0;
|
|
71
|
+
}
|
|
72
|
+
if (top < 0) {
|
|
73
|
+
top = 0;
|
|
74
|
+
}
|
|
75
|
+
this.#content.scroll({ left: left, top: top, behavior });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getScroll() {
|
|
79
|
+
return {
|
|
80
|
+
left: this.#content.scrollLeft,
|
|
81
|
+
top: this.#content.scrollTop
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
resize({ height }: { height?: number }) {
|
|
86
|
+
if (typeof height == 'number') {
|
|
87
|
+
this.#container.style.height = `${height}px`;
|
|
88
|
+
refresh();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
refresh() {
|
|
93
|
+
this.#updateThumbSize();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
#updateThumbSize() {
|
|
97
|
+
const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
|
|
98
|
+
const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
|
|
99
|
+
const visibleRatio = containerHeight / scrollHeight;
|
|
100
|
+
const thumbHeight = visibleRatio * containerHeight;
|
|
101
|
+
this.#thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
|
|
102
|
+
this.#track.style.display = visibleRatio < 1 ? 'block' : 'none';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#thumbMouseDown(e: MouseEvent) {
|
|
106
|
+
this.#mouseupHandler = this.#mouseDetach.bind(this); // .push(this.#mouseDetach.bind(this));
|
|
107
|
+
this.#mousemoveHandler = this.#thumbMouseMove.bind(this); // .push(this.#thumbMouseMove.bind(this));
|
|
108
|
+
document.addEventListener('mouseup', this.#mouseupHandler, { passive: true }); // this.#mouseupHandler[this.#mouseupHandler.length - 1]);
|
|
109
|
+
document.addEventListener('dragend', this.#mouseupHandler, { passive: true }); // this.#mouseupHandler[this.#mouseupHandler.length - 1]);
|
|
110
|
+
document.addEventListener('mousemove', this.#mousemoveHandler, { passive: true }); // this.#mousemoveHandler[this.#mousemoveHandler.length - 1]);
|
|
111
|
+
this.#isDragging = true;
|
|
112
|
+
this.#startY = e.clientY;
|
|
113
|
+
this.#startScrollTop = this.#content.scrollTop;
|
|
114
|
+
this.#thumb.style.cursor = 'grabbing';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#thumbMouseMove(e: MouseEvent) {
|
|
118
|
+
// console.log(performance.now());
|
|
119
|
+
if (this.#isDragging) {
|
|
120
|
+
const deltaY = e.clientY - this.#startY;
|
|
121
|
+
const scrollRatio =
|
|
122
|
+
(this.#content.scrollHeight - this.#container.clientHeight) /
|
|
123
|
+
(this.#container.clientHeight - this.#thumb.clientHeight);
|
|
124
|
+
this.#content.scrollTop = this.#startScrollTop + deltaY * scrollRatio;
|
|
125
|
+
} else {
|
|
126
|
+
this.#mouseDetach();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// #thumbMouseUp(e: MouseEvent) {
|
|
131
|
+
// this.#isDragging = false;
|
|
132
|
+
// this.#thumb.style.cursor = 'grab';
|
|
133
|
+
// }
|
|
134
|
+
|
|
135
|
+
#mouseDetach() {
|
|
136
|
+
this.#isDragging = false;
|
|
137
|
+
this.#thumb.style.cursor = 'grab';
|
|
138
|
+
document.removeEventListener('mouseup', this.#mouseupHandler);
|
|
139
|
+
document.removeEventListener('dragend', this.#mouseupHandler);
|
|
140
|
+
document.removeEventListener('mousemove', this.#mousemoveHandler);
|
|
141
|
+
// for (const m of this.#mouseupHandler) {
|
|
142
|
+
// document.removeEventListener('mouseup', m);
|
|
143
|
+
// document.removeEventListener('dragend', m);
|
|
144
|
+
// }
|
|
145
|
+
// for (const m of this.#mousemoveHandler) {
|
|
146
|
+
// document.removeEventListener('mousemove', m);
|
|
147
|
+
// }
|
|
148
|
+
// this.#mouseupHandler = [];
|
|
149
|
+
// this.#mousemoveHandler = [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#scrollContent() {
|
|
153
|
+
const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
|
|
154
|
+
const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
|
|
155
|
+
const scrollRatio = this.#content.scrollTop / (scrollHeight - containerHeight);
|
|
156
|
+
const top = scrollRatio * (this.#track.clientHeight - this.#thumb.clientHeight);
|
|
157
|
+
this.#thumb.style.top = `${top}px`;
|
|
158
|
+
}
|
|
1
159
|
|
|
2
|
-
export interface IScrollContainer {
|
|
3
|
-
container: HTMLElement;
|
|
4
|
-
content: HTMLElement;
|
|
5
|
-
track: HTMLElement;
|
|
6
|
-
thumb: HTMLElement;
|
|
7
|
-
isDragging: boolean;
|
|
8
|
-
startY: number;
|
|
9
|
-
startScrollTop: number;
|
|
10
160
|
}
|
|
11
161
|
|
|
12
|
-
export function resize(scrollContainer:
|
|
162
|
+
export function resize(scrollContainer: string | HTMLElement | ScrollContainer, { height }: { height?: number }) {
|
|
13
163
|
if (typeof height == 'number') {
|
|
14
|
-
|
|
15
|
-
|
|
164
|
+
const sc = getScrollContainer(scrollContainer);
|
|
165
|
+
if (sc) {
|
|
166
|
+
sc.resize({ height })
|
|
167
|
+
}
|
|
16
168
|
}
|
|
17
169
|
}
|
|
18
170
|
|
|
19
|
-
export function refresh(scrollContainer?:
|
|
171
|
+
export function refresh(scrollContainer?: string | HTMLElement | ScrollContainer) {
|
|
20
172
|
if (scrollContainer) {
|
|
21
|
-
|
|
173
|
+
const sc = getScrollContainer(scrollContainer);
|
|
174
|
+
if (sc) {
|
|
175
|
+
sc.refresh()
|
|
176
|
+
}
|
|
22
177
|
} else {
|
|
23
178
|
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
24
|
-
|
|
179
|
+
scrollContainer.refresh();
|
|
25
180
|
});
|
|
26
181
|
}
|
|
27
182
|
}
|
|
28
183
|
|
|
29
|
-
export function getScroll(scrollContainer:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
184
|
+
export function getScroll(scrollContainer: string | HTMLElement | ScrollContainer): { left: number, top: number } | undefined {
|
|
185
|
+
const sc = getScrollContainer(scrollContainer);
|
|
186
|
+
if (sc) {
|
|
187
|
+
return sc.getScroll();
|
|
188
|
+
} else {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
34
191
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
192
|
+
|
|
193
|
+
export function scroll(scrollContainer: string | HTMLElement | ScrollContainer, { left, top, behavior = 'auto' }: { left?: number, top?: number, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
|
|
194
|
+
const sc = getScrollContainer(scrollContainer);
|
|
195
|
+
if (sc) {
|
|
196
|
+
const current = sc.getScroll();
|
|
197
|
+
sc.scroll({ left: left ?? current.left, top: top ?? current.top, behavior });
|
|
198
|
+
}
|
|
38
199
|
}
|
|
39
200
|
|
|
40
|
-
export function getScrollContainer(selector: string | HTMLElement):
|
|
201
|
+
export function getScrollContainer(selector: string | HTMLElement | ScrollContainer): ScrollContainer | undefined {
|
|
202
|
+
if (selector instanceof ScrollContainer) {
|
|
203
|
+
return selector;
|
|
204
|
+
}
|
|
41
205
|
const key = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
|
|
42
206
|
return key ? scrollContainers.get(key) : undefined;
|
|
43
207
|
}
|
|
44
208
|
|
|
45
|
-
function thumbMouseDown(scrollContainer: IScrollContainer, e: MouseEvent) {
|
|
46
|
-
scrollContainer.isDragging = true;
|
|
47
|
-
scrollContainer.startY = e.clientY;
|
|
48
|
-
scrollContainer.startScrollTop = scrollContainer.content.scrollTop;
|
|
49
|
-
scrollContainer.thumb.style.cursor = 'grabbing';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function updateThumbSize(scrollContainer: IScrollContainer) {
|
|
53
|
-
const { container, content, thumb, track } = scrollContainer;
|
|
54
|
-
const scrollHeight = content.scrollHeight - getPaddingY(content);
|
|
55
|
-
const containerHeight = container.clientHeight - getPaddingY(container);
|
|
56
|
-
const visibleRatio = containerHeight / scrollHeight;
|
|
57
|
-
const thumbHeight = visibleRatio * containerHeight;
|
|
58
|
-
thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
|
|
59
|
-
track.style.display = visibleRatio < 1 ? 'block' : 'none';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function scrollContent(scrollContainer: IScrollContainer) {
|
|
63
|
-
const { container, content, thumb, track } = scrollContainer;
|
|
64
|
-
const scrollHeight = content.scrollHeight - getPaddingY(content);
|
|
65
|
-
const containerHeight = container.clientHeight - getPaddingY(container);
|
|
66
|
-
const scrollRatio = content.scrollTop / (scrollHeight - containerHeight);
|
|
67
|
-
const top = scrollRatio * (track.clientHeight - thumb.clientHeight);
|
|
68
|
-
thumb.style.top = `${top}px`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
209
|
function getPaddingY(content: HTMLElement): number {
|
|
72
210
|
const style = getComputedStyle(content);
|
|
73
211
|
return parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
|
|
74
212
|
}
|
|
75
213
|
|
|
76
|
-
|
|
77
|
-
let container = element;
|
|
78
|
-
while (container && !container.classList.contains('scroll-container')) {
|
|
79
|
-
container = container.parentElement as HTMLElement;
|
|
80
|
-
}
|
|
81
|
-
return container;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function createScrollContainer(container: HTMLElement): IScrollContainer {
|
|
85
|
-
return {
|
|
86
|
-
container: container,
|
|
87
|
-
content: container.querySelector('.evo-scroll-content') as HTMLElement,
|
|
88
|
-
track: container.querySelector('.evo-scroll-track') as HTMLElement,
|
|
89
|
-
thumb: container.querySelector('.evo-scroll-thumb') as HTMLElement,
|
|
90
|
-
isDragging: false,
|
|
91
|
-
startY: 0,
|
|
92
|
-
startScrollTop: 0
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const scrollContainers = new Map<HTMLElement, IScrollContainer>();
|
|
214
|
+
const scrollContainers = new Map<HTMLElement, ScrollContainer>();
|
|
97
215
|
|
|
98
216
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
|
99
217
|
entries.forEach((entry) => {
|
|
100
218
|
if (entry.isIntersecting) {
|
|
101
|
-
|
|
219
|
+
const sc = getScrollContainer(entry.target as HTMLElement);
|
|
220
|
+
if (sc) {
|
|
221
|
+
sc.refresh();
|
|
222
|
+
}
|
|
102
223
|
}
|
|
103
224
|
});
|
|
104
225
|
},
|
|
@@ -106,45 +227,28 @@ const intersectionObserver = new IntersectionObserver((entries) => {
|
|
|
106
227
|
);
|
|
107
228
|
|
|
108
229
|
const mutationObserver = new MutationObserver((mutations) => {
|
|
109
|
-
const containers
|
|
230
|
+
const containers = new Set<ScrollContainer>();
|
|
110
231
|
mutations.forEach((mutation) => {
|
|
111
|
-
const sc =
|
|
112
|
-
if (sc
|
|
113
|
-
containers.
|
|
232
|
+
const sc = getScrollContainer(mutation.target as HTMLElement);
|
|
233
|
+
if (sc) {
|
|
234
|
+
containers.add(sc);
|
|
114
235
|
}
|
|
115
236
|
});
|
|
116
|
-
containers.forEach((container) => {
|
|
117
|
-
|
|
237
|
+
[...containers].forEach((container) => {
|
|
238
|
+
container.refresh();
|
|
118
239
|
});
|
|
119
240
|
});
|
|
120
241
|
|
|
121
242
|
document.querySelectorAll<HTMLElement>('.evo-scroll-container').forEach((container) => {
|
|
122
|
-
const scrollContainer =
|
|
243
|
+
const scrollContainer = new ScrollContainer(container);
|
|
123
244
|
scrollContainers.set(container, scrollContainer);
|
|
124
|
-
|
|
125
|
-
scrollContainer.content.addEventListener('scroll', (e) => { scrollContent(scrollContainer); }, { passive: true });
|
|
245
|
+
|
|
126
246
|
intersectionObserver.observe(container);
|
|
127
|
-
mutationObserver.observe(container, { childList: true, subtree: true });
|
|
128
|
-
});
|
|
129
|
-
document.addEventListener('mousemove', (e) => {
|
|
130
|
-
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
131
|
-
if (!scrollContainer.isDragging) return;
|
|
132
|
-
const { container, content, thumb } = scrollContainer;
|
|
133
|
-
const deltaY = e.clientY - scrollContainer.startY;
|
|
134
|
-
const scrollRatio =
|
|
135
|
-
(content.scrollHeight - container.clientHeight) /
|
|
136
|
-
(container.clientHeight - thumb.clientHeight);
|
|
137
|
-
scrollContainer.content.scrollTop = scrollContainer.startScrollTop + deltaY * scrollRatio;
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
document.addEventListener('mouseup', () => {
|
|
141
|
-
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
142
|
-
scrollContainer.isDragging = false;
|
|
143
|
-
scrollContainer.thumb.style.cursor = 'grab';
|
|
144
|
-
});
|
|
247
|
+
mutationObserver.observe(container, { attributes: true, childList: true, subtree: true });
|
|
145
248
|
});
|
|
249
|
+
|
|
146
250
|
window.addEventListener('resize', () => {
|
|
147
251
|
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
148
|
-
|
|
252
|
+
scrollContainer.refresh();
|
|
149
253
|
});
|
|
150
254
|
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
|
|
2
|
+
export interface IScrollContainer {
|
|
3
|
+
container: HTMLElement;
|
|
4
|
+
content: HTMLElement;
|
|
5
|
+
track: HTMLElement;
|
|
6
|
+
thumb: HTMLElement;
|
|
7
|
+
isDragging: boolean;
|
|
8
|
+
startY: number;
|
|
9
|
+
startScrollTop: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function resize(scrollContainer: IScrollContainer, { height }: { height?: number }) {
|
|
13
|
+
if (typeof height == 'number') {
|
|
14
|
+
scrollContainer.container.style.height = `${height}px`;
|
|
15
|
+
refresh(scrollContainer);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function refresh(scrollContainer?: IScrollContainer) {
|
|
20
|
+
if (scrollContainer) {
|
|
21
|
+
updateThumbSize(scrollContainer);
|
|
22
|
+
} else {
|
|
23
|
+
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
24
|
+
updateThumbSize(scrollContainer);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getScroll(scrollContainer: IScrollContainer): { left: number, top: number } {
|
|
30
|
+
return {
|
|
31
|
+
left: scrollContainer.content.scrollLeft,
|
|
32
|
+
top: scrollContainer.content.scrollTop
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function scroll(scrollContainer: IScrollContainer, { left, top, behavior = 'auto' }: { left?: number, top?: number, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
|
|
36
|
+
const current = getScroll(scrollContainer);
|
|
37
|
+
scrollContainer.content.scroll({ left: left ?? current.left, top: top ?? current.top, behavior });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getScrollContainer(selector: string | HTMLElement): IScrollContainer | undefined {
|
|
41
|
+
const key = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
|
|
42
|
+
return key ? scrollContainers.get(key) : undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function thumbMouseDown(scrollContainer: IScrollContainer, e: MouseEvent) {
|
|
46
|
+
scrollContainer.isDragging = true;
|
|
47
|
+
scrollContainer.startY = e.clientY;
|
|
48
|
+
scrollContainer.startScrollTop = scrollContainer.content.scrollTop;
|
|
49
|
+
scrollContainer.thumb.style.cursor = 'grabbing';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function updateThumbSize(scrollContainer: IScrollContainer) {
|
|
53
|
+
const { container, content, thumb, track } = scrollContainer;
|
|
54
|
+
const scrollHeight = content.scrollHeight - getPaddingY(content);
|
|
55
|
+
const containerHeight = container.clientHeight - getPaddingY(container);
|
|
56
|
+
const visibleRatio = containerHeight / scrollHeight;
|
|
57
|
+
const thumbHeight = visibleRatio * containerHeight;
|
|
58
|
+
thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
|
|
59
|
+
track.style.display = visibleRatio < 1 ? 'block' : 'none';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function scrollContent(scrollContainer: IScrollContainer) {
|
|
63
|
+
const { container, content, thumb, track } = scrollContainer;
|
|
64
|
+
const scrollHeight = content.scrollHeight - getPaddingY(content);
|
|
65
|
+
const containerHeight = container.clientHeight - getPaddingY(container);
|
|
66
|
+
const scrollRatio = content.scrollTop / (scrollHeight - containerHeight);
|
|
67
|
+
const top = scrollRatio * (track.clientHeight - thumb.clientHeight);
|
|
68
|
+
thumb.style.top = `${top}px`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getPaddingY(content: HTMLElement): number {
|
|
72
|
+
const style = getComputedStyle(content);
|
|
73
|
+
return parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getScrollContainerElement(element: HTMLElement) {
|
|
77
|
+
let container = element;
|
|
78
|
+
while (container && !container.classList.contains('scroll-container')) {
|
|
79
|
+
container = container.parentElement as HTMLElement;
|
|
80
|
+
}
|
|
81
|
+
return container;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function createScrollContainer(container: HTMLElement): IScrollContainer {
|
|
85
|
+
return {
|
|
86
|
+
container: container,
|
|
87
|
+
content: container.querySelector('.evo-scroll-content') as HTMLElement,
|
|
88
|
+
track: container.querySelector('.evo-scroll-track') as HTMLElement,
|
|
89
|
+
thumb: container.querySelector('.evo-scroll-thumb') as HTMLElement,
|
|
90
|
+
isDragging: false,
|
|
91
|
+
startY: 0,
|
|
92
|
+
startScrollTop: 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const scrollContainers = new Map<HTMLElement, IScrollContainer>();
|
|
97
|
+
|
|
98
|
+
const intersectionObserver = new IntersectionObserver((entries) => {
|
|
99
|
+
entries.forEach((entry) => {
|
|
100
|
+
if (entry.isIntersecting) {
|
|
101
|
+
updateThumbSize(scrollContainers.get(entry.target as HTMLElement) as IScrollContainer);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
{ threshold: 0.1 }
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const mutationObserver = new MutationObserver((mutations) => {
|
|
109
|
+
const containers: IScrollContainer[] = [];
|
|
110
|
+
mutations.forEach((mutation) => {
|
|
111
|
+
const sc = scrollContainers.get(getScrollContainerElement(mutation.target as HTMLElement));
|
|
112
|
+
if (sc && !containers.includes(sc)) {
|
|
113
|
+
containers.push(sc);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
containers.forEach((container) => {
|
|
117
|
+
updateThumbSize(container);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
document.querySelectorAll<HTMLElement>('.evo-scroll-container').forEach((container) => {
|
|
122
|
+
const scrollContainer = createScrollContainer(container);
|
|
123
|
+
scrollContainers.set(container, scrollContainer);
|
|
124
|
+
scrollContainer.thumb.addEventListener('mousedown', (e) => { thumbMouseDown(scrollContainer, e); }, { passive: true });
|
|
125
|
+
scrollContainer.content.addEventListener('scroll', (e) => { scrollContent(scrollContainer); }, { passive: true });
|
|
126
|
+
intersectionObserver.observe(container);
|
|
127
|
+
mutationObserver.observe(container, { childList: true, subtree: true });
|
|
128
|
+
});
|
|
129
|
+
document.addEventListener('mousemove', (e) => {
|
|
130
|
+
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
131
|
+
if (!scrollContainer.isDragging) return;
|
|
132
|
+
const { container, content, thumb } = scrollContainer;
|
|
133
|
+
const deltaY = e.clientY - scrollContainer.startY;
|
|
134
|
+
const scrollRatio =
|
|
135
|
+
(content.scrollHeight - container.clientHeight) /
|
|
136
|
+
(container.clientHeight - thumb.clientHeight);
|
|
137
|
+
scrollContainer.content.scrollTop = scrollContainer.startScrollTop + deltaY * scrollRatio;
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
document.addEventListener('mouseup', () => {
|
|
141
|
+
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
142
|
+
scrollContainer.isDragging = false;
|
|
143
|
+
scrollContainer.thumb.style.cursor = 'grab';
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
window.addEventListener('resize', () => {
|
|
147
|
+
[...scrollContainers.values()].forEach((scrollContainer) => {
|
|
148
|
+
updateThumbSize(scrollContainer);
|
|
149
|
+
});
|
|
150
|
+
});
|