lupine.components 1.1.57 → 1.1.59

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.
@@ -0,0 +1,777 @@
1
+ import { CssProps, RefProps, VNode, bindGlobalStyle } from 'lupine.components';
2
+
3
+ export interface SlidePageHookProps {
4
+ moveTo?: (index: number) => void;
5
+ getIndex?: () => number;
6
+ setIndex?: (index: number) => void;
7
+ setPause?: (pause: boolean) => void;
8
+ isPaused?: () => boolean;
9
+ togglePause?: () => boolean;
10
+ next?: () => void;
11
+ prev?: () => void;
12
+ }
13
+
14
+ export interface SlidePageItemProps {
15
+ id?: string;
16
+ title?: string;
17
+ content: VNode<any> | any;
18
+ link?: string;
19
+ target?: string;
20
+ onClick?: (event: any, page: SlidePageItemProps, index: number) => void;
21
+ }
22
+
23
+ export type SlidePageItem = SlidePageItemProps;
24
+
25
+ export interface SlidePageProps {
26
+ pages: SlidePageItemProps[];
27
+ hook?: SlidePageHookProps;
28
+ initialIndex?: number;
29
+ index?: number;
30
+ autoplay?: boolean;
31
+ interval?: number;
32
+ showDots?: boolean;
33
+ dotsPosition?: 'inside' | 'outside';
34
+ showArrows?: boolean;
35
+ pause?: boolean;
36
+ pauseOnHover?: boolean;
37
+ pauseOnClick?: boolean;
38
+ pauseOnInteraction?: boolean;
39
+ draggable?: boolean;
40
+ onChange?: (index: number, page: SlidePageItemProps) => void;
41
+ class?: string;
42
+ style?: CssProps;
43
+ dotClass?: string;
44
+ height?: string;
45
+ }
46
+
47
+ export const SlidePageComponent = (props: SlidePageProps) => {
48
+ if (!props.pages || props.pages.length === 0) {
49
+ return null;
50
+ }
51
+
52
+ const css: CssProps = {
53
+ display: 'flex',
54
+ flexDirection: 'column',
55
+ flex: 1,
56
+ width: '100%',
57
+ height: props.height || '100%',
58
+ minHeight: '160px',
59
+ overflow: 'hidden',
60
+ position: 'relative',
61
+ boxSizing: 'border-box',
62
+
63
+ '.slide-page-c-list': {
64
+ flex: 1,
65
+ display: 'flex',
66
+ flexDirection: 'row',
67
+ overflowX: 'auto',
68
+ overflowY: 'hidden',
69
+ width: '100%',
70
+ height: '100%',
71
+ scrollSnapType: 'x mandatory',
72
+ scrollBehavior: 'smooth',
73
+ WebkitOverflowScrolling: 'touch',
74
+ boxSizing: 'border-box',
75
+ scrollbarWidth: 'none',
76
+ cursor: 'grab',
77
+ userSelect: 'none',
78
+ WebkitUserSelect: 'none',
79
+ touchAction: 'pan-y pinch-zoom',
80
+ '&::-webkit-scrollbar': { display: 'none' },
81
+ '&.is-dragging': {
82
+ cursor: 'grabbing',
83
+ scrollSnapType: 'none !important',
84
+ scrollBehavior: 'auto !important',
85
+ },
86
+ },
87
+
88
+ '.slide-page-c-item': {
89
+ width: '100%',
90
+ minWidth: '100%',
91
+ maxWidth: '100%',
92
+ flexShrink: 0,
93
+ height: '100%',
94
+ overflowY: 'auto',
95
+ position: 'relative',
96
+ scrollSnapAlign: 'start',
97
+ scrollSnapStop: 'always',
98
+ boxSizing: 'border-box',
99
+ cursor: 'default',
100
+ display: 'flex',
101
+ flexDirection: 'column',
102
+ scrollbarWidth: 'none',
103
+ WebkitOverflowScrolling: 'touch',
104
+ '&::-webkit-scrollbar': { display: 'none' },
105
+ },
106
+
107
+ '.slide-page-c-item.slide-page-c-item-link': {
108
+ cursor: 'pointer',
109
+ textDecoration: 'none',
110
+ color: 'inherit',
111
+ transition: 'opacity 0.2s ease, transform 0.2s ease',
112
+ WebkitTapHighlightColor: 'transparent',
113
+ '&:hover': {
114
+ opacity: 0.95,
115
+ },
116
+ '&:active': {
117
+ transform: 'scale(0.995)',
118
+ opacity: 0.88,
119
+ },
120
+ },
121
+
122
+ '.slide-page-c-arrow': {
123
+ position: 'absolute',
124
+ top: '50%',
125
+ transform: 'translateY(-50%)',
126
+ width: '32px',
127
+ height: '32px',
128
+ borderRadius: '50%',
129
+ backgroundColor: 'var(--secondary-bg-color)',
130
+ border: '1px solid var(--secondary-border-color)',
131
+ color: 'var(--primary-color)',
132
+ fontFamily: 'monospace',
133
+ fontSize: '22px',
134
+ lineHeight: '1',
135
+ display: 'flex',
136
+ alignItems: 'center',
137
+ justifyContent: 'center',
138
+ cursor: 'pointer',
139
+ zIndex: 10,
140
+ backdropFilter: 'blur(8px)',
141
+ WebkitBackdropFilter: 'blur(8px)',
142
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
143
+ transition: 'all 0.2s ease',
144
+ userSelect: 'none',
145
+ WebkitTapHighlightColor: 'transparent',
146
+ padding: '0',
147
+ outline: 'none',
148
+ '&:hover': {
149
+ transform: 'translateY(-50%) scale(1.08)',
150
+ opacity: 0.92,
151
+ },
152
+ '&:active': {
153
+ transform: 'translateY(-50%) scale(0.96)',
154
+ },
155
+ },
156
+ '.slide-page-c-arrow-prev': {
157
+ left: '12px',
158
+ },
159
+ '.slide-page-c-arrow-next': {
160
+ right: '12px',
161
+ },
162
+
163
+ '.slide-page-c-dots': {
164
+ position: 'absolute',
165
+ bottom: '12px',
166
+ left: '0',
167
+ right: '0',
168
+ display: 'flex',
169
+ flexDirection: 'row',
170
+ justifyContent: 'center',
171
+ alignItems: 'center',
172
+ gap: '8px',
173
+ zIndex: 10,
174
+ pointerEvents: 'auto',
175
+ },
176
+
177
+ '.slide-page-c-dots.dots-outside': {
178
+ position: 'relative',
179
+ bottom: 'auto',
180
+ marginTop: '10px',
181
+ marginBottom: '4px',
182
+ },
183
+
184
+ '.slide-page-c-dot': {
185
+ cursor: 'pointer',
186
+ width: '8px',
187
+ height: '8px',
188
+ borderRadius: '4px',
189
+ backgroundColor: 'var(--secondary-color)',
190
+ opacity: 0.5,
191
+ transition: 'all 0.25s cubic-bezier(0.4, 0, 0.2, 1)',
192
+ WebkitTapHighlightColor: 'transparent',
193
+ boxShadow: '0 1px 3px rgba(0, 0, 0, 0.15)',
194
+ },
195
+
196
+ '.slide-page-c-dot.active': {
197
+ width: '24px',
198
+ borderRadius: '4px',
199
+ backgroundColor: 'var(--primary-accent-color)',
200
+ opacity: 1,
201
+ boxShadow: '0 2px 6px rgba(2, 132, 199, 0.4)',
202
+ },
203
+
204
+ '.slide-page-c-dot:hover': {
205
+ backgroundColor: 'var(--primary-accent-color)',
206
+ opacity: 0.85,
207
+ },
208
+ };
209
+
210
+ bindGlobalStyle('slide-page-c-box', css);
211
+
212
+ const ref: RefProps = {};
213
+ let slideIndex = props.initialIndex ?? props.index ?? 0;
214
+ if (slideIndex < 0 || slideIndex >= props.pages.length) {
215
+ slideIndex = 0;
216
+ }
217
+
218
+ let manualScroll = false;
219
+ let scrollEndTimer: any = null;
220
+ let loopTimer: any = null;
221
+ let isHovered = false;
222
+ let isUserPaused = props.pause || false;
223
+
224
+ const autoplay = props.autoplay ?? true;
225
+ const interval = props.interval || 4000;
226
+
227
+ const resetSlides = (index: number) => {
228
+ const dots = ref.$all?.('.slide-page-c-dot');
229
+ if (dots) {
230
+ for (let i = 0; i < dots.length; i++) {
231
+ dots[i].classList.toggle('active', i === index);
232
+ }
233
+ }
234
+ if (props.onChange && props.pages[index]) {
235
+ props.onChange(index, props.pages[index]);
236
+ }
237
+ };
238
+
239
+ const pauseAutoplay = (userPaused: boolean = false) => {
240
+ if (loopTimer) {
241
+ clearTimeout(loopTimer);
242
+ loopTimer = null;
243
+ }
244
+ if (scrollEndTimer) {
245
+ clearTimeout(scrollEndTimer);
246
+ scrollEndTimer = null;
247
+ }
248
+ if (userPaused) {
249
+ isUserPaused = true;
250
+ }
251
+ };
252
+
253
+ const canHover = () => {
254
+ if (typeof window === 'undefined' || !window.matchMedia) return false;
255
+ return window.matchMedia('(hover: hover) and (pointer: fine)').matches;
256
+ };
257
+
258
+ const scheduleAutoplay = (customDelay?: number) => {
259
+ if (loopTimer) {
260
+ clearTimeout(loopTimer);
261
+ loopTimer = null;
262
+ }
263
+ if (!autoplay || props.pages.length <= 1 || isUserPaused) {
264
+ return;
265
+ }
266
+ const container = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
267
+ // If container is not yet connected or has width <= 0 (e.g. parent tab hidden),
268
+ // do not abandon autoplay; poll every 1s until visible again
269
+ if (!container || !container.isConnected || container.clientWidth <= 0) {
270
+ loopTimer = setTimeout(() => scheduleAutoplay(), 1000);
271
+ return;
272
+ }
273
+ // If user is currently dragging or touching, wait and retry
274
+ if (isPointerDown || isTouching || isDragging || isInteracting) {
275
+ loopTimer = setTimeout(() => scheduleAutoplay(), 1500);
276
+ return;
277
+ }
278
+ // If hovered on a device with hover support, pause temporarily and check back
279
+ if (isHovered && props.pauseOnHover !== false && canHover()) {
280
+ loopTimer = setTimeout(() => scheduleAutoplay(), 2500);
281
+ return;
282
+ }
283
+ const delay = customDelay !== undefined ? customDelay : interval;
284
+ loopTimer = setTimeout(() => {
285
+ autoNextSlide();
286
+ }, delay);
287
+ };
288
+
289
+ const autoNextSlide = () => {
290
+ const container = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
291
+ if (!container || !container.isConnected || container.clientWidth <= 0) {
292
+ scheduleAutoplay(1000);
293
+ return;
294
+ }
295
+ if (
296
+ isUserPaused ||
297
+ isPointerDown ||
298
+ isTouching ||
299
+ isDragging ||
300
+ isInteracting
301
+ ) {
302
+ scheduleAutoplay(1500);
303
+ return;
304
+ }
305
+ if (isHovered && props.pauseOnHover !== false && canHover()) {
306
+ scheduleAutoplay(2500);
307
+ return;
308
+ }
309
+
310
+ const nextIndex = (slideIndex + 1) % props.pages.length;
311
+ moveSlide(nextIndex);
312
+ };
313
+
314
+ let isPointerDown = false;
315
+ let isTouching = false;
316
+ let isDragging = false;
317
+ let isInteracting = false;
318
+ let wasDragging = false;
319
+ let startX = 0;
320
+ let startY = 0;
321
+ let lastX = 0;
322
+ let startScrollLeft = 0;
323
+ let pointerDownTime = 0;
324
+
325
+ const drawerScrollStop = () => {
326
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
327
+ if (!drawer) return;
328
+ const width = drawer.clientWidth;
329
+ if (width <= 0) {
330
+ scheduleAutoplay(1000);
331
+ return;
332
+ }
333
+ const currentScrollIndex = Math.round(drawer.scrollLeft / width);
334
+ if (currentScrollIndex !== slideIndex && currentScrollIndex >= 0 && currentScrollIndex < props.pages.length) {
335
+ slideIndex = currentScrollIndex;
336
+ resetSlides(slideIndex);
337
+ }
338
+ if (
339
+ !isPointerDown &&
340
+ !isTouching &&
341
+ !isDragging &&
342
+ !isInteracting &&
343
+ !isUserPaused
344
+ ) {
345
+ scheduleAutoplay();
346
+ }
347
+ };
348
+
349
+ const drawerScroll = () => {
350
+ if (isPointerDown || isTouching || isDragging || isInteracting) {
351
+ pauseAutoplay(false);
352
+ return;
353
+ }
354
+ if (manualScroll) return;
355
+ pauseAutoplay(false);
356
+ if (scrollEndTimer) clearTimeout(scrollEndTimer);
357
+ scrollEndTimer = setTimeout(() => {
358
+ drawerScrollStop();
359
+ }, 120);
360
+ };
361
+
362
+ const moveSlide = (targetIndex: number) => {
363
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
364
+ if (!drawer) {
365
+ scheduleAutoplay(1000);
366
+ return;
367
+ }
368
+ const width = drawer.clientWidth;
369
+ if (width <= 0) {
370
+ scheduleAutoplay(1000);
371
+ return;
372
+ }
373
+
374
+ if (props.pages.length > 0) {
375
+ targetIndex = (targetIndex + props.pages.length) % props.pages.length;
376
+ }
377
+ manualScroll = true;
378
+ slideIndex = targetIndex;
379
+ resetSlides(slideIndex);
380
+
381
+ drawer.scrollTo({
382
+ left: targetIndex * width,
383
+ behavior: 'smooth',
384
+ });
385
+
386
+ setTimeout(() => {
387
+ manualScroll = false;
388
+ isInteracting = false;
389
+ if (
390
+ !isPointerDown &&
391
+ !isTouching &&
392
+ !isDragging &&
393
+ !isUserPaused
394
+ ) {
395
+ scheduleAutoplay();
396
+ }
397
+ }, 350);
398
+ };
399
+
400
+ const handleStart = (clientX: number, clientY: number, pointerId?: number) => {
401
+ if (props.draggable === false) return;
402
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
403
+ if (!drawer) return;
404
+
405
+ isPointerDown = true;
406
+ isTouching = true;
407
+ isInteracting = true;
408
+ isDragging = false;
409
+ wasDragging = false;
410
+ startX = clientX;
411
+ startY = clientY;
412
+ lastX = clientX;
413
+ startScrollLeft = drawer.scrollLeft;
414
+ pointerDownTime = Date.now();
415
+
416
+ // Immediately freeze/pause autoplay while pressing down
417
+ pauseAutoplay(false);
418
+ };
419
+
420
+ const handleMove = (clientX: number, clientY: number, e?: any) => {
421
+ if (!isPointerDown && !isTouching) return;
422
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
423
+ if (!drawer) return;
424
+
425
+ lastX = clientX;
426
+ const deltaX = clientX - startX;
427
+ const deltaY = clientY - startY;
428
+
429
+ // Immediately freeze/pause autoplay while sliding
430
+ pauseAutoplay(false);
431
+
432
+ if (!isDragging) {
433
+ // Highly responsive drag detection (2px threshold)
434
+ if (Math.abs(deltaX) > 2) {
435
+ isDragging = true;
436
+ wasDragging = true;
437
+ manualScroll = true;
438
+ if (e && e.pointerId !== undefined) {
439
+ try {
440
+ drawer.setPointerCapture?.(e.pointerId);
441
+ } catch { }
442
+ }
443
+ drawer.classList.add('is-dragging');
444
+ drawer.style.scrollSnapType = 'none';
445
+ drawer.style.scrollBehavior = 'auto';
446
+ }
447
+ }
448
+
449
+ if (isDragging) {
450
+ if (e && e.cancelable) e.preventDefault();
451
+ drawer.scrollLeft = startScrollLeft - deltaX;
452
+ }
453
+ };
454
+
455
+ const handleEnd = (clientX?: number, e?: any) => {
456
+ if (!isPointerDown && !isTouching) return;
457
+ isPointerDown = false;
458
+ isTouching = false;
459
+
460
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
461
+ if (!drawer) return;
462
+
463
+ if (isDragging) {
464
+ isDragging = false;
465
+ drawer.classList.remove('is-dragging');
466
+ drawer.style.scrollSnapType = 'x mandatory';
467
+ drawer.style.scrollBehavior = 'smooth';
468
+ if (e && e.pointerId !== undefined) {
469
+ try {
470
+ drawer.releasePointerCapture?.(e.pointerId);
471
+ } catch { }
472
+ }
473
+
474
+ const finalX = clientX !== undefined ? clientX : lastX;
475
+ const deltaX = finalX - startX;
476
+ const elapsed = Math.max(Date.now() - pointerDownTime, 1);
477
+ const velocity = Math.abs(deltaX) / elapsed;
478
+ const width = drawer.clientWidth || 1;
479
+
480
+ if (Math.abs(deltaX) > width * 0.15 || velocity > 0.25) {
481
+ const direction = deltaX < 0 ? 1 : -1;
482
+ moveSlide(slideIndex + direction);
483
+ } else {
484
+ moveSlide(slideIndex);
485
+ }
486
+ } else {
487
+ // Clean tap without drag
488
+ if (props.pauseOnClick) {
489
+ props.hook?.togglePause ? props.hook.togglePause() : (isUserPaused = !isUserPaused);
490
+ }
491
+ }
492
+
493
+ setTimeout(() => {
494
+ wasDragging = false;
495
+ manualScroll = false;
496
+ isInteracting = false;
497
+ // Resume autoplay after releasing if not user paused
498
+ if (!isPointerDown && !isTouching && !isUserPaused) {
499
+ scheduleAutoplay();
500
+ }
501
+ }, 120);
502
+ };
503
+
504
+ if (props.hook) {
505
+ props.hook.moveTo = moveSlide;
506
+ props.hook.setIndex = moveSlide;
507
+ props.hook.getIndex = () => slideIndex;
508
+ props.hook.isPaused = () => isUserPaused;
509
+ props.hook.setPause = (inPause: boolean) => {
510
+ isUserPaused = inPause;
511
+ if (inPause) {
512
+ pauseAutoplay(true);
513
+ } else {
514
+ scheduleAutoplay();
515
+ }
516
+ };
517
+ props.hook.togglePause = () => {
518
+ const next = !isUserPaused;
519
+ props.hook?.setPause?.(next);
520
+ return next;
521
+ };
522
+ props.hook.next = () => moveSlide(slideIndex + 1);
523
+ props.hook.prev = () => moveSlide(slideIndex - 1);
524
+ }
525
+
526
+ const handleMouseEnter = () => {
527
+ if (props.pauseOnHover !== false && canHover()) {
528
+ isHovered = true;
529
+ pauseAutoplay(false);
530
+ }
531
+ };
532
+
533
+ const handleMouseLeave = () => {
534
+ isHovered = false;
535
+ if (
536
+ !isPointerDown &&
537
+ !isTouching &&
538
+ !isDragging &&
539
+ !isInteracting &&
540
+ !isUserPaused
541
+ ) {
542
+ scheduleAutoplay();
543
+ }
544
+ };
545
+
546
+ let resizeObserver: ResizeObserver | null = null;
547
+ let intersectionObserver: IntersectionObserver | null = null;
548
+ let watchdogTimer: any = null;
549
+
550
+ const wakeUpAutoplay = () => {
551
+ isPointerDown = false;
552
+ isTouching = false;
553
+ isDragging = false;
554
+ isInteracting = false;
555
+ isHovered = false;
556
+ if (autoplay && !isUserPaused) {
557
+ scheduleAutoplay(400);
558
+ }
559
+ };
560
+
561
+ ref.onLoad = async () => {
562
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
563
+ if (drawer) {
564
+ drawer.addEventListener('scrollend', drawerScrollStop);
565
+
566
+ if (typeof ResizeObserver !== 'undefined') {
567
+ resizeObserver = new ResizeObserver((entries) => {
568
+ for (const entry of entries) {
569
+ if (entry.contentRect.width > 0) {
570
+ if (autoplay && !isUserPaused && !loopTimer) {
571
+ scheduleAutoplay(400);
572
+ }
573
+ }
574
+ }
575
+ });
576
+ resizeObserver.observe(drawer);
577
+ }
578
+
579
+ if (typeof IntersectionObserver !== 'undefined') {
580
+ intersectionObserver = new IntersectionObserver((entries) => {
581
+ for (const entry of entries) {
582
+ if (entry.isIntersecting) {
583
+ if (autoplay && !isUserPaused && !loopTimer) {
584
+ scheduleAutoplay(400);
585
+ }
586
+ }
587
+ }
588
+ });
589
+ intersectionObserver.observe(drawer);
590
+ }
591
+ }
592
+
593
+ if (typeof window !== 'undefined') {
594
+ window.addEventListener('focus', wakeUpAutoplay);
595
+ window.addEventListener('updateTheme', wakeUpAutoplay);
596
+ window.addEventListener('theme-bg-change', wakeUpAutoplay);
597
+ window.addEventListener('id-photo-theme-changed', wakeUpAutoplay);
598
+ window.addEventListener('id-photo-tab-switched', wakeUpAutoplay);
599
+ document.addEventListener('visibilitychange', () => {
600
+ if (document.visibilityState === 'visible') {
601
+ wakeUpAutoplay();
602
+ }
603
+ });
604
+ }
605
+
606
+ // Watchdog timer: every 8s ensure rotation hasn't stalled unexpectedly
607
+ watchdogTimer = setInterval(() => {
608
+ if (autoplay && !isUserPaused && !loopTimer) {
609
+ scheduleAutoplay();
610
+ }
611
+ }, 8000);
612
+
613
+ resetSlides(slideIndex);
614
+ if (slideIndex > 0) {
615
+ setTimeout(() => {
616
+ moveSlide(slideIndex);
617
+ }, 50);
618
+ }
619
+ scheduleAutoplay();
620
+ };
621
+
622
+ ref.onUnload = async () => {
623
+ const drawer = ref.$?.('.slide-page-c-list') as HTMLElement | undefined;
624
+ if (drawer) {
625
+ drawer.removeEventListener('scrollend', drawerScrollStop);
626
+ }
627
+ if (resizeObserver) {
628
+ resizeObserver.disconnect();
629
+ resizeObserver = null;
630
+ }
631
+ if (intersectionObserver) {
632
+ intersectionObserver.disconnect();
633
+ intersectionObserver = null;
634
+ }
635
+ if (watchdogTimer) {
636
+ clearInterval(watchdogTimer);
637
+ watchdogTimer = null;
638
+ }
639
+ if (typeof window !== 'undefined') {
640
+ window.removeEventListener('focus', wakeUpAutoplay);
641
+ window.removeEventListener('updateTheme', wakeUpAutoplay);
642
+ window.removeEventListener('theme-bg-change', wakeUpAutoplay);
643
+ window.removeEventListener('id-photo-theme-changed', wakeUpAutoplay);
644
+ window.removeEventListener('id-photo-tab-switched', wakeUpAutoplay);
645
+ document.removeEventListener('visibilitychange', wakeUpAutoplay);
646
+ }
647
+ pauseAutoplay(false);
648
+ };
649
+
650
+ const handleItemClick = (event: any, page: SlidePageItemProps, index: number) => {
651
+ if (wasDragging) {
652
+ event.preventDefault();
653
+ event.stopPropagation();
654
+ return;
655
+ }
656
+ if (page.onClick) {
657
+ page.onClick(event, page, index);
658
+ }
659
+ };
660
+
661
+ return (
662
+ <section
663
+ class={`slide-page-c-box ${props.class || ''}`}
664
+ ref={ref}
665
+ css={props.style}
666
+ onMouseEnter={handleMouseEnter}
667
+ onMouseLeave={handleMouseLeave}
668
+ >
669
+ <div
670
+ class="slide-page-c-list no-scrollbar-container"
671
+ onScroll={drawerScroll}
672
+ onPointerDown={(e: any) => {
673
+ if (e.button !== undefined && e.button !== 0) return;
674
+ handleStart(e.clientX, e.clientY, e.pointerId);
675
+ }}
676
+ onPointerMove={(e: any) => handleMove(e.clientX, e.clientY, e)}
677
+ onPointerUp={(e: any) => handleEnd(e.clientX, e)}
678
+ onPointerCancel={(e: any) => handleEnd(e.clientX, e)}
679
+ onTouchStart={(e: any) => {
680
+ if (e.touches && e.touches[0]) {
681
+ handleStart(e.touches[0].clientX, e.touches[0].clientY);
682
+ }
683
+ }}
684
+ onTouchMove={(e: any) => {
685
+ if (e.touches && e.touches[0]) {
686
+ handleMove(e.touches[0].clientX, e.touches[0].clientY, e);
687
+ }
688
+ }}
689
+ onTouchEnd={(e: any) => {
690
+ const t = e.changedTouches?.[0];
691
+ handleEnd(t ? t.clientX : undefined, e);
692
+ }}
693
+ onTouchCancel={(e: any) => {
694
+ const t = e.changedTouches?.[0];
695
+ handleEnd(t ? t.clientX : undefined, e);
696
+ }}
697
+ onMouseDown={(e: any) => {
698
+ if (e.button !== 0) return;
699
+ handleStart(e.clientX, e.clientY);
700
+ }}
701
+ >
702
+ {props.pages.map((page, index) => {
703
+ if (page.link) {
704
+ return (
705
+ <a
706
+ class={`slide-page-c-item slide-page-c-item-link ${page.id ? `slide-page-item-${page.id}` : ''}`}
707
+ href={page.link}
708
+ target={page.target || '_self'}
709
+ title={page.title}
710
+ onClick={(event: any) => handleItemClick(event, page, index)}
711
+ >
712
+ {page.content}
713
+ </a>
714
+ );
715
+ }
716
+ return (
717
+ <div
718
+ class={`slide-page-c-item ${page.id ? `slide-page-item-${page.id}` : ''}`}
719
+ title={page.title}
720
+ onClick={(event: any) => handleItemClick(event, page, index)}
721
+ >
722
+ {page.content}
723
+ </div>
724
+ );
725
+ })}
726
+ </div>
727
+
728
+ {props.showArrows && props.pages.length > 1 && (
729
+ <>
730
+ <button
731
+ type="button"
732
+ class="slide-page-c-arrow slide-page-c-arrow-prev"
733
+ aria-label="Previous slide"
734
+ onClick={(e: any) => {
735
+ e.preventDefault();
736
+ e.stopPropagation();
737
+ moveSlide(slideIndex - 1);
738
+ scheduleAutoplay(interval);
739
+ }}
740
+ >
741
+ ‹
742
+ </button>
743
+ <button
744
+ type="button"
745
+ class="slide-page-c-arrow slide-page-c-arrow-next"
746
+ aria-label="Next slide"
747
+ onClick={(e: any) => {
748
+ e.preventDefault();
749
+ e.stopPropagation();
750
+ moveSlide(slideIndex + 1);
751
+ scheduleAutoplay(interval);
752
+ }}
753
+ >
754
+ ›
755
+ </button>
756
+ </>
757
+ )}
758
+
759
+ {props.showDots !== false && props.pages.length > 1 && (
760
+ <div class={`slide-page-c-dots ${props.dotsPosition === 'outside' ? 'dots-outside' : ''} ${props.dotClass || ''}`}>
761
+ {props.pages.map((page, index) => (
762
+ <div
763
+ class={`slide-page-c-dot ${index === slideIndex ? 'active' : ''}`}
764
+ title={page.title || `Page ${index + 1}`}
765
+ onClick={(event: any) => {
766
+ event.preventDefault();
767
+ event.stopPropagation();
768
+ moveSlide(index);
769
+ scheduleAutoplay(interval);
770
+ }}
771
+ />
772
+ ))}
773
+ </div>
774
+ )}
775
+ </section>
776
+ );
777
+ };