@inizioevoke/astro-core 1.6.5 → 2.0.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.
Files changed (32) hide show
  1. package/package.json +3 -5
  2. package/src/components/FlipCard/FlipCard.ts +15 -9
  3. package/src/components/ISI/{RightISI.astro → Right/RightISI.astro} +16 -9
  4. package/src/components/ISI/Right/RightISI.css +61 -0
  5. package/src/components/ISI/{RightISI.md → Right/RightISI.md} +0 -1
  6. package/src/components/ISI/Right/RightISI.ts +78 -0
  7. package/src/components/ISI/Right/index.ts +1 -0
  8. package/src/components/ISI/index.ts +5 -0
  9. package/src/components/Modal/Modal.astro +11 -5
  10. package/src/components/Modal/Modal.css +49 -39
  11. package/src/components/Modal/Modal.ts +186 -169
  12. package/src/components/PdfViewer/PdfViewer.astro +6 -3
  13. package/src/components/PdfViewer/PdfViewer.css +5 -3
  14. package/src/components/PdfViewer/PdfViewer.ts +226 -198
  15. package/src/components/ScrollContainer/ScrollContainer.ts +23 -2
  16. package/src/components/index.ts +1 -0
  17. package/src/lib/gestures/index.ts +2 -0
  18. package/src/lib/gestures/pinch.ts +66 -0
  19. package/src/lib/gestures/swipe.ts +153 -0
  20. package/src/lib/index.ts +2 -0
  21. package/src/components/ISI/RightISI.css +0 -31
  22. package/src/components/ISI/RightISI.ts +0 -27
  23. package/src/components/Modal/v2/Modal.astro +0 -42
  24. package/src/components/Modal/v2/Modal.css +0 -155
  25. package/src/components/Modal/v2/Modal.ts +0 -219
  26. package/src/components/Modal/v2/ModalOverlay.astro +0 -14
  27. package/src/components/Modal/v2/ModalTrigger.astro +0 -29
  28. package/src/components/Modal/v2/index.ts +0 -1
  29. package/src/components/ScrollContainer/archive-20260417.ts +0 -150
  30. package/src/components/v2.ts +0 -3
  31. package/src/lib/swipe.ts +0 -109
  32. package/src/lib/v2.ts +0 -1
@@ -1,42 +1,245 @@
1
+ /// <reference types="vite/client" />
1
2
  import * as pdfjs from './pdf.min.mjs';
3
+ import workerSrc from './pdf.worker.min.mjs?url';
2
4
  import type { PDFDocumentProxy } from 'pdfjs-dist';
3
- import * as ScrollContainer from '../ScrollContainer/archive-20260417';
5
+ import { EvoScrollContainerElement } from '../ScrollContainer/ScrollContainer';
4
6
 
5
- pdfjs.GlobalWorkerOptions.workerSrc = './pdf.worker.min.mjs';
7
+ const TAG_NAME = 'evo-pdf-viewer';
6
8
 
7
-
8
- export interface PdfViewerCustomEventDetail {
9
+ export interface EvoPdfViewerEventDetail {
9
10
  type: string;
10
11
  cmd?: string;
11
12
  args?: Record<string, string>
12
13
  }
14
+ export type EvoPdfViewerEvent = CustomEvent<EvoPdfViewerEventDetail>;
13
15
  declare global {
14
16
  interface ElementEventMap {
15
- 'pdfviewer-click': CustomEvent<PdfViewerCustomEventDetail>
17
+ 'evopdfviewer-click': EvoPdfViewerEvent
16
18
  }
17
19
  }
18
20
 
19
- interface LinkAnnotation {
20
- rect: [number, number, number, number];
21
- url?: string;
22
- dest?: any;
23
- newWindow?: boolean;
21
+ export interface IEvoPdfViewerElement {
22
+ scrollToPage: (page: number | string) => void;
23
+ zoom: (z: number) => void;
24
24
  }
25
+ export class EvoPdfViewerElement extends HTMLElement implements IEvoPdfViewerElement {
26
+ #toolbar!: HTMLElement;
27
+ #pageSelect!: HTMLSelectElement;
28
+ #scrollContainer!: EvoScrollContainerElement;
25
29
 
26
- interface PdfViewerSettings {
27
- workerDir?: string;
28
- workerSrc?: string;
29
- }
30
- export function init(settings: PdfViewerSettings = {}) {
31
- if (!settings.workerDir) {
32
- settings.workerDir = './';
30
+ #toolbarHeight = 0;
31
+ #defaultZoom = 100;
32
+ #pageCount = 0;
33
+
34
+ constructor() {
35
+ super();
36
+ pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
33
37
  }
34
- if (!settings.workerSrc) {
35
- settings.workerSrc = `${settings.workerDir}${settings.workerDir.endsWith('/') ? '' : '/'}pdf.worker.min.mjs`
38
+
39
+ connectedCallback() {
40
+ this.#toolbar = this.querySelector('.evo-pdf-viewer-toolbar') as HTMLElement;
41
+ this.#pageSelect = this.#toolbar.querySelector('.evo-pdf-viewer-nav-page select') as HTMLSelectElement;
42
+ this.#scrollContainer = this.querySelector('evo-scroll-container') as EvoScrollContainerElement;
43
+
44
+ this.#toolbarHeight = parseFloat(getComputedStyle(this.#toolbar).height);
45
+ this.#defaultZoom = parseInt(this.getAttribute('data-zoom') ?? '100', 10);
46
+
47
+ // *** nav
48
+ this.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-prev')?.addEventListener('click', () => {
49
+ const page = parseInt(this.#pageSelect.options[this.#pageSelect.selectedIndex].value, 10) - 1;
50
+ if (page > 0) {
51
+ this.scrollToPage(page);
52
+ }
53
+ }, { passive: true });
54
+
55
+ this.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-next')?.addEventListener('click', () => {
56
+ const page = parseInt(this.#pageSelect.options[this.#pageSelect.selectedIndex].value, 10) + 1;
57
+ if (page <= this.#pageCount) {
58
+ this.scrollToPage(page);
59
+ }
60
+ }, { passive: true });
61
+
62
+ this.#pageSelect.addEventListener('change', () => {
63
+ const page = this.#pageSelect.options[this.#pageSelect.selectedIndex].value;
64
+ this.scrollToPage(page);
65
+ }, { passive: true });
66
+
67
+ // *** zoom
68
+ this.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-out')?.addEventListener('click', () => {
69
+ this.zoom(-1);
70
+ }, { passive: true });
71
+
72
+ this.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-in')?.addEventListener('click', () => {
73
+ this.zoom(1);
74
+ }, { passive: true });
75
+
76
+ this.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-reset')?.addEventListener('click', () => {
77
+ this.zoom(0);
78
+ }, { passive: true });
79
+
80
+
81
+ // *** bookmarks
82
+ const bookmarksSelect = this.#toolbar.querySelector<HTMLSelectElement>('.evo-pdf-viewer-toolbar-bookmarks select');
83
+ if (bookmarksSelect) {
84
+ bookmarksSelect.addEventListener('change', () => {
85
+ this.scrollToPage(bookmarksSelect.options[bookmarksSelect.selectedIndex].value);
86
+ bookmarksSelect.selectedIndex = 0;
87
+ });
88
+ }
89
+
90
+ this.#scrollContainer.addEventListener('scroll', this.#updateCurrentPage, { passive: true });
91
+
92
+ this.#renderPDF()
93
+ .then(() => {
94
+ this.zoom(0);
95
+ this.#updateCurrentPage();
96
+ })
97
+ .catch((err) => {
98
+ console.error('A PDF rendering error occurred', err);
99
+ });
100
+
101
+ }
102
+
103
+ scrollToPage(page: number | string) {
104
+ if (typeof page == 'string') {
105
+ page = parseInt(page, 10);
106
+ }
107
+ // requestAnimationFrame(() => {
108
+ const canvas = this.#scrollContainer.querySelector<HTMLElement>(`canvas[data-page="${page}"]`);
109
+ if (canvas) {
110
+ this.#scrollContainer.scroll({
111
+ top: canvas.getBoundingClientRect().top + this.#scrollContainer.scrollTop - this.#toolbarHeight
112
+ }); // , behavior: 'smooth' });
113
+ this.#pageSelect.selectedIndex = page - 1;
114
+ }
115
+ // }
116
+ }
117
+
118
+ zoom(z: number) {
119
+ const style = getComputedStyle(this);
120
+ const current = Math.floor(parseFloat(style.getPropertyValue('--evo-pdf-viewer-scale')) * 10);
121
+ const scale = z === 0 ? this.#defaultZoom / 10 : current + z;
122
+ if (scale >= 1) {
123
+ const scroll = {
124
+ left: this.#scrollContainer.scrollLeft,
125
+ top: this.#scrollContainer.scrollTop
126
+ };
127
+ this.style.setProperty('--evo-pdf-viewer-scale', (scale/10).toString());
128
+ this.#scrollContainer.scroll({
129
+ left: scroll.left * scale / current,
130
+ top: scroll.top * scale / current
131
+ });
132
+ this.#scrollContainer.refresh();
133
+ }
134
+ }
135
+
136
+ async #renderPDF() {
137
+ const outputScale = window.devicePixelRatio || 1;
138
+ const pdf: PDFDocumentProxy = await pdfjs.getDocument(this.getAttribute('data-pdf') as string).promise;
139
+
140
+ const pages = new Array(pdf.numPages).fill(1).map((v, i) => { return i + 1; });
141
+ this.#pageCount = pages.length;
142
+
143
+ this.querySelector<HTMLElement>('.evo-pdf-viewer-nav-page-count')!.innerText = pages.length.toString();
144
+
145
+ this.#pageSelect.options.remove(0);
146
+ for (const pageNum of pages) {
147
+ const option = document.createElement('option');
148
+ option.value = pageNum.toString();
149
+ option.innerText = `${pageNum}`;
150
+ this.#pageSelect.options.add(option);
151
+ }
152
+
153
+ for (const pageNum of pages) {
154
+
155
+ const pdfPage = await pdf.getPage(pageNum);
156
+ const pdfPageWidth = pdfPage.getViewport({ scale: 1}).width;
157
+ const containerStyle = getComputedStyle(this.#scrollContainer.content);
158
+ const trackWidth = parseInt(containerStyle.getPropertyValue('--evo-scroll-container-track-width'));
159
+ const viewport = pdfPage.getViewport({ scale: parseFloat(containerStyle.width) / pdfPageWidth });
160
+
161
+ const canvas = document.createElement('canvas');
162
+ canvas.setAttribute('data-page', pageNum.toString());
163
+ const width = Math.floor(viewport.width * outputScale);
164
+ const height = Math.floor(viewport.height * outputScale);
165
+ canvas.width = width;
166
+ canvas.height = height;
167
+ canvas.style.aspectRatio = `${width}/${height}`;
168
+ canvas.style.width = `calc(${Math.floor(viewport.width) - (trackWidth * 2)}px * var(--evo-pdf-viewer-scale))`;
169
+ // canvas.style.height = `${Math.floor(viewport.height)}px`;
170
+
171
+ // Create wrapper for canvas and overlay
172
+ const pageWrapper = document.createElement('div');
173
+ pageWrapper.className = 'evo-pdf-viewer-page-wrapper';
174
+ pageWrapper.style.position = 'relative';
175
+ pageWrapper.style.width = canvas.style.width;
176
+ pageWrapper.style.aspectRatio = canvas.style.aspectRatio;
177
+ pageWrapper.appendChild(canvas);
178
+
179
+ this.#scrollContainer.content.append(pageWrapper);
180
+
181
+ pdfPage.render({
182
+ canvas,
183
+ // canvasContext: canvas.getContext('2d') as CanvasRenderingContext2D,
184
+ transform: outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : undefined,
185
+ viewport
186
+ });
187
+
188
+ // Extract and render links
189
+ const links = await getPageLinks(pdfPage);
190
+ if (links.length > 0) {
191
+ const linkOverlay = createLinkOverlay(canvas, links, viewport, pageNum, this, this.scrollToPage.bind(this), pdf);
192
+ pageWrapper.appendChild(linkOverlay);
193
+ }
194
+
195
+ this.#scrollContainer.refresh();
196
+ }
197
+ }
198
+
199
+ #updateCurrentPage() {
200
+ const canvases = this.#scrollContainer.content.querySelectorAll<HTMLCanvasElement>('canvas');
201
+ let visiblePage: HTMLCanvasElement | undefined;
202
+ let maxVisibility = 0;
203
+
204
+ canvases.forEach((canvas) => {
205
+ const rect = canvas.getBoundingClientRect();
206
+ const containerRect = this.#scrollContainer.getBoundingClientRect();
207
+
208
+ // Calculate intersection height
209
+ const intersectTop = Math.max(rect.top, containerRect.top);
210
+ const intersectBottom = Math.min(rect.bottom, containerRect.bottom);
211
+ const intersectionHeight = Math.max(0, intersectBottom - intersectTop);
212
+
213
+ // Calculate visibility ratio
214
+ const visibility = intersectionHeight / (rect.height || 1);
215
+
216
+ if (visibility > maxVisibility) {
217
+ maxVisibility = visibility;
218
+ visiblePage = canvas;
219
+ }
220
+ });
221
+
222
+ if (visiblePage && maxVisibility >= 0.1) {
223
+ const pageNum = visiblePage.getAttribute('data-page');
224
+ if (pageNum) {
225
+ this.#pageSelect.selectedIndex = parseInt(pageNum, 10) - 1;
226
+ }
227
+ }
36
228
  }
37
- pdfjs.GlobalWorkerOptions.workerSrc = settings.workerSrc;
38
229
  }
39
230
 
231
+ if (!customElements.get(TAG_NAME)) {
232
+ customElements.define(TAG_NAME, EvoPdfViewerElement);
233
+ }
234
+
235
+
236
+
237
+ interface LinkAnnotation {
238
+ rect: [number, number, number, number];
239
+ url?: string;
240
+ dest?: any;
241
+ newWindow?: boolean;
242
+ }
40
243
  /**
41
244
  * Extract link annotations from a PDF page
42
245
  */
@@ -143,7 +346,7 @@ function createLinkOverlay(
143
346
  e.stopPropagation();
144
347
 
145
348
  if (link.url) {
146
- if (link.url.startsWith('http://pdfviewer')) {
349
+ if (link.url.startsWith('http://pdfviewer.evo')) {
147
350
  const url = new URL(link.url);
148
351
  const [ type, cmd ] = url.pathname.split('/').filter(p => p.trim() !== '');
149
352
  const args = url.search === '' ? undefined :
@@ -153,7 +356,7 @@ function createLinkOverlay(
153
356
  })
154
357
  );
155
358
 
156
- pdfViewer.dispatchEvent(new CustomEvent('pdfviewer-click', {
359
+ pdfViewer.dispatchEvent(new CustomEvent('evopdfviewer-click', {
157
360
  detail: { type: type ?? '', cmd, args }
158
361
  }));
159
362
  return;
@@ -215,179 +418,4 @@ function createLinkOverlay(
215
418
  }
216
419
 
217
420
  return svg;
218
- }
219
-
220
- export async function createViewer(selector: string) {
221
- const pdfViewer = document.querySelector<HTMLElement>(selector);
222
- if (pdfViewer) {
223
- // const ddlPage = pdfViewer.querySelector('select') as HTMLSelectElement;
224
- const toolbar = pdfViewer.querySelector('.evo-pdf-viewer-toolbar') as HTMLElement;
225
- const toolbarHeight = parseFloat(getComputedStyle(toolbar).height);
226
- const pageSelect = toolbar.querySelector('.evo-pdf-viewer-nav-page select') as HTMLSelectElement;
227
- const scrollContainer = ScrollContainer.getScrollContainer(pdfViewer.querySelector('.evo-scroll-container') as HTMLElement) as ScrollContainer.IScrollContainer;
228
- const defaultZoom = parseInt(pdfViewer.getAttribute('data-zoom') ?? '100', 10);
229
- const zoom = (z: number) => {
230
- const style = getComputedStyle(pdfViewer);
231
- const current = Math.floor(parseFloat(style.getPropertyValue('--evo-pdf-viewer-scale')) * 10);
232
- const scale = z === 0 ? defaultZoom / 10 : current + z;
233
- if (scale >= 1) {
234
- const scroll = ScrollContainer.getScroll(scrollContainer);
235
- pdfViewer.style.setProperty('--evo-pdf-viewer-scale', (scale/10).toString());
236
- ScrollContainer.scroll(scrollContainer, { left: scroll.left * scale / current, top: scroll.top * scale / current });
237
- ScrollContainer.refresh(scrollContainer);
238
- }
239
- };
240
- zoom(0);
241
-
242
- const gotoPage = (page: number | string) => {
243
- if (typeof page == 'string') {
244
- page = parseInt(page, 10);
245
- }
246
- requestAnimationFrame(() => {
247
- const container = pdfViewer.querySelector('.evo-scroll-content') as HTMLElement;
248
- const canvas = container.querySelector<HTMLElement>(`canvas[data-page="${page}"]`);
249
- if (canvas) {
250
- container.scroll({ top: canvas.getBoundingClientRect().top + container.scrollTop - toolbarHeight }); // , behavior: 'smooth' });
251
- pageSelect.selectedIndex = page - 1;
252
- }
253
- })
254
- };
255
-
256
- pageSelect.addEventListener('change', (e) => {
257
- const page = pageSelect.options[pageSelect.selectedIndex].value;
258
- gotoPage(page);
259
- }, { passive: true });
260
-
261
- pdfViewer.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-out')?.addEventListener('click', () => {
262
- zoom(-1);
263
- }, { passive: true });
264
-
265
- pdfViewer.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-in')?.addEventListener('click', () => {
266
- zoom(1);
267
- }, { passive: true });
268
-
269
- pdfViewer.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-zoom-reset')?.addEventListener('click', () => {
270
- zoom(0);
271
- }, { passive: true });
272
-
273
- const pdf: PDFDocumentProxy = await pdfjs.getDocument(pdfViewer.getAttribute('data-pdf') as string).promise;
274
-
275
- const bookmarksSelect = toolbar.querySelector<HTMLSelectElement>('.evo-pdf-viewer-toolbar-bookmarks select');
276
- if (bookmarksSelect) {
277
- bookmarksSelect.addEventListener('change', () => {
278
- gotoPage(bookmarksSelect.options[bookmarksSelect.selectedIndex].value);
279
- bookmarksSelect.selectedIndex = 0;
280
- });
281
- }
282
-
283
- const outputScale = window.devicePixelRatio || 1;
284
- const pages = new Array(pdf.numPages).fill(1).map((v, i) => { return i + 1; });
285
-
286
-
287
- pdfViewer.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-prev')?.addEventListener('click', () => {
288
- const page = parseInt(pageSelect.options[pageSelect.selectedIndex].value, 10) - 1;
289
- if (page > 0) {
290
- gotoPage(page);
291
- }
292
- }, { passive: true });
293
-
294
- pdfViewer.querySelector<HTMLButtonElement>('button.evo-pdf-viewer-toolbar-next')?.addEventListener('click', () => {
295
- const page = parseInt(pageSelect.options[pageSelect.selectedIndex].value, 10) + 1;
296
- if (page <= pages.length) {
297
- gotoPage(page);
298
- }
299
- }, { passive: true });
300
-
301
- const pdfContainer = pdfViewer.querySelector('.evo-scroll-content') as HTMLElement;
302
- pdfViewer.querySelector<HTMLElement>('.evo-pdf-viewer-nav-page-count')!.innerText = pages.length.toString();
303
- pageSelect.options.remove(0);
304
- for (const pageNum of pages) {
305
- const option = document.createElement('option');
306
- option.value = pageNum.toString();
307
- option.innerText = `${pageNum}`;
308
- pageSelect.options.add(option);
309
- }
310
- for (const pageNum of pages) {
311
-
312
- const pdfPage = await pdf.getPage(pageNum);
313
- const pdfPageWidth = pdfPage.getViewport({ scale: 1}).width;
314
- const containerStyle = getComputedStyle(pdfContainer);
315
- const trackWidth = parseInt(containerStyle.getPropertyValue('--evo-scroll-container-track-width'));
316
- const viewport = pdfPage.getViewport({ scale: parseFloat(containerStyle.width) / pdfPageWidth });
317
-
318
- const canvas = document.createElement('canvas');
319
- canvas.setAttribute('data-page', pageNum.toString());
320
- const width = Math.floor(viewport.width * outputScale);
321
- const height = Math.floor(viewport.height * outputScale);
322
- canvas.width = width;
323
- canvas.height = height;
324
- canvas.style.aspectRatio = `${width}/${height}`;
325
- canvas.style.width = `calc(${Math.floor(viewport.width) - (trackWidth * 2)}px * var(--evo-pdf-viewer-scale)`;
326
- // canvas.style.height = `${Math.floor(viewport.height)}px`;
327
-
328
- // Create wrapper for canvas and overlay
329
- const pageWrapper = document.createElement('div');
330
- pageWrapper.className = 'evo-pdf-viewer-page-wrapper';
331
- pageWrapper.style.position = 'relative';
332
- pageWrapper.style.width = canvas.style.width;
333
- pageWrapper.style.aspectRatio = canvas.style.aspectRatio;
334
- pageWrapper.appendChild(canvas);
335
-
336
- pdfContainer.append(pageWrapper);
337
-
338
- pdfPage.render({
339
- canvas,
340
- // canvasContext: canvas.getContext('2d') as CanvasRenderingContext2D,
341
- transform: outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : undefined,
342
- viewport
343
- });
344
-
345
- // Extract and render links
346
- const links = await getPageLinks(pdfPage);
347
- if (links.length > 0) {
348
- const linkOverlay = createLinkOverlay(canvas, links, viewport, pageNum, pdfViewer, gotoPage, pdf);
349
- pageWrapper.appendChild(linkOverlay);
350
- }
351
-
352
- ScrollContainer.refresh(scrollContainer);
353
- }
354
-
355
- // Function to check and update current page
356
- const updateCurrentPage = () => {
357
- const canvases = pdfContainer.querySelectorAll<HTMLCanvasElement>('canvas');
358
- let visiblePage: HTMLCanvasElement | undefined;
359
- let maxVisibility = 0;
360
-
361
- canvases.forEach((canvas) => {
362
- const rect = canvas.getBoundingClientRect();
363
- const containerRect = scrollContainer.container.getBoundingClientRect();
364
-
365
- // Calculate intersection height
366
- const intersectTop = Math.max(rect.top, containerRect.top);
367
- const intersectBottom = Math.min(rect.bottom, containerRect.bottom);
368
- const intersectionHeight = Math.max(0, intersectBottom - intersectTop);
369
-
370
- // Calculate visibility ratio
371
- const visibility = intersectionHeight / (rect.height || 1);
372
-
373
- if (visibility > maxVisibility) {
374
- maxVisibility = visibility;
375
- visiblePage = canvas;
376
- }
377
- });
378
-
379
- if (visiblePage && maxVisibility >= 0.1) {
380
- const pageNum = visiblePage.getAttribute('data-page');
381
- if (pageNum) {
382
- pageSelect.selectedIndex = parseInt(pageNum, 10) - 1;
383
- }
384
- }
385
- };
386
-
387
- // Update on scroll
388
- scrollContainer.content.addEventListener('scroll', updateCurrentPage, { passive: true });
389
-
390
- // Initial update
391
- updateCurrentPage();
392
- }
393
- }
421
+ }
@@ -24,8 +24,25 @@ const mutationObserver = new MutationObserver((mutations) => {
24
24
  });
25
25
  });
26
26
 
27
-
28
- export class EvoScrollContainerElement extends HTMLElement {
27
+ export interface IEvoScrollContainerElement {
28
+ content: HTMLElement;
29
+ scrollLeft: number;
30
+ scrollTop: number;
31
+ scrollWidth: number;
32
+ scrollHeight: number;
33
+ configureScrollbar: (settings: ScrollbarSettings) => void;
34
+ getScroll: () => { left: number, top: number };
35
+ resize: (opts: { height?: number }) => void;
36
+ resetScrollbar: () => void;
37
+ refresh: () => void;
38
+ scroll(opts?: ScrollToOptions): void;
39
+ scroll(x: number, y: number): void;
40
+ scrollTo(opts?: ScrollToOptions): void;
41
+ scrollTo(x: number, y: number): void;
42
+ scrollBy(opts?: ScrollToOptions): void;
43
+ scrollBy(x: number, y: number): void;
44
+ }
45
+ export class EvoScrollContainerElement extends HTMLElement implements IEvoScrollContainerElement {
29
46
  static get htmlTagName() {
30
47
  return 'evo-scroll-container';
31
48
  }
@@ -69,6 +86,10 @@ export class EvoScrollContainerElement extends HTMLElement {
69
86
  window.removeEventListener('resize', this.#boundResizeHandler);
70
87
  }
71
88
 
89
+ get content() {
90
+ return this.#content;
91
+ }
92
+
72
93
  scroll(opts?: ScrollToOptions): void;
73
94
  scroll(x: number, y: number): void;
74
95
  scroll(...args: any[]) {
@@ -1,4 +1,5 @@
1
1
  export { default as FlipCard } from './FlipCard/FlipCard.astro';
2
+ export { default as RightISI } from './ISI/Right/RightISI.astro';
2
3
  export { default as Modal } from './Modal/Modal.astro';
3
4
  export { default as ModalOverlay } from './Modal/ModalOverlay.astro';
4
5
  export { default as ModalTrigger } from './Modal/ModalTrigger.astro';
@@ -0,0 +1,2 @@
1
+ export * from './pinch';
2
+ export * from './swipe';
@@ -0,0 +1,66 @@
1
+ export function createPinchListener() {
2
+ type PinchDirection = 'in' | 'out';
3
+
4
+ let initialDist: number = 0;
5
+ let lastDistance: number = 0;
6
+ let currentScale: number = 1;
7
+ let activeScale: number = 1;
8
+
9
+ function getTouchDistance(touches: TouchList) {
10
+ return Math.hypot(touches[0].clientX - touches[1].clientX, touches[0].clientY - touches[1].clientY);
11
+ }
12
+
13
+ function reset() {
14
+ window.removeEventListener('touchmove', touchmove);
15
+ window.removeEventListener('touchend', touchend);
16
+ currentScale = activeScale;
17
+ initialDist = 0;
18
+ lastDistance = 0;
19
+ }
20
+
21
+ const touchstart = (e: TouchEvent) => {
22
+ if (e.touches.length === 2) {
23
+ initialDist = getTouchDistance(e.touches);
24
+ lastDistance = initialDist;
25
+ window.addEventListener('touchmove', touchmove, { passive: true });
26
+ window.addEventListener('touchend', touchend, { passive: true });
27
+ } else {
28
+ reset();
29
+ }
30
+ };
31
+
32
+ const touchmove = (e: TouchEvent) => {
33
+ if (e.touches.length === 2) {
34
+ const currentDistance = getTouchDistance(e.touches);
35
+ const ratio = currentDistance / initialDist;
36
+
37
+ const rawScale = currentScale * ratio;
38
+
39
+ // Detect if we're crossing 1 from either direction
40
+ const crossingOne =
41
+ (currentScale > 1 && rawScale < 1) ||
42
+ (currentScale < 1 && rawScale > 1);
43
+
44
+ activeScale = crossingOne ? 1 : rawScale; // snap to 1
45
+
46
+ let direction: PinchDirection | undefined = undefined;
47
+ if (currentDistance > lastDistance) {
48
+ direction = 'in';
49
+ } else if (currentDistance < lastDistance) {
50
+ direction = 'out';
51
+ }
52
+
53
+ if (direction !== undefined) {
54
+ console.log(activeScale, direction);
55
+ lastDistance = currentDistance;
56
+ }
57
+ }
58
+ };
59
+
60
+ const touchend = (e: TouchEvent) => {
61
+ if (e.touches.length < 2) {
62
+ reset();
63
+ }
64
+ };
65
+ window.addEventListener('touchstart', touchstart, { passive: true });
66
+ }