@inizioevoke/astro-core 1.3.5 → 1.4.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
  {
2
2
  "name": "@inizioevoke/astro-core",
3
- "version": "1.3.5",
3
+ "version": "1.4.0",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -38,7 +38,7 @@ if (innerWidth) {
38
38
  contentAttrs.style = `width:${typeof innerWidth == 'number' || /^\d+$/.test(innerWidth) ? `${innerWidth}px` : innerWidth};`
39
39
  }
40
40
  ---
41
- <div class:list={['evo-scroll-container', cssClass]} {...containerAttrs}>
41
+ <scroll-container class:list={['evo-scroll-container', cssClass]} {...containerAttrs}>
42
42
  <div class="evo-scroll-content" {...contentAttrs}>
43
43
  <slot />
44
44
  </div>
@@ -48,7 +48,7 @@ if (innerWidth) {
48
48
  {horizontal && <div class="evo-scroll-track evo-scroll-track-x">
49
49
  <div class="evo-scroll-thumb"></div>
50
50
  </div>}
51
- </div>
51
+ </scroll-container>
52
52
 
53
53
  <script>
54
54
  import './ScrollContainer';
@@ -11,8 +11,10 @@
11
11
  --evo-scroll-container-thumb-border-color: var(--evo-scroll-container-track-color);
12
12
  }
13
13
 
14
+ evo-scroll-container,
14
15
  .evo-scroll-container {
15
16
  position: relative;
17
+ display: block;
16
18
  width: 100%;
17
19
  height: 100%;
18
20
  overflow: hidden;
@@ -1,3 +1,31 @@
1
+
2
+
3
+ const intersectionObserver = new IntersectionObserver((entries) => {
4
+ entries.forEach((entry) => {
5
+ if (entry.isIntersecting) {
6
+ const sc = getScrollContainer(entry.target as HTMLElement);
7
+ if (sc) {
8
+ sc.refresh();
9
+ }
10
+ }
11
+ });
12
+ },
13
+ { threshold: 0.1 }
14
+ );
15
+
16
+ const mutationObserver = new MutationObserver((mutations) => {
17
+ const containers = new Set<IScrollContainer>();
18
+ mutations.forEach((mutation) => {
19
+ const sc = getScrollContainer(mutation.target as HTMLElement);
20
+ if (sc) {
21
+ containers.add(sc);
22
+ }
23
+ });
24
+ [...containers].forEach((container) => {
25
+ container.refresh();
26
+ });
27
+ });
28
+
1
29
  export interface IScrollContainer {
2
30
  scroll(args?: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' }): void;
3
31
  getScroll(): { left: number, top: number }
@@ -5,64 +33,126 @@ export interface IScrollContainer {
5
33
  refresh(): void;
6
34
  }
7
35
 
8
- class ScrollContainer implements IScrollContainer {
9
- #container: HTMLElement;
10
- #content: HTMLElement;
11
- #track: HTMLElement;
12
- #thumb: HTMLElement;
13
- #isDragging: boolean;
14
- #startY: number;
15
- #startScrollTop: number;
36
+
37
+ export class ScrollContainer extends HTMLElement implements IScrollContainer {
38
+ // #container: HTMLElement & { evoScrollContainer: ScrollContainer };
39
+ #content!: HTMLElement;
40
+ #track!: HTMLElement;
41
+ #thumb!: HTMLElement;
42
+ #isDragging: boolean = false;
43
+ #startY: number = 0;
44
+ #startScrollTop: number = 0;
16
45
 
46
+ #scrollbarSettings: ScrollbarSettings = {};
17
47
  #mouseupHandler: any = undefined;
18
48
  #mousemoveHandler: any = undefined;
19
49
 
20
- constructor(container: HTMLElement) {
50
+ constructor() {
51
+ super();
52
+ }
53
+
54
+ connectedCallback() {
21
55
  // const _this = this;
22
- this.#container = container;
23
- this.#content = container.querySelector('.evo-scroll-content') as HTMLElement;
24
- this.#track = container.querySelector('.evo-scroll-track') as HTMLElement;
25
- this.#thumb = container.querySelector('.evo-scroll-thumb') as HTMLElement;
56
+ // this.#container = container as HTMLElement & { evoScrollContainer: ScrollContainer };
57
+ // this.#container.evoScrollContainer = this;
58
+ this.#content = this.querySelector('.evo-scroll-content') as HTMLElement;
59
+ this.#track = this.querySelector('.evo-scroll-track') as HTMLElement;
60
+ this.#thumb = this.querySelector('.evo-scroll-thumb') as HTMLElement;
26
61
  this.#isDragging = false;
27
62
  this.#startY = 0;
28
63
  this.#startScrollTop = 0;
29
64
 
30
65
  this.#thumb.addEventListener('mousedown', this.#thumbMouseDown.bind(this), { passive: true });
31
66
  this.#content.addEventListener('scroll', this.#scrollContent.bind(this), { passive: true });
67
+
68
+ intersectionObserver.observe(this);
69
+ mutationObserver.observe(this, { attributes: true, childList: true, subtree: true });
70
+
71
+ window.addEventListener('resize', this.refresh.bind(this), { passive: true });
32
72
  }
33
73
 
34
- scroll({ left, top, behavior = 'auto' }: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
35
- const current = this.getScroll();
36
- if (typeof left == 'string') {
37
- if (/^[\+\-]=?\d+/.test(left)) {
38
- left = current.left + parseInt(left.replace(/=/,''), 10);
39
- } else {
40
- left = parseInt(left, 10);
41
- }
42
- if (isNaN(left)) {
43
- left = undefined;
44
- }
45
- }
46
- if (typeof top == 'string') {
47
- if (/^[\+\-]=?\d+/.test(top)) {
48
- top = current.top + parseInt(top.replace(/=/,''), 10);
49
- } else {
50
- top = parseInt(top, 10);
51
- }
52
- if (isNaN(top)) {
53
- top = undefined;
54
- }
55
- }
56
- left = left ?? current.left;
57
- top = top ?? current.top;
58
- if (left < 0) {
59
- left = 0;
60
- }
61
- if (top < 0) {
62
- top = 0;
63
- }
64
- this.#content.scroll({ left: left, top: top, behavior });
74
+ // scroll({ left, top, behavior = 'auto' }: { left?: number | string, top?: number | string, behavior?: 'auto' | 'instant' | 'smooth' } = {}) {
75
+ // const current = this.getScroll();
76
+ // if (typeof left == 'string') {
77
+ // if (/^[\+\-]=?\d+/.test(left)) {
78
+ // left = current.left + parseInt(left.replace(/=/,''), 10);
79
+ // } else {
80
+ // left = parseInt(left, 10);
81
+ // }
82
+ // if (isNaN(left)) {
83
+ // left = undefined;
84
+ // }
85
+ // }
86
+ // if (typeof top == 'string') {
87
+ // if (/^[\+\-]=?\d+/.test(top)) {
88
+ // top = current.top + parseInt(top.replace(/=/,''), 10);
89
+ // } else {
90
+ // top = parseInt(top, 10);
91
+ // }
92
+ // if (isNaN(top)) {
93
+ // top = undefined;
94
+ // }
95
+ // }
96
+ // left = left ?? current.left;
97
+ // top = top ?? current.top;
98
+ // if (left < 0) {
99
+ // left = 0;
100
+ // }
101
+ // if (top < 0) {
102
+ // top = 0;
103
+ // }
104
+ // this.#content.scroll({ left: left, top: top, behavior });
105
+ // }
106
+
107
+ scroll(opts?: ScrollToOptions): void;
108
+ scroll(x: number, y: number): void;
109
+ scroll(...args: any[]) {
110
+ this.#content.scroll(...args);
111
+ }
112
+
113
+ scrollTo(opts?: ScrollToOptions): void;
114
+ scrollTo(x: number, y: number): void;
115
+ scrollTo(...args: any[]) {
116
+ this.scroll(...args);
117
+ }
118
+
119
+ scrollBy(opts?: ScrollToOptions): void;
120
+ scrollBy(x: number, y: number): void;
121
+ scrollBy(...args: any[]) {
122
+ this.#content.scrollBy(...args);
123
+ // let opts: ScrollToOptions = {};
124
+ // if (args.length === 1) {
125
+ // opts = args[0] as ScrollToOptions;
126
+ // } else if (args.length == 2) {
127
+ // opts.left = args[0];
128
+ // opts.top = args[1];
129
+ // }
130
+ // const current = this.getScroll();
131
+ // opts.left = current.left + (opts.left ?? 0);
132
+ // opts.top = current.top + (opts.top ?? 0);
133
+ // this.scroll(opts);
134
+ }
135
+
136
+ get scrollLeft() {
137
+ return this.#content.scrollLeft;
138
+ }
139
+ set scrollLeft(value: number) {
140
+ this.scroll({ left: value });
141
+ }
142
+ get scrollTop() {
143
+ return this.#content.scrollTop;
144
+ }
145
+ set scrollTop(value: number) {
146
+ this.scroll({ top: value });
147
+ }
148
+ get scrollWidth() {
149
+ return this.#content.scrollWidth;
150
+ }
151
+ get scrollHeight() {
152
+ return this.#content.scrollHeight;
65
153
  }
154
+
155
+
66
156
 
67
157
  getScroll() {
68
158
  return {
@@ -73,22 +163,38 @@ class ScrollContainer implements IScrollContainer {
73
163
 
74
164
  resize({ height }: { height?: number }) {
75
165
  if (typeof height == 'number') {
76
- this.#container.style.height = `${height}px`;
166
+ this.style.height = `${height}px`;
77
167
  refresh();
78
168
  }
79
169
  }
80
170
 
171
+ configureScrollbar({ trackVisible, thumbHeight }: ScrollbarSettings) {
172
+ this.#scrollbarSettings = { trackVisible, thumbHeight };
173
+ this.refresh();
174
+ }
175
+ resetScrollbar() {
176
+ this.configureScrollbar({});
177
+ }
81
178
  refresh() {
82
179
  this.#updateThumbSize();
83
180
  }
84
181
 
85
182
  #updateThumbSize() {
86
183
  const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
87
- const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
184
+ const containerHeight = this.clientHeight - getPaddingY(this);
88
185
  const visibleRatio = containerHeight / scrollHeight;
89
- const thumbHeight = this.#container.getAttribute('data-evo-scroll-thumb-height') ? parseInt(this.#container.getAttribute('data-evo-scroll-thumb-height') as string, 10) : visibleRatio * containerHeight;
90
- this.#thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
91
- this.#track.style.display = this.#container.classList.contains('evo-scroll-track-visible') ? 'block' : visibleRatio < 1 ? 'block' : 'none';
186
+ const thumbHeight = visibleRatio * containerHeight;
187
+ if (this.#scrollbarSettings.thumbHeight != undefined) {
188
+ this.#thumb.style.height = `${this.#scrollbarSettings.thumbHeight < 0 ? 0 : this.#scrollbarSettings.thumbHeight > containerHeight ? containerHeight : this.#scrollbarSettings.thumbHeight}px`;
189
+ } else {
190
+ this.#thumb.style.height = `${thumbHeight > 20 ? thumbHeight : 20}px`;
191
+ }
192
+ if (this.#scrollbarSettings.trackVisible !== undefined) {
193
+ this.#track.style.display = this.#scrollbarSettings.trackVisible === true ? 'block' : 'none';
194
+ } else {
195
+ this.#track.style.display = visibleRatio < 1 ? 'block' : 'none';
196
+ }
197
+
92
198
  }
93
199
 
94
200
  #thumbMouseDown(e: MouseEvent) {
@@ -108,8 +214,8 @@ class ScrollContainer implements IScrollContainer {
108
214
  if (this.#isDragging) {
109
215
  const deltaY = e.clientY - this.#startY;
110
216
  const scrollRatio =
111
- (this.#content.scrollHeight - this.#container.clientHeight) /
112
- (this.#container.clientHeight - this.#thumb.clientHeight);
217
+ (this.#content.scrollHeight - this.clientHeight) /
218
+ (this.clientHeight - this.#thumb.clientHeight);
113
219
  this.#content.scrollTop = this.#startScrollTop + deltaY * scrollRatio;
114
220
  } else {
115
221
  this.#mouseDetach();
@@ -126,12 +232,13 @@ class ScrollContainer implements IScrollContainer {
126
232
 
127
233
  #scrollContent() {
128
234
  const scrollHeight = this.#content.scrollHeight - getPaddingY(this.#content);
129
- const containerHeight = this.#container.clientHeight - getPaddingY(this.#container);
235
+ const containerHeight = this.clientHeight - getPaddingY(this);
130
236
  const scrollRatio = this.#content.scrollTop / (scrollHeight - containerHeight);
131
237
  const top = scrollRatio * (this.#track.clientHeight - this.#thumb.clientHeight);
132
238
  this.#thumb.style.top = `${top}px`;
133
239
  }
134
240
  }
241
+ customElements.define('scroll-container', ScrollContainer);
135
242
 
136
243
  export function resize(selector: string | HTMLElement | ScrollContainer, { height }: { height?: number }) {
137
244
  if (typeof height == 'number') {
@@ -176,23 +283,30 @@ export function getScrollContainer(selector: string | HTMLElement | ScrollContai
176
283
  if (selector instanceof ScrollContainer) {
177
284
  return selector;
178
285
  }
179
- const key = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
180
- return key ? scrollContainers.get(key) : undefined;
286
+ const scrollContainer = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
287
+ return scrollContainer instanceof ScrollContainer ? scrollContainer as IScrollContainer : undefined;
288
+ // const key = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
289
+ // return key ? scrollContainers.get(key) : undefined;
181
290
  }
182
291
 
183
- export function createScrollContainer(selector: string | HTMLElement): IScrollContainer | undefined {
184
- const container = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
185
- if (container) {
186
- if (scrollContainers.has(container)) {
187
- return scrollContainers.get(container);
188
- } else {
189
- const scrollContainer = new ScrollContainer(container);
190
- initNewScrollContainer(container, scrollContainer);
191
- return scrollContainer;
192
- }
193
- } else {
194
- return undefined;
195
- }
292
+ // export function createScrollContainer(selector: string | HTMLElement): IScrollContainer | undefined {
293
+ // const container = typeof selector == 'string' ? document.querySelector<HTMLElement>(selector) : selector;
294
+ // if (container) {
295
+ // if (scrollContainers.has(container)) {
296
+ // return scrollContainers.get(container);
297
+ // } else {
298
+ // const scrollContainer = new ScrollContainer(container);
299
+ // initNewScrollContainer(container, scrollContainer);
300
+ // return scrollContainer;
301
+ // }
302
+ // } else {
303
+ // return undefined;
304
+ // }
305
+ // }
306
+
307
+ interface ScrollbarSettings {
308
+ trackVisible?: boolean;
309
+ thumbHeight?: number;
196
310
  }
197
311
 
198
312
  function getPaddingY(content: HTMLElement): number {
@@ -200,48 +314,25 @@ function getPaddingY(content: HTMLElement): number {
200
314
  return parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
201
315
  }
202
316
 
203
- const scrollContainers = new Map<HTMLElement, ScrollContainer>();
317
+ // const scrollContainers = new Map<HTMLElement, ScrollContainer>();
204
318
 
205
- const intersectionObserver = new IntersectionObserver((entries) => {
206
- entries.forEach((entry) => {
207
- if (entry.isIntersecting) {
208
- const sc = getScrollContainer(entry.target as HTMLElement);
209
- if (sc) {
210
- sc.refresh();
211
- }
212
- }
213
- });
214
- },
215
- { threshold: 0.1 }
216
- );
217
319
 
218
- const mutationObserver = new MutationObserver((mutations) => {
219
- const containers = new Set<IScrollContainer>();
220
- mutations.forEach((mutation) => {
221
- const sc = getScrollContainer(mutation.target as HTMLElement);
222
- if (sc) {
223
- containers.add(sc);
224
- }
225
- });
226
- [...containers].forEach((container) => {
227
- container.refresh();
228
- });
229
- });
230
320
 
231
- function initNewScrollContainer(container: HTMLElement, scrollContainer: ScrollContainer) {
232
- scrollContainers.set(container, scrollContainer);
321
+ // function initNewScrollContainer(container: HTMLElement, scrollContainer: ScrollContainer) {
322
+ // scrollContainers.set(container, scrollContainer);
233
323
 
234
- intersectionObserver.observe(container);
235
- mutationObserver.observe(container, { attributes: true, childList: true, subtree: true });
236
- }
324
+ // intersectionObserver.observe(container);
325
+ // mutationObserver.observe(container, { attributes: true, childList: true, subtree: true });
326
+ // }
237
327
 
238
- document.querySelectorAll<HTMLElement>('.evo-scroll-container').forEach((container) => {
239
- const scrollContainer = new ScrollContainer(container);
240
- initNewScrollContainer(container, scrollContainer);
241
- });
328
+ // document.querySelectorAll<HTMLElement>('.evo-scroll-container').forEach((container) => {
329
+ // const scrollContainer = new ScrollContainer(container);
330
+ // initNewScrollContainer(container, scrollContainer);
331
+ // });
242
332
 
243
- window.addEventListener('resize', () => {
244
- [...scrollContainers.values()].forEach((scrollContainer) => {
245
- scrollContainer.refresh();
246
- });
247
- }, { passive: true });
333
+ // window.addEventListener('resize', () => {
334
+ // // [...scrollContainers.values()].forEach((scrollContainer) => {
335
+ // [...document.querySelectorAll<ScrollContainer>('scroll-container')].forEach((scrollContainer) => {
336
+ // scrollContainer.refresh();
337
+ // });
338
+ // }, { passive: true });