@inizioevoke/astro-core 1.2.0 → 1.3.1

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
  {
2
2
  "name": "@inizioevoke/astro-core",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -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/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,207 @@
1
-
2
1
  export interface IScrollContainer {
3
- container: HTMLElement;
4
- content: HTMLElement;
5
- track: HTMLElement;
6
- thumb: HTMLElement;
7
- isDragging: boolean;
8
- startY: number;
9
- startScrollTop: number;
2
+ scroll(args?: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' }): void;
3
+ getScroll(): { left: number, top: number }
4
+ resize(args: { height?: number }): void;
5
+ refresh(): void;
10
6
  }
7
+ export class ScrollContainer implements IScrollContainer {
8
+ #container: HTMLElement;
9
+ #content: HTMLElement;
10
+ #track: HTMLElement;
11
+ #thumb: HTMLElement;
12
+ #isDragging: boolean;
13
+ #startY: number;
14
+ #startScrollTop: number;
15
+
16
+ #mouseupHandler: any = undefined;
17
+ #mousemoveHandler: any = undefined;
18
+
19
+ constructor(container: HTMLElement) {
20
+ const _this = this;
21
+ this.#container = container;
22
+ this.#content = container.querySelector('.evo-scroll-content') as HTMLElement;
23
+ this.#track = container.querySelector('.evo-scroll-track') as HTMLElement;
24
+ this.#thumb = container.querySelector('.evo-scroll-thumb') as HTMLElement;
25
+ this.#isDragging = false;
26
+ this.#startY = 0;
27
+ this.#startScrollTop = 0;
28
+ // this.#enabled = enabled ?? true;
29
+
30
+ this.#thumb.addEventListener('mousedown', (e) => {
31
+ _this.#thumbMouseDown(e);
32
+ }, { passive: true });
33
+
34
+ // this.#thumb.addEventListener('mouseup', (e) => {
35
+ // _this.#thumbMouseUp(e);
36
+ // }, { passive: true });
37
+
38
+ this.#content.addEventListener('scroll', () => {
39
+ _this.#scrollContent();
40
+ }, { passive: true });
41
+ }
42
+
43
+ scroll({ left, top, behavior = 'auto' }: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
44
+ const current = this.getScroll();
45
+ if (typeof left == 'string') {
46
+ if (/^[\+\-]=?\d+/.test(left)) {
47
+ left = current.left + parseInt(left.replace(/=/,''), 10);
48
+ } else {
49
+ left = parseInt(left, 10);
50
+ }
51
+ if (isNaN(left)) {
52
+ left = undefined;
53
+ }
54
+ }
55
+ if (typeof top == 'string') {
56
+ if (/^[\+\-]=?\d+/.test(top)) {
57
+ top = current.top + parseInt(top.replace(/=/,''), 10);
58
+ } else {
59
+ top = parseInt(top, 10);
60
+ }
61
+ if (isNaN(top)) {
62
+ top = undefined;
63
+ }
64
+ }
65
+ left = left ?? current.left;
66
+ top = top ?? current.top;
67
+ if (left < 0) {
68
+ left = 0;
69
+ }
70
+ if (top < 0) {
71
+ top = 0;
72
+ }
73
+ this.#content.scroll({ left: left, top: top, behavior });
74
+ }
11
75
 
12
- export function resize(scrollContainer: IScrollContainer, { height }: { height?: number }) {
76
+ getScroll() {
77
+ return {
78
+ left: this.#content.scrollLeft,
79
+ top: this.#content.scrollTop
80
+ };
81
+ }
82
+
83
+ resize({ height }: { height?: number }) {
84
+ if (typeof height == 'number') {
85
+ this.#container.style.height = `${height}px`;
86
+ refresh();
87
+ }
88
+ }
89
+
90
+ refresh() {
91
+ this.#updateThumbSize();
92
+ }
93
+
94
+ #updateThumbSize() {
95
+ const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
96
+ const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
97
+ const visibleRatio = containerHeight / scrollHeight;
98
+ const thumbHeight = visibleRatio * containerHeight;
99
+ this.#thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
100
+ this.#track.style.display = visibleRatio < 1 ? 'block' : 'none';
101
+ }
102
+
103
+ #thumbMouseDown(e: MouseEvent) {
104
+ this.#mouseupHandler = this.#mouseDetach.bind(this);
105
+ this.#mousemoveHandler = this.#thumbMouseMove.bind(this);
106
+ document.addEventListener('mouseup', this.#mouseupHandler, { passive: true });
107
+ document.addEventListener('dragend', this.#mouseupHandler, { passive: true });
108
+ document.addEventListener('mousemove', this.#mousemoveHandler, { passive: true });
109
+ this.#isDragging = true;
110
+ this.#startY = e.clientY;
111
+ this.#startScrollTop = this.#content.scrollTop;
112
+ this.#thumb.style.cursor = 'grabbing';
113
+ }
114
+
115
+ #thumbMouseMove(e: MouseEvent) {
116
+ if (this.#isDragging) {
117
+ const deltaY = e.clientY - this.#startY;
118
+ const scrollRatio =
119
+ (this.#content.scrollHeight - this.#container.clientHeight) /
120
+ (this.#container.clientHeight - this.#thumb.clientHeight);
121
+ this.#content.scrollTop = this.#startScrollTop + deltaY * scrollRatio;
122
+ } else {
123
+ this.#mouseDetach();
124
+ }
125
+ }
126
+
127
+ #mouseDetach() {
128
+ this.#isDragging = false;
129
+ this.#thumb.style.cursor = 'grab';
130
+ document.removeEventListener('mouseup', this.#mouseupHandler);
131
+ document.removeEventListener('dragend', this.#mouseupHandler);
132
+ document.removeEventListener('mousemove', this.#mousemoveHandler);
133
+ }
134
+
135
+ #scrollContent() {
136
+ const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
137
+ const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
138
+ const scrollRatio = this.#content.scrollTop / (scrollHeight - containerHeight);
139
+ const top = scrollRatio * (this.#track.clientHeight - this.#thumb.clientHeight);
140
+ this.#thumb.style.top = `${top}px`;
141
+ }
142
+ }
143
+
144
+ export function resize(scrollContainer: string | HTMLElement | ScrollContainer, { height }: { height?: number }) {
13
145
  if (typeof height == 'number') {
14
- scrollContainer.container.style.height = `${height}px`;
15
- refresh(scrollContainer);
146
+ const sc = getScrollContainer(scrollContainer);
147
+ if (sc) {
148
+ sc.resize({ height })
149
+ }
16
150
  }
17
151
  }
18
152
 
19
- export function refresh(scrollContainer?: IScrollContainer) {
153
+ export function refresh(scrollContainer?: string | HTMLElement | ScrollContainer) {
20
154
  if (scrollContainer) {
21
- updateThumbSize(scrollContainer);
155
+ const sc = getScrollContainer(scrollContainer);
156
+ if (sc) {
157
+ sc.refresh()
158
+ }
22
159
  } else {
23
160
  [...scrollContainers.values()].forEach((scrollContainer) => {
24
- updateThumbSize(scrollContainer);
161
+ scrollContainer.refresh();
25
162
  });
26
163
  }
27
164
  }
28
165
 
29
- export function getScroll(scrollContainer: IScrollContainer): { left: number, top: number } {
30
- return {
31
- left: scrollContainer.content.scrollLeft,
32
- top: scrollContainer.content.scrollTop
33
- };
166
+ export function getScroll(scrollContainer: string | HTMLElement | ScrollContainer): { left: number, top: number } | undefined {
167
+ const sc = getScrollContainer(scrollContainer);
168
+ if (sc) {
169
+ return sc.getScroll();
170
+ } else {
171
+ return undefined;
172
+ }
34
173
  }
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 });
174
+
175
+ export function scroll(scrollContainer: string | HTMLElement | ScrollContainer, { left, top, behavior = 'auto' }: { left?: number, top?: number, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
176
+ const sc = getScrollContainer(scrollContainer);
177
+ if (sc) {
178
+ const current = sc.getScroll();
179
+ sc.scroll({ left: left ?? current.left, top: top ?? current.top, behavior });
180
+ }
38
181
  }
39
182
 
40
- export function getScrollContainer(selector: string | HTMLElement): IScrollContainer | undefined {
183
+ export function getScrollContainer(selector: string | HTMLElement | ScrollContainer): IScrollContainer | undefined {
184
+ if (selector instanceof ScrollContainer) {
185
+ return selector;
186
+ }
41
187
  const key = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
42
188
  return key ? scrollContainers.get(key) : undefined;
43
189
  }
44
190
 
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
191
  function getPaddingY(content: HTMLElement): number {
72
192
  const style = getComputedStyle(content);
73
193
  return parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
74
194
  }
75
195
 
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>();
196
+ const scrollContainers = new Map<HTMLElement, ScrollContainer>();
97
197
 
98
198
  const intersectionObserver = new IntersectionObserver((entries) => {
99
199
  entries.forEach((entry) => {
100
200
  if (entry.isIntersecting) {
101
- updateThumbSize(scrollContainers.get(entry.target as HTMLElement) as IScrollContainer);
201
+ const sc = getScrollContainer(entry.target as HTMLElement);
202
+ if (sc) {
203
+ sc.refresh();
204
+ }
102
205
  }
103
206
  });
104
207
  },
@@ -106,45 +209,28 @@ const intersectionObserver = new IntersectionObserver((entries) => {
106
209
  );
107
210
 
108
211
  const mutationObserver = new MutationObserver((mutations) => {
109
- const containers: IScrollContainer[] = [];
212
+ const containers = new Set<IScrollContainer>();
110
213
  mutations.forEach((mutation) => {
111
- const sc = scrollContainers.get(getScrollContainerElement(mutation.target as HTMLElement));
112
- if (sc && !containers.includes(sc)) {
113
- containers.push(sc);
214
+ const sc = getScrollContainer(mutation.target as HTMLElement);
215
+ if (sc) {
216
+ containers.add(sc);
114
217
  }
115
218
  });
116
- containers.forEach((container) => {
117
- updateThumbSize(container);
219
+ [...containers].forEach((container) => {
220
+ container.refresh();
118
221
  });
119
222
  });
120
223
 
121
224
  document.querySelectorAll<HTMLElement>('.evo-scroll-container').forEach((container) => {
122
- const scrollContainer = createScrollContainer(container);
225
+ const scrollContainer = new ScrollContainer(container);
123
226
  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 });
227
+
126
228
  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
- });
229
+ mutationObserver.observe(container, { attributes: true, childList: true, subtree: true });
145
230
  });
231
+
146
232
  window.addEventListener('resize', () => {
147
233
  [...scrollContainers.values()].forEach((scrollContainer) => {
148
- updateThumbSize(scrollContainer);
234
+ scrollContainer.refresh();
149
235
  });
150
236
  });
@@ -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
+ });