lazer-slider 1.1.1 → 1.1.3

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/dist/index.js CHANGED
@@ -85,16 +85,19 @@ var updateActiveThumb = (thumbs, currentIndex, activeClass = "active") => {
85
85
  thumb.setAttribute("aria-selected", isActive.toString());
86
86
  });
87
87
  };
88
- var setupKeyboardNavigation = (feed, onPrev, onNext, abortSignal) => {
88
+ var setupKeyboardNavigation = (feed, onPrev, onNext, abortSignal, direction = "horizontal") => {
89
+ const isVertical = direction === "vertical";
90
+ const prevKey = isVertical ? "ArrowUp" : "ArrowLeft";
91
+ const nextKey = isVertical ? "ArrowDown" : "ArrowRight";
89
92
  feed.addEventListener(
90
93
  "keydown",
91
94
  (event) => {
92
95
  switch (event.key) {
93
- case "ArrowLeft":
96
+ case prevKey:
94
97
  event.preventDefault();
95
98
  onPrev();
96
99
  break;
97
- case "ArrowRight":
100
+ case nextKey:
98
101
  event.preventDefault();
99
102
  onNext();
100
103
  break;
@@ -111,21 +114,25 @@ var setupKeyboardNavigation = (feed, onPrev, onNext, abortSignal) => {
111
114
  var createDragState = () => ({
112
115
  isDragging: false,
113
116
  startX: 0,
117
+ startY: 0,
114
118
  startScrollLeft: 0,
119
+ startScrollTop: 0,
115
120
  velocity: 0,
116
121
  lastX: 0,
122
+ lastY: 0,
117
123
  lastTime: 0,
118
124
  momentumId: null
119
125
  });
120
- var findNearestSlide = (feed, slides) => {
126
+ var findNearestSlide = (feed, slides, direction = "horizontal") => {
121
127
  const feedRect = feed.getBoundingClientRect();
122
- const feedCenter = feedRect.left + feedRect.width / 2;
128
+ const isVertical = direction === "vertical";
129
+ const feedCenter = isVertical ? feedRect.top + feedRect.height / 2 : feedRect.left + feedRect.width / 2;
123
130
  let nearestSlide = null;
124
131
  let minDistance = Infinity;
125
132
  for (const slide of slides) {
126
133
  if (slide.offsetParent === null) continue;
127
134
  const slideRect = slide.getBoundingClientRect();
128
- const slideCenter = slideRect.left + slideRect.width / 2;
135
+ const slideCenter = isVertical ? slideRect.top + slideRect.height / 2 : slideRect.left + slideRect.width / 2;
129
136
  const distance = Math.abs(feedCenter - slideCenter);
130
137
  if (distance < minDistance) {
131
138
  minDistance = distance;
@@ -134,20 +141,26 @@ var findNearestSlide = (feed, slides) => {
134
141
  }
135
142
  return nearestSlide;
136
143
  };
137
- var applyMomentum = (state, feed, slides, smoothScrollTo, onDragEnd) => {
144
+ var applyMomentum = (state, feed, slides, smoothScrollTo, onDragEnd, direction = "horizontal") => {
138
145
  const friction = 0.95;
139
146
  const minVelocity = 0.5;
147
+ const isVertical = direction === "vertical";
140
148
  const animate = () => {
141
149
  if (Math.abs(state.velocity) < minVelocity) {
142
150
  state.momentumId = null;
143
- const nearestSlide = findNearestSlide(feed, slides);
151
+ const nearestSlide = findNearestSlide(feed, slides, direction);
144
152
  if (nearestSlide) {
145
- smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic);
153
+ const targetPosition = isVertical ? nearestSlide.offsetTop : nearestSlide.offsetLeft;
154
+ smoothScrollTo(targetPosition, easeOutCubic);
146
155
  }
147
156
  onDragEnd?.();
148
157
  return;
149
158
  }
150
- feed.scrollLeft += state.velocity;
159
+ if (isVertical) {
160
+ feed.scrollTop += state.velocity;
161
+ } else {
162
+ feed.scrollLeft += state.velocity;
163
+ }
151
164
  state.velocity *= friction;
152
165
  state.momentumId = requestAnimationFrame(animate);
153
166
  };
@@ -159,9 +172,16 @@ var getEventX = (event) => {
159
172
  }
160
173
  return event.clientX;
161
174
  };
175
+ var getEventY = (event) => {
176
+ if ("touches" in event) {
177
+ return event.touches[0]?.clientY ?? 0;
178
+ }
179
+ return event.clientY;
180
+ };
162
181
  var setupDragToScroll = (config) => {
163
- const { feed, slides, abortSignal, smoothScrollTo, onDragEnd, dragFree = false } = config;
182
+ const { feed, slides, abortSignal, smoothScrollTo, onDragEnd, direction = "horizontal" } = config;
164
183
  const state = createDragState();
184
+ const isVertical = direction === "vertical";
165
185
  const handleDragStart = (event) => {
166
186
  if (state.momentumId !== null) {
167
187
  cancelAnimationFrame(state.momentumId);
@@ -169,11 +189,13 @@ var setupDragToScroll = (config) => {
169
189
  }
170
190
  state.isDragging = true;
171
191
  state.startX = getEventX(event);
192
+ state.startY = getEventY(event);
172
193
  state.startScrollLeft = feed.scrollLeft;
194
+ state.startScrollTop = feed.scrollTop;
173
195
  state.velocity = 0;
174
196
  state.lastX = state.startX;
197
+ state.lastY = state.startY;
175
198
  state.lastTime = performance.now();
176
- feed.style.cursor = "grabbing";
177
199
  feed.style.userSelect = "none";
178
200
  if (event.type === "mousedown") {
179
201
  event.preventDefault();
@@ -182,14 +204,24 @@ var setupDragToScroll = (config) => {
182
204
  const handleDragMove = (event) => {
183
205
  if (!state.isDragging) return;
184
206
  const currentX = getEventX(event);
207
+ const currentY = getEventY(event);
185
208
  const currentTime = performance.now();
186
- const deltaX = state.startX - currentX;
187
209
  const deltaTime = currentTime - state.lastTime;
188
- feed.scrollLeft = state.startScrollLeft + deltaX;
189
- if (deltaTime > 0) {
190
- state.velocity = (state.lastX - currentX) / deltaTime * 16;
210
+ if (isVertical) {
211
+ const deltaY = state.startY - currentY;
212
+ feed.scrollTop = state.startScrollTop + deltaY;
213
+ if (deltaTime > 0) {
214
+ state.velocity = (state.lastY - currentY) / deltaTime * 16;
215
+ }
216
+ state.lastY = currentY;
217
+ } else {
218
+ const deltaX = state.startX - currentX;
219
+ feed.scrollLeft = state.startScrollLeft + deltaX;
220
+ if (deltaTime > 0) {
221
+ state.velocity = (state.lastX - currentX) / deltaTime * 16;
222
+ }
223
+ state.lastX = currentX;
191
224
  }
192
- state.lastX = currentX;
193
225
  state.lastTime = currentTime;
194
226
  if (event.type === "touchmove") {
195
227
  event.preventDefault();
@@ -198,41 +230,18 @@ var setupDragToScroll = (config) => {
198
230
  const handleDragEnd = () => {
199
231
  if (!state.isDragging) return;
200
232
  state.isDragging = false;
201
- feed.style.cursor = "grab";
202
233
  feed.style.userSelect = "";
203
- if (dragFree) {
204
- if (Math.abs(state.velocity) > 1) {
205
- applyMomentum(state, feed, slides, smoothScrollTo, onDragEnd);
206
- } else {
207
- const nearestSlide = findNearestSlide(feed, slides);
208
- if (nearestSlide) {
209
- smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic);
210
- }
211
- onDragEnd?.();
212
- }
234
+ if (Math.abs(state.velocity) > 1) {
235
+ applyMomentum(state, feed, slides, smoothScrollTo, onDragEnd, direction);
213
236
  } else {
214
- const swipeDistance = state.startX - state.lastX;
215
- const swipeThreshold = 50;
216
- const nearestSlide = findNearestSlide(feed, slides);
217
- if (nearestSlide && Math.abs(swipeDistance) > swipeThreshold) {
218
- const visibleSlides = slides.filter((slide) => slide.offsetParent !== null);
219
- const visibleIndex = visibleSlides.indexOf(nearestSlide);
220
- let targetSlide = null;
221
- if (swipeDistance > 0 && visibleIndex < visibleSlides.length - 1) {
222
- targetSlide = visibleSlides[visibleIndex + 1] ?? nearestSlide;
223
- } else if (swipeDistance < 0 && visibleIndex > 0) {
224
- targetSlide = visibleSlides[visibleIndex - 1] ?? nearestSlide;
225
- } else {
226
- targetSlide = nearestSlide;
227
- }
228
- smoothScrollTo(targetSlide.offsetLeft, easeOutCubic);
229
- } else if (nearestSlide) {
230
- smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic);
237
+ const nearestSlide = findNearestSlide(feed, slides, direction);
238
+ if (nearestSlide) {
239
+ const targetPosition = isVertical ? nearestSlide.offsetTop : nearestSlide.offsetLeft;
240
+ smoothScrollTo(targetPosition, easeOutCubic);
231
241
  }
232
242
  onDragEnd?.();
233
243
  }
234
244
  };
235
- feed.style.cursor = "grab";
236
245
  feed.addEventListener("mousedown", handleDragStart, { signal: abortSignal });
237
246
  document.addEventListener("mousemove", handleDragMove, { signal: abortSignal });
238
247
  document.addEventListener("mouseup", handleDragEnd, { signal: abortSignal });
@@ -301,6 +310,67 @@ var generateBullets = ({
301
310
  return bullets;
302
311
  };
303
312
 
313
+ // src/core/thumbs.ts
314
+ var generateThumbs = ({
315
+ thumbsContainer,
316
+ slides,
317
+ thumbClass,
318
+ thumbActiveClass,
319
+ feedId,
320
+ thumbImageSelector = "img",
321
+ thumbSize
322
+ }) => {
323
+ if (!thumbsContainer || !(thumbsContainer instanceof HTMLElement)) {
324
+ throw new Error("Invalid thumbsContainer: must be a valid HTMLElement");
325
+ }
326
+ if (!Array.isArray(slides) || slides.length === 0) {
327
+ throw new Error("Invalid slides: must be a non-empty array");
328
+ }
329
+ if (!feedId || typeof feedId !== "string") {
330
+ throw new Error("Invalid feedId: must be a non-empty string");
331
+ }
332
+ if (!thumbClass || typeof thumbClass !== "string") {
333
+ throw new Error("Invalid thumbClass: must be a non-empty string");
334
+ }
335
+ thumbsContainer.innerHTML = "";
336
+ thumbsContainer.setAttribute("role", "tablist");
337
+ thumbsContainer.setAttribute("aria-label", "Slide thumbnails");
338
+ const visibleSlides = slides.map((slide, originalIndex) => ({ slide, originalIndex })).filter(({ slide }) => slide.offsetParent !== null);
339
+ if (visibleSlides.length === 0) {
340
+ console.warn("No visible slides found");
341
+ return [];
342
+ }
343
+ const thumbs = visibleSlides.map(({ slide, originalIndex }, visibleIndex) => {
344
+ const thumb = document.createElement("button");
345
+ thumb.type = "button";
346
+ thumb.classList.add(thumbClass);
347
+ if (visibleIndex === 0) {
348
+ thumb.classList.add(thumbActiveClass);
349
+ }
350
+ const sourceImage = slide.querySelector(thumbImageSelector);
351
+ if (sourceImage?.src) {
352
+ const thumbImg = document.createElement("img");
353
+ thumbImg.src = sourceImage.src;
354
+ thumbImg.alt = sourceImage.alt || `Slide ${visibleIndex + 1} thumbnail`;
355
+ thumbImg.draggable = false;
356
+ if (thumbSize) {
357
+ thumbImg.style.width = `${thumbSize.width}px`;
358
+ thumbImg.style.height = `${thumbSize.height}px`;
359
+ thumbImg.style.objectFit = "cover";
360
+ }
361
+ thumb.appendChild(thumbImg);
362
+ }
363
+ thumb.setAttribute("role", "tab");
364
+ thumb.setAttribute("aria-selected", visibleIndex === 0 ? "true" : "false");
365
+ thumb.setAttribute("aria-controls", feedId);
366
+ thumb.setAttribute("aria-label", `Go to slide ${visibleIndex + 1}`);
367
+ thumb.setAttribute("data-slide-index", String(visibleIndex));
368
+ thumbsContainer.appendChild(thumb);
369
+ return thumb;
370
+ });
371
+ return thumbs;
372
+ };
373
+
304
374
  // src/core/marquee.ts
305
375
  var createMarqueeState = () => ({
306
376
  initialized: false,
@@ -415,6 +485,72 @@ var attachMarqueeEventListeners = (settings, state, signal) => {
415
485
  );
416
486
  };
417
487
 
488
+ // src/core/styles.ts
489
+ var CRITICAL_STYLES = `
490
+ /* Lazer Slider - Critical Styles (Auto-injected) */
491
+ .lazer-feed {
492
+ position: relative;
493
+ display: flex;
494
+ overflow-x: auto;
495
+ overflow-y: hidden;
496
+ -webkit-overflow-scrolling: touch;
497
+ scrollbar-width: none;
498
+ scroll-snap-type: x mandatory;
499
+ }
500
+
501
+ .lazer-feed::-webkit-scrollbar {
502
+ display: none;
503
+ }
504
+
505
+ .lazer-feed.lazer-vertical {
506
+ flex-direction: column;
507
+ overflow-x: hidden;
508
+ overflow-y: auto;
509
+ scroll-snap-type: y mandatory;
510
+ }
511
+
512
+ .lazer-slide {
513
+ scroll-snap-align: start;
514
+ flex-shrink: 0;
515
+ }
516
+
517
+ .lazer-feed.is-dragging {
518
+ cursor: grabbing;
519
+ user-select: none;
520
+ scroll-snap-type: none;
521
+ }
522
+
523
+ .lazer-feed:not(.is-dragging) {
524
+ cursor: grab;
525
+ }
526
+ `;
527
+ var stylesInjected = false;
528
+ var STYLE_ID = "lazer-slider-critical-styles";
529
+ var injectStyles = () => {
530
+ if (stylesInjected || typeof document === "undefined") return;
531
+ const existingStyle = document.getElementById(STYLE_ID);
532
+ if (existingStyle) {
533
+ stylesInjected = true;
534
+ return;
535
+ }
536
+ const style = document.createElement("style");
537
+ style.id = STYLE_ID;
538
+ style.textContent = CRITICAL_STYLES;
539
+ document.head.appendChild(style);
540
+ stylesInjected = true;
541
+ };
542
+ var injectStylesOnce = () => {
543
+ injectStyles();
544
+ };
545
+ var removeStyles = () => {
546
+ if (typeof document === "undefined") return;
547
+ const style = document.getElementById(STYLE_ID);
548
+ if (style) {
549
+ style.remove();
550
+ stylesInjected = false;
551
+ }
552
+ };
553
+
418
554
  // src/core/slider.ts
419
555
  var ANIMATION = {
420
556
  MIN_DURATION: 400,
@@ -425,6 +561,7 @@ var ANIMATION = {
425
561
  };
426
562
  var DESKTOP_BREAKPOINT = "(min-width: 64rem)";
427
563
  var createSlider = (settings) => {
564
+ injectStylesOnce();
428
565
  if (!settings.feed) {
429
566
  throw new Error("lazer-slider: feed element is required");
430
567
  }
@@ -434,16 +571,40 @@ var createSlider = (settings) => {
434
571
  if (!settings.feed.id) {
435
572
  settings.feed.id = `lazer-slider-feed-${Math.random().toString(36).substr(2, 9)}`;
436
573
  }
574
+ settings.feed.classList.add("lazer-feed");
575
+ settings.slides.forEach((slide) => {
576
+ slide.classList.add("lazer-slide");
577
+ });
437
578
  if (settings.bulletsContainer && !settings.thumbs) {
438
579
  const bullets = generateBullets({
439
580
  bulletsContainer: settings.bulletsContainer,
440
581
  slides: settings.slides,
441
- bulletClass: settings.bulletsClass ?? "slider-bullet",
582
+ bulletClass: settings.bulletsClass ?? "lazer-bullet",
442
583
  bulletActiveClass: settings.bulletsActiveClass ?? "active",
443
584
  feedId: settings.feed.id
444
585
  });
445
586
  settings.thumbs = bullets;
446
587
  }
588
+ if (settings.thumbsContainer && !settings.thumbs) {
589
+ const thumbs = generateThumbs({
590
+ thumbsContainer: settings.thumbsContainer,
591
+ slides: settings.slides,
592
+ thumbClass: settings.thumbsClass ?? "lazer-thumb",
593
+ thumbActiveClass: settings.thumbsActiveClass ?? "active",
594
+ feedId: settings.feed.id,
595
+ thumbImageSelector: settings.thumbImageSelector ?? "img",
596
+ thumbSize: settings.thumbSize
597
+ });
598
+ settings.thumbs = thumbs;
599
+ }
600
+ const direction = settings.direction ?? "horizontal";
601
+ const isVertical = direction === "vertical";
602
+ if (isVertical) {
603
+ settings.feed.classList.add("lazer-vertical");
604
+ }
605
+ if (settings.marquee) {
606
+ settings.feed.classList.add("lazer-marquee");
607
+ }
447
608
  const state = {
448
609
  currentSlideIndex: 0,
449
610
  isScrolling: false,
@@ -452,7 +613,6 @@ var createSlider = (settings) => {
452
613
  lastWidth: 0,
453
614
  updateThumbTimeout: null,
454
615
  scrollEndTimeout: null,
455
- resizeTimeout: null,
456
616
  abortController: new AbortController(),
457
617
  autoplayIntervalId: null,
458
618
  autoplayPaused: false,
@@ -471,10 +631,10 @@ var createSlider = (settings) => {
471
631
  const marqueeState = createMarqueeState();
472
632
  const easing = settings.easing ?? easeOutExpo;
473
633
  const getFeedRect = () => {
474
- const currentWidth = settings.feed.clientWidth;
475
- if (!state.cachedFeedRect || state.lastWidth !== currentWidth) {
634
+ const currentSize = isVertical ? settings.feed.clientHeight : settings.feed.clientWidth;
635
+ if (!state.cachedFeedRect || state.lastWidth !== currentSize) {
476
636
  state.cachedFeedRect = settings.feed.getBoundingClientRect();
477
- state.lastWidth = currentWidth;
637
+ state.lastWidth = currentSize;
478
638
  }
479
639
  return state.cachedFeedRect;
480
640
  };
@@ -517,26 +677,38 @@ var createSlider = (settings) => {
517
677
  requestAnimationFrame(() => {
518
678
  const firstRealSlide = realSlides[0];
519
679
  if (firstRealSlide) {
520
- settings.feed.scrollLeft = firstRealSlide.offsetLeft;
680
+ if (isVertical) {
681
+ settings.feed.scrollTop = firstRealSlide.offsetTop;
682
+ } else {
683
+ settings.feed.scrollLeft = firstRealSlide.offsetLeft;
684
+ }
521
685
  }
522
686
  });
523
687
  loopState.initialized = true;
524
688
  };
525
- const handleLoopReposition = (direction) => {
689
+ const handleLoopReposition = (navDirection) => {
526
690
  if (!settings.loop || !loopState.initialized) return;
527
691
  state.isLoopRepositioning = true;
528
692
  const realSlides = loopState.realSlides;
529
693
  const totalRealSlides = realSlides.length;
530
- if (direction === "next") {
694
+ if (navDirection === "next") {
531
695
  const firstRealSlide = realSlides[0];
532
696
  if (firstRealSlide) {
533
- settings.feed.scrollLeft = firstRealSlide.offsetLeft;
697
+ if (isVertical) {
698
+ settings.feed.scrollTop = firstRealSlide.offsetTop;
699
+ } else {
700
+ settings.feed.scrollLeft = firstRealSlide.offsetLeft;
701
+ }
534
702
  }
535
703
  state.currentSlideIndex = 0;
536
704
  } else {
537
705
  const lastRealSlide = realSlides[totalRealSlides - 1];
538
706
  if (lastRealSlide) {
539
- settings.feed.scrollLeft = lastRealSlide.offsetLeft;
707
+ if (isVertical) {
708
+ settings.feed.scrollTop = lastRealSlide.offsetTop;
709
+ } else {
710
+ settings.feed.scrollLeft = lastRealSlide.offsetLeft;
711
+ }
540
712
  }
541
713
  state.currentSlideIndex = totalRealSlides - 1;
542
714
  }
@@ -566,39 +738,74 @@ var createSlider = (settings) => {
566
738
  settings.slides.forEach((slide) => {
567
739
  slide.style.flex = "";
568
740
  slide.style.minWidth = "";
741
+ slide.style.minHeight = "";
569
742
  });
570
743
  return;
571
744
  }
572
- const totalGapWidth = gap * (perView - 1);
573
- const slideWidth = `calc((100% - ${totalGapWidth}px) / ${perView})`;
574
- settings.slides.forEach((slide) => {
575
- slide.style.flex = `0 0 ${slideWidth}`;
576
- slide.style.minWidth = slideWidth;
577
- });
745
+ const totalGapSize = gap * (perView - 1);
746
+ const slideSize = `calc((100% - ${totalGapSize}px) / ${perView})`;
747
+ if (isVertical) {
748
+ settings.slides.forEach((slide) => {
749
+ slide.style.flex = `0 0 ${slideSize}`;
750
+ slide.style.minHeight = slideSize;
751
+ slide.style.minWidth = "";
752
+ });
753
+ } else {
754
+ settings.slides.forEach((slide) => {
755
+ slide.style.flex = `0 0 ${slideSize}`;
756
+ slide.style.minWidth = slideSize;
757
+ slide.style.minHeight = "";
758
+ });
759
+ }
578
760
  };
579
761
  const updateScrollbar = () => {
580
762
  if (!settings.scrollbarThumb) return;
581
763
  const feedRect = getFeedRect();
582
- const thumbWidth = feedRect.width / settings.feed.scrollWidth * 100;
583
- settings.scrollbarThumb.style.width = `${thumbWidth}%`;
764
+ if (isVertical) {
765
+ const thumbHeight = feedRect.height / settings.feed.scrollHeight * 100;
766
+ settings.scrollbarThumb.style.height = `${thumbHeight}%`;
767
+ settings.scrollbarThumb.style.width = "";
768
+ } else {
769
+ const thumbWidth = feedRect.width / settings.feed.scrollWidth * 100;
770
+ settings.scrollbarThumb.style.width = `${thumbWidth}%`;
771
+ settings.scrollbarThumb.style.height = "";
772
+ }
584
773
  };
585
774
  const updateScrollbarPosition = () => {
586
775
  if (!settings.scrollbarThumb || !settings.scrollbarTrack) return;
587
- const trackWidth = settings.scrollbarTrack.getBoundingClientRect().width;
588
- const thumbWidth = settings.scrollbarThumb.getBoundingClientRect().width;
589
- const totalTransform = trackWidth - thumbWidth;
590
- const maxScroll = settings.feed.scrollWidth - settings.feed.clientWidth;
591
- const scrollProgress = maxScroll > 0 ? settings.feed.scrollLeft / maxScroll : 0;
592
- settings.scrollbarThumb.style.transform = `translateX(${totalTransform * scrollProgress}px)`;
776
+ if (isVertical) {
777
+ const trackHeight = settings.scrollbarTrack.getBoundingClientRect().height;
778
+ const thumbHeight = settings.scrollbarThumb.getBoundingClientRect().height;
779
+ const totalTransform = trackHeight - thumbHeight;
780
+ const maxScroll = settings.feed.scrollHeight - settings.feed.clientHeight;
781
+ const scrollProgress = maxScroll > 0 ? settings.feed.scrollTop / maxScroll : 0;
782
+ settings.scrollbarThumb.style.transform = `translateY(${totalTransform * scrollProgress}px)`;
783
+ } else {
784
+ const trackWidth = settings.scrollbarTrack.getBoundingClientRect().width;
785
+ const thumbWidth = settings.scrollbarThumb.getBoundingClientRect().width;
786
+ const totalTransform = trackWidth - thumbWidth;
787
+ const maxScroll = settings.feed.scrollWidth - settings.feed.clientWidth;
788
+ const scrollProgress = maxScroll > 0 ? settings.feed.scrollLeft / maxScroll : 0;
789
+ settings.scrollbarThumb.style.transform = `translateX(${totalTransform * scrollProgress}px)`;
790
+ }
593
791
  };
594
792
  const updateControlsVisibility = () => {
595
793
  if (state.isLoopRepositioning) {
596
794
  return;
597
795
  }
598
796
  const feedRect = getFeedRect();
599
- const isAtStart = settings.feed.scrollLeft <= 1;
600
- const isAtEnd = settings.feed.scrollLeft + feedRect.width >= settings.feed.scrollWidth - 1;
601
- const shouldHideScrollbar = settings.feed.scrollWidth <= feedRect.width;
797
+ let isAtStart;
798
+ let isAtEnd;
799
+ let shouldHideScrollbar;
800
+ if (isVertical) {
801
+ isAtStart = settings.feed.scrollTop <= 1;
802
+ isAtEnd = settings.feed.scrollTop + feedRect.height >= settings.feed.scrollHeight - 1;
803
+ shouldHideScrollbar = settings.feed.scrollHeight <= feedRect.height;
804
+ } else {
805
+ isAtStart = settings.feed.scrollLeft <= 1;
806
+ isAtEnd = settings.feed.scrollLeft + feedRect.width >= settings.feed.scrollWidth - 1;
807
+ shouldHideScrollbar = settings.feed.scrollWidth <= feedRect.width;
808
+ }
602
809
  if (settings.scrollbarTrack) {
603
810
  settings.scrollbarTrack.style.display = shouldHideScrollbar ? "none" : "block";
604
811
  }
@@ -632,21 +839,25 @@ var createSlider = (settings) => {
632
839
  const viewportVisibleSlides = slidesToCheck.filter((slide) => {
633
840
  const slideRect = slide.getBoundingClientRect();
634
841
  const tolerance = 20;
842
+ if (isVertical) {
843
+ return slideRect.bottom > feedRect.top + tolerance && slideRect.top < feedRect.bottom - tolerance;
844
+ }
635
845
  return slideRect.right > feedRect.left + tolerance && slideRect.left < feedRect.right - tolerance;
636
846
  });
637
847
  if (viewportVisibleSlides.length && viewportVisibleSlides[0]) {
638
848
  const newIndex = slidesToCheck.indexOf(viewportVisibleSlides[0]);
639
849
  if (newIndex !== -1) {
640
850
  state.currentSlideIndex = newIndex;
851
+ const currentScroll = isVertical ? settings.feed.scrollTop : settings.feed.scrollLeft;
641
852
  settings.onScroll?.({
642
- currentScroll: settings.feed.scrollLeft,
853
+ currentScroll,
643
854
  currentSlideIndex: state.currentSlideIndex
644
855
  });
645
856
  }
646
857
  }
647
858
  };
648
859
  const smoothScrollTo = (target, customEasing = easing, onComplete) => {
649
- const start = settings.feed.scrollLeft;
860
+ const start = isVertical ? settings.feed.scrollTop : settings.feed.scrollLeft;
650
861
  const distance = Math.abs(target - start);
651
862
  const duration = Math.min(
652
863
  ANIMATION.MAX_DURATION,
@@ -657,11 +868,20 @@ var createSlider = (settings) => {
657
868
  const elapsed = (currentTime - startTime) / duration;
658
869
  const progress = Math.min(elapsed, 1);
659
870
  const ease = customEasing(progress);
660
- settings.feed.scrollLeft = start + (target - start) * ease;
871
+ const scrollPosition = start + (target - start) * ease;
872
+ if (isVertical) {
873
+ settings.feed.scrollTop = scrollPosition;
874
+ } else {
875
+ settings.feed.scrollLeft = scrollPosition;
876
+ }
661
877
  if (progress < 1) {
662
878
  requestAnimationFrame(animateScroll);
663
879
  } else {
664
- settings.feed.scrollLeft = target;
880
+ if (isVertical) {
881
+ settings.feed.scrollTop = target;
882
+ } else {
883
+ settings.feed.scrollLeft = target;
884
+ }
665
885
  onComplete?.();
666
886
  }
667
887
  };
@@ -680,16 +900,17 @@ var createSlider = (settings) => {
680
900
  state.updateThumbTimeout = setTimeout(() => {
681
901
  state.isScrolling = false;
682
902
  }, ANIMATION.THUMB_UPDATE_DELAY);
683
- smoothScrollTo(settings.slides[index].offsetLeft);
903
+ const targetPosition = isVertical ? settings.slides[index].offsetTop : settings.slides[index].offsetLeft;
904
+ smoothScrollTo(targetPosition);
684
905
  };
685
- const handleNavButtonClick = (direction) => {
906
+ const handleNavButtonClick = (navDirection) => {
686
907
  const realSlides = loopState.initialized ? loopState.realSlides : getVisibleSlides();
687
908
  const slidesToScroll = isDesktop() ? settings.desktopSlidesPerScroll ?? 1 : settings.mobileSlidesPerScroll ?? 1;
688
909
  const totalRealSlides = realSlides.length;
689
910
  updateCurrentSlideIndex();
690
911
  let targetSlide;
691
912
  let needsReposition = false;
692
- if (direction === "prev") {
913
+ if (navDirection === "prev") {
693
914
  if (settings.loop && loopState.initialized && state.currentSlideIndex === 0) {
694
915
  const prependedClones = loopState.clonedSlides.filter(
695
916
  (clone) => clone.getAttribute("data-lazer-clone") === "prepend"
@@ -716,17 +937,19 @@ var createSlider = (settings) => {
716
937
  }
717
938
  }
718
939
  if (!targetSlide) return;
940
+ const currentScroll = isVertical ? settings.feed.scrollTop : settings.feed.scrollLeft;
719
941
  settings.onScrollStart?.({
720
- currentScroll: settings.feed.scrollLeft,
942
+ currentScroll,
721
943
  target: targetSlide,
722
- direction
944
+ direction: navDirection
723
945
  });
946
+ const targetPosition = isVertical ? targetSlide.offsetTop : targetSlide.offsetLeft;
724
947
  if (needsReposition) {
725
- smoothScrollTo(targetSlide.offsetLeft, easing, () => {
726
- handleLoopReposition(direction);
948
+ smoothScrollTo(targetPosition, easing, () => {
949
+ handleLoopReposition(navDirection);
727
950
  });
728
951
  } else {
729
- smoothScrollTo(targetSlide.offsetLeft);
952
+ smoothScrollTo(targetPosition);
730
953
  }
731
954
  };
732
955
  const updateScrollPosition = () => {
@@ -741,8 +964,9 @@ var createSlider = (settings) => {
741
964
  }
742
965
  state.scrollEndTimeout = setTimeout(() => {
743
966
  state.isScrolling = false;
967
+ const currentScroll = isVertical ? settings.feed.scrollTop : settings.feed.scrollLeft;
744
968
  settings.onScrollEnd?.({
745
- currentScroll: settings.feed.scrollLeft,
969
+ currentScroll,
746
970
  currentSlideIndex: state.currentSlideIndex
747
971
  });
748
972
  }, ANIMATION.SCROLL_END_DELAY);
@@ -757,20 +981,8 @@ var createSlider = (settings) => {
757
981
  }
758
982
  };
759
983
  const handleWindowResize = () => {
760
- if (state.resizeTimeout) {
761
- clearTimeout(state.resizeTimeout);
762
- }
763
- state.resizeTimeout = setTimeout(() => {
764
- state.cachedFeedRect = null;
765
- updateCurrentSlideIndex();
766
- const currentIndex = state.currentSlideIndex;
767
- refresh();
768
- const slides = loopState.initialized ? loopState.realSlides : getVisibleSlides();
769
- const targetSlide = slides[currentIndex];
770
- if (targetSlide) {
771
- settings.feed.scrollLeft = targetSlide.offsetLeft;
772
- }
773
- }, 150);
984
+ state.cachedFeedRect = null;
985
+ refresh();
774
986
  };
775
987
  const attachEventListeners = () => {
776
988
  const { signal } = state.abortController;
@@ -803,9 +1015,10 @@ var createSlider = (settings) => {
803
1015
  settings.feed,
804
1016
  () => handleNavButtonClick("prev"),
805
1017
  () => handleNavButtonClick("next"),
806
- signal
1018
+ signal,
1019
+ direction
807
1020
  );
808
- if (settings.enableDragToScroll) {
1021
+ if (settings.enableDragToScroll !== false) {
809
1022
  dragState = setupDragToScroll({
810
1023
  feed: settings.feed,
811
1024
  slides: settings.slides,
@@ -815,7 +1028,7 @@ var createSlider = (settings) => {
815
1028
  updateCurrentSlideIndex();
816
1029
  updateActiveThumb(settings.thumbs, state.currentSlideIndex);
817
1030
  },
818
- dragFree: settings.dragFree
1031
+ direction
819
1032
  });
820
1033
  }
821
1034
  if (settings.autoplay && settings.pauseOnHover !== false) {
@@ -870,7 +1083,8 @@ var createSlider = (settings) => {
870
1083
  if (!targetSlide) return;
871
1084
  state.currentSlideIndex = safeIndex;
872
1085
  updateActiveThumb(settings.thumbs, safeIndex);
873
- smoothScrollTo(targetSlide.offsetLeft);
1086
+ const targetPosition = isVertical ? targetSlide.offsetTop : targetSlide.offsetLeft;
1087
+ smoothScrollTo(targetPosition);
874
1088
  };
875
1089
  const refresh = () => {
876
1090
  state.cachedFeedRect = null;
@@ -892,9 +1106,6 @@ var createSlider = (settings) => {
892
1106
  if (state.scrollEndTimeout) {
893
1107
  clearTimeout(state.scrollEndTimeout);
894
1108
  }
895
- if (state.resizeTimeout) {
896
- clearTimeout(state.resizeTimeout);
897
- }
898
1109
  if (dragState) {
899
1110
  cleanupDrag(dragState);
900
1111
  }
@@ -950,6 +1161,9 @@ export {
950
1161
  easeOutExpo,
951
1162
  easeOutQuad,
952
1163
  generateBullets,
953
- linear
1164
+ generateThumbs,
1165
+ injectStyles,
1166
+ linear,
1167
+ removeStyles
954
1168
  };
955
1169
  //# sourceMappingURL=index.js.map