lazer-slider 1.0.9 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -9
- package/dist/index.cjs +119 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -56
- package/dist/index.d.ts +17 -56
- package/dist/index.js +118 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -160,7 +160,7 @@ var getEventX = (event) => {
|
|
|
160
160
|
return event.clientX;
|
|
161
161
|
};
|
|
162
162
|
var setupDragToScroll = (config) => {
|
|
163
|
-
const { feed, slides, abortSignal, smoothScrollTo, onDragEnd } = config;
|
|
163
|
+
const { feed, slides, abortSignal, smoothScrollTo, onDragEnd, dragFree = false } = config;
|
|
164
164
|
const state = createDragState();
|
|
165
165
|
const handleDragStart = (event) => {
|
|
166
166
|
if (state.momentumId !== null) {
|
|
@@ -200,11 +200,33 @@ var setupDragToScroll = (config) => {
|
|
|
200
200
|
state.isDragging = false;
|
|
201
201
|
feed.style.cursor = "grab";
|
|
202
202
|
feed.style.userSelect = "";
|
|
203
|
-
if (
|
|
204
|
-
|
|
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
|
+
}
|
|
205
213
|
} else {
|
|
214
|
+
const swipeDistance = state.startX - state.lastX;
|
|
215
|
+
const swipeThreshold = 50;
|
|
206
216
|
const nearestSlide = findNearestSlide(feed, slides);
|
|
207
|
-
if (nearestSlide) {
|
|
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) {
|
|
208
230
|
smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic);
|
|
209
231
|
}
|
|
210
232
|
onDragEnd?.();
|
|
@@ -220,7 +242,6 @@ var setupDragToScroll = (config) => {
|
|
|
220
242
|
});
|
|
221
243
|
feed.addEventListener("touchmove", handleDragMove, {
|
|
222
244
|
passive: false,
|
|
223
|
-
// Need to prevent default
|
|
224
245
|
signal: abortSignal
|
|
225
246
|
});
|
|
226
247
|
feed.addEventListener("touchend", handleDragEnd, { signal: abortSignal });
|
|
@@ -234,6 +255,52 @@ var cleanupDrag = (state) => {
|
|
|
234
255
|
}
|
|
235
256
|
};
|
|
236
257
|
|
|
258
|
+
// src/core/bullets.ts
|
|
259
|
+
var generateBullets = ({
|
|
260
|
+
bulletsContainer,
|
|
261
|
+
slides,
|
|
262
|
+
bulletClass,
|
|
263
|
+
bulletActiveClass,
|
|
264
|
+
feedId
|
|
265
|
+
}) => {
|
|
266
|
+
if (!bulletsContainer || !(bulletsContainer instanceof HTMLElement)) {
|
|
267
|
+
throw new Error("Invalid bulletsContainer: must be a valid HTMLElement");
|
|
268
|
+
}
|
|
269
|
+
if (!Array.isArray(slides) || slides.length === 0) {
|
|
270
|
+
throw new Error("Invalid slides: must be a non-empty array");
|
|
271
|
+
}
|
|
272
|
+
if (!feedId || typeof feedId !== "string") {
|
|
273
|
+
throw new Error("Invalid feedId: must be a non-empty string");
|
|
274
|
+
}
|
|
275
|
+
if (!bulletClass || typeof bulletClass !== "string") {
|
|
276
|
+
throw new Error("Invalid bulletClass: must be a non-empty string");
|
|
277
|
+
}
|
|
278
|
+
bulletsContainer.innerHTML = "";
|
|
279
|
+
bulletsContainer.setAttribute("role", "tablist");
|
|
280
|
+
bulletsContainer.setAttribute("aria-label", "Slide navigation");
|
|
281
|
+
const visibleSlides = slides.map((slide, originalIndex) => ({ slide, originalIndex })).filter(({ slide }) => slide.offsetParent !== null);
|
|
282
|
+
if (visibleSlides.length === 0) {
|
|
283
|
+
console.warn("No visible slides found");
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
const bullets = visibleSlides.map(({ slide, originalIndex }, visibleIndex) => {
|
|
287
|
+
const bullet = document.createElement("button");
|
|
288
|
+
bullet.type = "button";
|
|
289
|
+
bullet.classList.add(bulletClass);
|
|
290
|
+
if (visibleIndex === 0) {
|
|
291
|
+
bullet.classList.add(bulletActiveClass);
|
|
292
|
+
}
|
|
293
|
+
bullet.setAttribute("role", "tab");
|
|
294
|
+
bullet.setAttribute("aria-selected", visibleIndex === 0 ? "true" : "false");
|
|
295
|
+
bullet.setAttribute("aria-controls", feedId);
|
|
296
|
+
bullet.setAttribute("aria-label", `Go to slide ${visibleIndex + 1}`);
|
|
297
|
+
bullet.setAttribute("data-slide-index", String(visibleIndex));
|
|
298
|
+
bulletsContainer.appendChild(bullet);
|
|
299
|
+
return bullet;
|
|
300
|
+
});
|
|
301
|
+
return bullets;
|
|
302
|
+
};
|
|
303
|
+
|
|
237
304
|
// src/core/marquee.ts
|
|
238
305
|
var createMarqueeState = () => ({
|
|
239
306
|
initialized: false,
|
|
@@ -364,6 +431,19 @@ var createSlider = (settings) => {
|
|
|
364
431
|
if (!settings.slides?.length) {
|
|
365
432
|
throw new Error("lazer-slider: slides array is required and must not be empty");
|
|
366
433
|
}
|
|
434
|
+
if (!settings.feed.id) {
|
|
435
|
+
settings.feed.id = `lazer-slider-feed-${Math.random().toString(36).substr(2, 9)}`;
|
|
436
|
+
}
|
|
437
|
+
if (settings.bulletsContainer && !settings.thumbs) {
|
|
438
|
+
const bullets = generateBullets({
|
|
439
|
+
bulletsContainer: settings.bulletsContainer,
|
|
440
|
+
slides: settings.slides,
|
|
441
|
+
bulletClass: settings.bulletsClass ?? "slider-bullet",
|
|
442
|
+
bulletActiveClass: settings.bulletsActiveClass ?? "active",
|
|
443
|
+
feedId: settings.feed.id
|
|
444
|
+
});
|
|
445
|
+
settings.thumbs = bullets;
|
|
446
|
+
}
|
|
367
447
|
const state = {
|
|
368
448
|
currentSlideIndex: 0,
|
|
369
449
|
isScrolling: false,
|
|
@@ -372,12 +452,14 @@ var createSlider = (settings) => {
|
|
|
372
452
|
lastWidth: 0,
|
|
373
453
|
updateThumbTimeout: null,
|
|
374
454
|
scrollEndTimeout: null,
|
|
455
|
+
resizeTimeout: null,
|
|
375
456
|
abortController: new AbortController(),
|
|
376
457
|
autoplayIntervalId: null,
|
|
377
458
|
autoplayPaused: false,
|
|
378
459
|
marqueeAnimationId: null,
|
|
379
460
|
marqueePaused: false,
|
|
380
|
-
marqueeLastTimestamp: 0
|
|
461
|
+
marqueeLastTimestamp: 0,
|
|
462
|
+
isLoopRepositioning: false
|
|
381
463
|
};
|
|
382
464
|
let dragState = null;
|
|
383
465
|
const loopState = {
|
|
@@ -442,6 +524,7 @@ var createSlider = (settings) => {
|
|
|
442
524
|
};
|
|
443
525
|
const handleLoopReposition = (direction) => {
|
|
444
526
|
if (!settings.loop || !loopState.initialized) return;
|
|
527
|
+
state.isLoopRepositioning = true;
|
|
445
528
|
const realSlides = loopState.realSlides;
|
|
446
529
|
const totalRealSlides = realSlides.length;
|
|
447
530
|
if (direction === "next") {
|
|
@@ -457,6 +540,12 @@ var createSlider = (settings) => {
|
|
|
457
540
|
}
|
|
458
541
|
state.currentSlideIndex = totalRealSlides - 1;
|
|
459
542
|
}
|
|
543
|
+
requestAnimationFrame(() => {
|
|
544
|
+
requestAnimationFrame(() => {
|
|
545
|
+
state.isLoopRepositioning = false;
|
|
546
|
+
updateControlsVisibility();
|
|
547
|
+
});
|
|
548
|
+
});
|
|
460
549
|
};
|
|
461
550
|
const cleanupLoopClones = () => {
|
|
462
551
|
if (!loopState.initialized) return;
|
|
@@ -503,6 +592,9 @@ var createSlider = (settings) => {
|
|
|
503
592
|
settings.scrollbarThumb.style.transform = `translateX(${totalTransform * scrollProgress}px)`;
|
|
504
593
|
};
|
|
505
594
|
const updateControlsVisibility = () => {
|
|
595
|
+
if (state.isLoopRepositioning) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
506
598
|
const feedRect = getFeedRect();
|
|
507
599
|
const isAtStart = settings.feed.scrollLeft <= 1;
|
|
508
600
|
const isAtEnd = settings.feed.scrollLeft + feedRect.width >= settings.feed.scrollWidth - 1;
|
|
@@ -665,8 +757,20 @@ var createSlider = (settings) => {
|
|
|
665
757
|
}
|
|
666
758
|
};
|
|
667
759
|
const handleWindowResize = () => {
|
|
668
|
-
state.
|
|
669
|
-
|
|
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);
|
|
670
774
|
};
|
|
671
775
|
const attachEventListeners = () => {
|
|
672
776
|
const { signal } = state.abortController;
|
|
@@ -710,7 +814,8 @@ var createSlider = (settings) => {
|
|
|
710
814
|
onDragEnd: () => {
|
|
711
815
|
updateCurrentSlideIndex();
|
|
712
816
|
updateActiveThumb(settings.thumbs, state.currentSlideIndex);
|
|
713
|
-
}
|
|
817
|
+
},
|
|
818
|
+
dragFree: settings.dragFree
|
|
714
819
|
});
|
|
715
820
|
}
|
|
716
821
|
if (settings.autoplay && settings.pauseOnHover !== false) {
|
|
@@ -787,6 +892,9 @@ var createSlider = (settings) => {
|
|
|
787
892
|
if (state.scrollEndTimeout) {
|
|
788
893
|
clearTimeout(state.scrollEndTimeout);
|
|
789
894
|
}
|
|
895
|
+
if (state.resizeTimeout) {
|
|
896
|
+
clearTimeout(state.resizeTimeout);
|
|
897
|
+
}
|
|
790
898
|
if (dragState) {
|
|
791
899
|
cleanupDrag(dragState);
|
|
792
900
|
}
|
|
@@ -841,6 +949,7 @@ export {
|
|
|
841
949
|
easeOutCubic,
|
|
842
950
|
easeOutExpo,
|
|
843
951
|
easeOutQuad,
|
|
952
|
+
generateBullets,
|
|
844
953
|
linear
|
|
845
954
|
};
|
|
846
955
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/easing.ts","../src/core/accessibility.ts","../src/core/drag.ts","../src/core/marquee.ts","../src/core/slider.ts"],"sourcesContent":["import type { EasingFunction } from './types.js'\n\n/**\n * Exponential ease-out - starts fast, decelerates smoothly\n * Best for scroll animations as it feels natural and responsive\n */\nexport const easeOutExpo: EasingFunction = (t) =>\n t === 1 ? 1 : 1 - Math.pow(2, -10 * t)\n\n/**\n * Cubic ease-out - smoother deceleration than exponential\n */\nexport const easeOutCubic: EasingFunction = (t) => 1 - Math.pow(1 - t, 3)\n\n/**\n * Cubic ease-in-out - smooth acceleration and deceleration\n */\nexport const easeInOutCubic: EasingFunction = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n\n/**\n * Quadratic ease-out - gentle deceleration\n */\nexport const easeOutQuad: EasingFunction = (t) => 1 - (1 - t) * (1 - t)\n\n/**\n * Linear - no easing, constant speed\n */\nexport const linear: EasingFunction = (t) => t\n","import type { SliderSettings } from './types.js'\n\n/**\n * Generate a unique ID for the slider\n */\nexport const generateSliderId = (): string =>\n `slider-${Math.random().toString(36).substring(2, 9)}`\n\n/**\n * Initialize ARIA attributes for accessibility\n */\nexport const initAria = (settings: SliderSettings): void => {\n const { feed, prevSlideButton, nextSlideButton, thumbs, slides } = settings\n\n // Ensure feed has an ID for aria-controls references\n if (!feed.id) {\n feed.id = generateSliderId()\n }\n\n // Set up feed as a scrollable region\n feed.setAttribute('role', 'region')\n feed.setAttribute('aria-label', 'Carousel')\n feed.setAttribute('aria-roledescription', 'carousel')\n\n // Remove tabindex to allow natural tab order\n feed.removeAttribute('tabindex')\n\n // Set up slides with proper roles\n slides.forEach((slide, index) => {\n slide.setAttribute('role', 'group')\n slide.setAttribute('aria-roledescription', 'slide')\n slide.setAttribute('aria-label', `Slide ${index + 1} of ${slides.length}`)\n })\n\n // Set up previous button\n if (prevSlideButton) {\n prevSlideButton.setAttribute('aria-label', 'Previous slide')\n prevSlideButton.setAttribute('aria-controls', feed.id)\n prevSlideButton.setAttribute('tabindex', '0')\n if (prevSlideButton.tagName !== 'BUTTON') {\n prevSlideButton.setAttribute('role', 'button')\n }\n }\n\n // Set up next button\n if (nextSlideButton) {\n nextSlideButton.setAttribute('aria-label', 'Next slide')\n nextSlideButton.setAttribute('aria-controls', feed.id)\n nextSlideButton.setAttribute('tabindex', '0')\n if (nextSlideButton.tagName !== 'BUTTON') {\n nextSlideButton.setAttribute('role', 'button')\n }\n }\n\n // Set up thumbnail/dot navigation\n if (thumbs?.length) {\n thumbs.forEach((thumb, index) => {\n if (thumb.tagName !== 'BUTTON') {\n thumb.setAttribute('role', 'button')\n }\n thumb.setAttribute('aria-label', `Go to slide ${index + 1}`)\n thumb.setAttribute('tabindex', '0')\n thumb.setAttribute('aria-controls', feed.id)\n })\n }\n}\n\n/**\n * Toggle visibility of navigation controls with proper ARIA handling\n */\nexport const toggleControlVisibility = (\n button: HTMLElement | null | undefined,\n shouldShow: boolean,\n feedElement?: HTMLElement\n): void => {\n if (!button) return\n\n // If hiding the button while it has focus, move focus to feed\n if (!shouldShow && button === document.activeElement && feedElement) {\n feedElement.focus()\n }\n\n // Update visual state with transition\n const transition = 'opacity 0.3s ease'\n const opacity = shouldShow ? '1' : '0'\n\n Object.assign(button.style, {\n opacity,\n transition,\n pointerEvents: shouldShow ? 'auto' : 'none'\n })\n\n // Update ARIA state\n if (!shouldShow) {\n button.setAttribute('aria-hidden', 'true')\n button.setAttribute('tabindex', '-1')\n } else {\n button.removeAttribute('aria-hidden')\n button.setAttribute('tabindex', '0')\n }\n\n // Hide from layout after transition if not visible\n if (!shouldShow) {\n setTimeout(() => {\n if (button.style.opacity === '0') {\n button.style.visibility = 'hidden'\n }\n }, 300)\n } else {\n button.style.visibility = 'visible'\n }\n}\n\n/**\n * Update active state on thumbnail elements\n */\nexport const updateActiveThumb = (\n thumbs: HTMLElement[] | undefined,\n currentIndex: number,\n activeClass: string = 'active'\n): void => {\n if (!thumbs?.length) return\n\n thumbs.forEach((thumb, index) => {\n const isActive = index === currentIndex\n thumb.classList.toggle(activeClass, isActive)\n thumb.setAttribute('aria-selected', isActive.toString())\n })\n}\n\n/**\n * Set up keyboard navigation for the slider\n */\nexport const setupKeyboardNavigation = (\n feed: HTMLElement,\n onPrev: () => void,\n onNext: () => void,\n abortSignal: AbortSignal\n): void => {\n feed.addEventListener(\n 'keydown',\n (event: KeyboardEvent) => {\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault()\n onPrev()\n break\n case 'ArrowRight':\n event.preventDefault()\n onNext()\n break\n }\n },\n { signal: abortSignal }\n )\n\n // Make feed focusable for keyboard navigation\n if (!feed.hasAttribute('tabindex')) {\n feed.setAttribute('tabindex', '0')\n }\n}\n","import type { DragState, EasingFunction } from './types.js'\nimport { easeOutCubic } from './easing.js'\n\n/**\n * Configuration for drag behavior\n */\ninterface DragConfig {\n /** Feed element to enable dragging on */\n feed: HTMLElement\n /** Slide elements for snap-to-slide calculation */\n slides: HTMLElement[]\n /** AbortSignal for cleanup */\n abortSignal: AbortSignal\n /** Callback to smooth scroll to a position */\n smoothScrollTo: (target: number, easing?: EasingFunction) => void\n /** Callback when drag ends (for updating state) */\n onDragEnd?: () => void\n}\n\n/**\n * Create initial drag state\n */\nexport const createDragState = (): DragState => ({\n isDragging: false,\n startX: 0,\n startScrollLeft: 0,\n velocity: 0,\n lastX: 0,\n lastTime: 0,\n momentumId: null\n})\n\n/**\n * Find the nearest slide to snap to after drag\n */\nconst findNearestSlide = (\n feed: HTMLElement,\n slides: HTMLElement[]\n): HTMLElement | null => {\n const feedRect = feed.getBoundingClientRect()\n const feedCenter = feedRect.left + feedRect.width / 2\n\n let nearestSlide: HTMLElement | null = null\n let minDistance = Infinity\n\n for (const slide of slides) {\n if (slide.offsetParent === null) continue // Skip hidden slides\n\n const slideRect = slide.getBoundingClientRect()\n const slideCenter = slideRect.left + slideRect.width / 2\n const distance = Math.abs(feedCenter - slideCenter)\n\n if (distance < minDistance) {\n minDistance = distance\n nearestSlide = slide\n }\n }\n\n return nearestSlide\n}\n\n/**\n * Apply momentum scrolling after drag release\n */\nconst applyMomentum = (\n state: DragState,\n feed: HTMLElement,\n slides: HTMLElement[],\n smoothScrollTo: (target: number, easing?: EasingFunction) => void,\n onDragEnd?: () => void\n): void => {\n const friction = 0.95\n const minVelocity = 0.5\n\n const animate = () => {\n if (Math.abs(state.velocity) < minVelocity) {\n state.momentumId = null\n\n // Snap to nearest slide\n const nearestSlide = findNearestSlide(feed, slides)\n if (nearestSlide) {\n smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic)\n }\n\n onDragEnd?.()\n return\n }\n\n feed.scrollLeft += state.velocity\n state.velocity *= friction\n\n state.momentumId = requestAnimationFrame(animate)\n }\n\n state.momentumId = requestAnimationFrame(animate)\n}\n\n/**\n * Get X position from mouse or touch event\n */\nconst getEventX = (event: MouseEvent | TouchEvent): number => {\n if ('touches' in event) {\n return event.touches[0]?.clientX ?? 0\n }\n return event.clientX\n}\n\n/**\n * Set up drag-to-scroll functionality\n */\nexport const setupDragToScroll = (config: DragConfig): DragState => {\n const { feed, slides, abortSignal, smoothScrollTo, onDragEnd } = config\n const state = createDragState()\n\n const handleDragStart = (event: MouseEvent | TouchEvent) => {\n // Cancel any ongoing momentum animation\n if (state.momentumId !== null) {\n cancelAnimationFrame(state.momentumId)\n state.momentumId = null\n }\n\n state.isDragging = true\n state.startX = getEventX(event)\n state.startScrollLeft = feed.scrollLeft\n state.velocity = 0\n state.lastX = state.startX\n state.lastTime = performance.now()\n\n // Visual feedback\n feed.style.cursor = 'grabbing'\n feed.style.userSelect = 'none'\n\n // Prevent default for mouse to avoid text selection\n if (event.type === 'mousedown') {\n event.preventDefault()\n }\n }\n\n const handleDragMove = (event: MouseEvent | TouchEvent) => {\n if (!state.isDragging) return\n\n const currentX = getEventX(event)\n const currentTime = performance.now()\n const deltaX = state.startX - currentX\n const deltaTime = currentTime - state.lastTime\n\n // Update scroll position\n feed.scrollLeft = state.startScrollLeft + deltaX\n\n // Calculate velocity for momentum\n if (deltaTime > 0) {\n state.velocity = (state.lastX - currentX) / deltaTime * 16 // Normalize to ~60fps\n }\n\n state.lastX = currentX\n state.lastTime = currentTime\n\n // Prevent default to stop page scrolling on touch\n if (event.type === 'touchmove') {\n event.preventDefault()\n }\n }\n\n const handleDragEnd = () => {\n if (!state.isDragging) return\n\n state.isDragging = false\n\n // Reset visual feedback\n feed.style.cursor = 'grab'\n feed.style.userSelect = ''\n\n // Apply momentum if velocity is significant\n if (Math.abs(state.velocity) > 1) {\n applyMomentum(state, feed, slides, smoothScrollTo, onDragEnd)\n } else {\n // Snap to nearest slide immediately\n const nearestSlide = findNearestSlide(feed, slides)\n if (nearestSlide) {\n smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic)\n }\n onDragEnd?.()\n }\n }\n\n // Set initial cursor\n feed.style.cursor = 'grab'\n\n // Mouse events\n feed.addEventListener('mousedown', handleDragStart, { signal: abortSignal })\n document.addEventListener('mousemove', handleDragMove, { signal: abortSignal })\n document.addEventListener('mouseup', handleDragEnd, { signal: abortSignal })\n\n // Touch events\n feed.addEventListener('touchstart', handleDragStart, {\n passive: true,\n signal: abortSignal\n })\n feed.addEventListener('touchmove', handleDragMove, {\n passive: false, // Need to prevent default\n signal: abortSignal\n })\n feed.addEventListener('touchend', handleDragEnd, { signal: abortSignal })\n\n // Handle mouse leaving the window\n document.addEventListener('mouseleave', handleDragEnd, { signal: abortSignal })\n\n return state\n}\n\n/**\n * Clean up drag state (cancel any pending animations)\n */\nexport const cleanupDrag = (state: DragState): void => {\n if (state.momentumId !== null) {\n cancelAnimationFrame(state.momentumId)\n state.momentumId = null\n }\n}\n","import type { SliderSettings, SliderState } from './types.js'\n\n/**\n * Marquee state - tracks cloned slides for marquee mode\n */\nexport interface MarqueeState {\n initialized: boolean\n clonedSlides: HTMLElement[]\n styleElement: HTMLStyleElement | null\n}\n\n/**\n * Create initial marquee state\n */\nexport const createMarqueeState = (): MarqueeState => ({\n initialized: false,\n clonedSlides: [],\n styleElement: null\n})\n\n/**\n * Inject CSS keyframes for smooth marquee animation\n */\nconst injectMarqueeKeyframes = (): HTMLStyleElement => {\n // Check if keyframes already exist\n const existingStyle = document.getElementById('lazer-marquee-keyframes')\n if (existingStyle) {\n return existingStyle as HTMLStyleElement\n }\n\n const style = document.createElement('style')\n style.id = 'lazer-marquee-keyframes'\n style.textContent = `\n @keyframes lazer-marquee-scroll {\n 0% {\n transform: translateX(0);\n }\n 100% {\n transform: translateX(-50%);\n }\n }\n `\n document.head.appendChild(style)\n return style\n}\n\n/**\n * Clone all slides and append for seamless marquee looping\n */\nexport const setupMarqueeClones = (\n settings: SliderSettings,\n marqueeState: MarqueeState\n): void => {\n if (marqueeState.initialized) return\n\n // Inject CSS keyframes\n marqueeState.styleElement = injectMarqueeKeyframes()\n\n // Ensure feed has proper CSS for transform animation\n // Note: Parent container should have overflow: hidden for marquee effect\n settings.feed.style.display = 'flex'\n settings.feed.style.willChange = 'transform'\n\n // Clone all original slides and append to create seamless loop\n settings.slides.forEach((slide) => {\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-marquee-clone', 'true')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.appendChild(clone)\n marqueeState.clonedSlides.push(clone)\n })\n\n marqueeState.initialized = true\n}\n\n/**\n * Remove marquee cloned slides from the DOM\n */\nexport const cleanupMarqueeClones = (marqueeState: MarqueeState): void => {\n if (!marqueeState.initialized) return\n\n marqueeState.clonedSlides.forEach((clone) => {\n clone.remove()\n })\n\n marqueeState.clonedSlides = []\n marqueeState.initialized = false\n}\n\n/**\n * Setup marquee CSS animation for smooth hardware-accelerated scrolling\n */\nconst setupMarqueeCss = (\n settings: SliderSettings,\n state: SliderState\n): void => {\n // Ensure keyframes exist first\n injectMarqueeKeyframes()\n\n // Wait a frame to ensure keyframes are parsed and layout is complete\n requestAnimationFrame(() => {\n const scrollWidth = settings.feed.scrollWidth\n const speed = settings.marqueeSpeed ?? 50 // pixels per second\n const direction = settings.marqueeDirection ?? 'left'\n\n // Distance is half the scroll width (the original content width)\n const distance = scrollWidth / 2\n\n // Validate values\n if (distance <= 0 || speed <= 0) {\n console.warn('[lazer-slider] Invalid marquee values:', { distance, speed, scrollWidth })\n return\n }\n\n // Calculate duration: distance / speed (how long to scroll through original content)\n const duration = distance / speed\n const animationDirection = direction === 'right' ? 'reverse' : 'normal'\n\n // Apply animation - use percentage-based keyframes for seamless loop\n const animationValue = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`\n\n // Remove any existing animation first\n settings.feed.style.animation = 'none'\n\n // Force reflow to reset animation\n void settings.feed.offsetWidth\n\n // Apply new animation\n settings.feed.style.animation = animationValue\n settings.feed.style.animationPlayState = state.marqueePaused ? 'paused' : 'running'\n })\n}\n\n/**\n * Start marquee animation using smooth CSS animations\n */\nexport const startMarquee = (\n settings: SliderSettings,\n state: SliderState\n): void => {\n // Setup CSS animation for smooth hardware-accelerated scrolling\n setupMarqueeCss(settings, state)\n}\n\n/**\n * Stop marquee animation\n */\nexport const stopMarquee = (state: SliderState, settings: SliderSettings): void => {\n // Remove animation\n settings.feed.style.animation = ''\n settings.feed.style.animationPlayState = ''\n\n // Reset transform\n settings.feed.style.transform = ''\n settings.feed.style.willChange = ''\n}\n\n/**\n * Pause marquee animation (temporary, resumes on mouse leave)\n */\nexport const pauseMarquee = (state: SliderState, settings: SliderSettings): void => {\n state.marqueePaused = true\n settings.feed.style.animationPlayState = 'paused'\n}\n\n/**\n * Resume marquee animation after pause\n */\nexport const resumeMarquee = (state: SliderState, settings: SliderSettings): void => {\n state.marqueePaused = false\n settings.feed.style.animationPlayState = 'running'\n}\n\n/**\n * Setup marquee mode (clones + animation)\n */\nexport const setupMarquee = (\n settings: SliderSettings,\n state: SliderState,\n marqueeState: MarqueeState\n): void => {\n if (!settings.marquee) return\n\n setupMarqueeClones(settings, marqueeState)\n startMarquee(settings, state)\n}\n\n/**\n * Attach marquee pause-on-hover event listeners\n */\nexport const attachMarqueeEventListeners = (\n settings: SliderSettings,\n state: SliderState,\n signal: AbortSignal\n): void => {\n if (!settings.marquee || settings.pauseOnHover === false) return\n\n settings.feed.addEventListener(\n 'mouseenter',\n () => pauseMarquee(state, settings),\n { signal }\n )\n settings.feed.addEventListener(\n 'mouseleave',\n () => resumeMarquee(state, settings),\n { signal }\n )\n settings.feed.addEventListener(\n 'touchstart',\n () => pauseMarquee(state, settings),\n { passive: true, signal }\n )\n settings.feed.addEventListener(\n 'touchend',\n () => resumeMarquee(state, settings),\n { signal }\n )\n}\n","import type {\n SliderSettings,\n SliderState,\n SliderDirection,\n EasingFunction,\n Slider,\n DragState\n} from './types.js'\nimport { easeOutExpo } from './easing.js'\nimport {\n initAria,\n toggleControlVisibility,\n updateActiveThumb,\n setupKeyboardNavigation\n} from './accessibility.js'\nimport { setupDragToScroll, cleanupDrag } from './drag.js'\nimport {\n createMarqueeState,\n setupMarquee,\n startMarquee,\n stopMarquee,\n pauseMarquee,\n resumeMarquee,\n cleanupMarqueeClones,\n attachMarqueeEventListeners\n} from './marquee.js'\n\n/**\n * Animation duration configuration\n */\nconst ANIMATION = {\n MIN_DURATION: 400,\n MAX_DURATION: 1000,\n SPEED_FACTOR: 1.5,\n SCROLL_END_DELAY: 50,\n THUMB_UPDATE_DELAY: 500\n} as const\n\n/**\n * Desktop breakpoint for responsive slidesPerScroll\n */\nconst DESKTOP_BREAKPOINT = '(min-width: 64rem)'\n\n/**\n * Create a slider instance\n */\nexport const createSlider = (settings: SliderSettings): Slider => {\n // Validate required settings\n if (!settings.feed) {\n throw new Error('lazer-slider: feed element is required')\n }\n\n if (!settings.slides?.length) {\n throw new Error('lazer-slider: slides array is required and must not be empty')\n }\n\n // Initialize state\n const state: SliderState = {\n currentSlideIndex: 0,\n isScrolling: false,\n ticking: false,\n cachedFeedRect: null,\n lastWidth: 0,\n updateThumbTimeout: null,\n scrollEndTimeout: null,\n abortController: new AbortController(),\n autoplayIntervalId: null,\n autoplayPaused: false,\n marqueeAnimationId: null,\n marqueePaused: false,\n marqueeLastTimestamp: 0\n }\n\n // Drag state (initialized if drag is enabled)\n let dragState: DragState | null = null\n\n // Loop state - tracks cloned slides for infinite loop\n const loopState = {\n initialized: false,\n clonedSlides: [] as HTMLElement[],\n realSlides: [...settings.slides] as HTMLElement[],\n clonesPerSide: 0\n }\n\n // Marquee state - tracks cloned slides for marquee mode\n const marqueeState = createMarqueeState()\n\n // Default easing function\n const easing = settings.easing ?? easeOutExpo\n\n /**\n * Get cached feed bounding rect (invalidated on resize)\n */\n const getFeedRect = (): DOMRect => {\n const currentWidth = settings.feed.clientWidth\n if (!state.cachedFeedRect || state.lastWidth !== currentWidth) {\n state.cachedFeedRect = settings.feed.getBoundingClientRect()\n state.lastWidth = currentWidth\n }\n return state.cachedFeedRect\n }\n\n /**\n * Get only visible slides (not hidden via CSS)\n */\n const getVisibleSlides = (): HTMLElement[] => {\n return settings.slides.filter((slide) => slide.offsetParent !== null)\n }\n\n /**\n * Check if we're on desktop based on breakpoint\n */\n const isDesktop = (): boolean => {\n return window.matchMedia(DESKTOP_BREAKPOINT).matches\n }\n\n /**\n * Get the number of slides to clone per side for infinite loop\n */\n const getLoopClonesCount = (): number => {\n const perView = isDesktop()\n ? settings.desktopSlidesPerView\n : settings.mobileSlidesPerView\n\n // Clone at least 1 slide, or the number of visible slides\n if (!perView || perView === 'auto') {\n return 1\n }\n return Math.ceil(perView)\n }\n\n /**\n * Setup cloned slides for infinite loop functionality\n * Clones first N slides to the end and last N slides to the beginning\n */\n const setupLoopClones = (): void => {\n if (!settings.loop || loopState.initialized) return\n\n const realSlides = loopState.realSlides\n const clonesCount = getLoopClonesCount()\n loopState.clonesPerSide = clonesCount\n\n // Clone last N slides and prepend to beginning\n for (let i = realSlides.length - clonesCount; i < realSlides.length; i++) {\n const slide = realSlides[i]\n if (!slide) continue\n\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-clone', 'prepend')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.insertBefore(clone, settings.feed.firstChild)\n loopState.clonedSlides.push(clone)\n }\n\n // Clone first N slides and append to end\n for (let i = 0; i < clonesCount; i++) {\n const slide = realSlides[i]\n if (!slide) continue\n\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-clone', 'append')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.appendChild(clone)\n loopState.clonedSlides.push(clone)\n }\n\n // Set initial scroll position to first real slide (after prepended clones)\n requestAnimationFrame(() => {\n const firstRealSlide = realSlides[0]\n if (firstRealSlide) {\n settings.feed.scrollLeft = firstRealSlide.offsetLeft\n }\n })\n\n loopState.initialized = true\n }\n\n /**\n * Handle repositioning when reaching clone boundaries\n * Silently jumps to the corresponding real slide without animation\n */\n const handleLoopReposition = (direction: SliderDirection): void => {\n if (!settings.loop || !loopState.initialized) return\n\n const realSlides = loopState.realSlides\n const totalRealSlides = realSlides.length\n\n if (direction === 'next') {\n const firstRealSlide = realSlides[0]\n if (firstRealSlide) {\n settings.feed.scrollLeft = firstRealSlide.offsetLeft\n }\n state.currentSlideIndex = 0\n } else {\n const lastRealSlide = realSlides[totalRealSlides - 1]\n if (lastRealSlide) {\n settings.feed.scrollLeft = lastRealSlide.offsetLeft\n }\n state.currentSlideIndex = totalRealSlides - 1\n }\n }\n\n /**\n * Remove cloned slides from the DOM\n */\n const cleanupLoopClones = (): void => {\n if (!loopState.initialized) return\n\n loopState.clonedSlides.forEach((clone) => {\n clone.remove()\n })\n\n loopState.clonedSlides = []\n loopState.initialized = false\n loopState.clonesPerSide = 0\n }\n\n /**\n * Apply slide widths based on slidesPerView settings\n */\n const applySlideWidths = (): void => {\n const perView = isDesktop()\n ? settings.desktopSlidesPerView\n : settings.mobileSlidesPerView\n\n const gap = settings.slideGap ?? 0\n\n // Set gap on the feed container\n if (gap > 0) {\n settings.feed.style.gap = `${gap}px`\n }\n\n // If 'auto' or not set, let CSS handle widths (natural sizing)\n if (!perView || perView === 'auto') {\n // Reset any previously set widths\n settings.slides.forEach((slide) => {\n slide.style.flex = ''\n slide.style.minWidth = ''\n })\n return\n }\n\n const totalGapWidth = gap * (perView - 1)\n const slideWidth = `calc((100% - ${totalGapWidth}px) / ${perView})`\n\n settings.slides.forEach((slide) => {\n slide.style.flex = `0 0 ${slideWidth}`\n slide.style.minWidth = slideWidth\n })\n }\n\n /**\n * Update scrollbar thumb width based on visible content\n */\n const updateScrollbar = (): void => {\n if (!settings.scrollbarThumb) return\n\n const feedRect = getFeedRect()\n const thumbWidth = (feedRect.width / settings.feed.scrollWidth) * 100\n settings.scrollbarThumb.style.width = `${thumbWidth}%`\n }\n\n /**\n * Update scrollbar thumb position based on scroll\n */\n const updateScrollbarPosition = (): void => {\n if (!settings.scrollbarThumb || !settings.scrollbarTrack) return\n\n const trackWidth = settings.scrollbarTrack.getBoundingClientRect().width\n const thumbWidth = settings.scrollbarThumb.getBoundingClientRect().width\n const totalTransform = trackWidth - thumbWidth\n\n const maxScroll = settings.feed.scrollWidth - settings.feed.clientWidth\n const scrollProgress = maxScroll > 0 ? settings.feed.scrollLeft / maxScroll : 0\n\n settings.scrollbarThumb.style.transform = `translateX(${totalTransform * scrollProgress}px)`\n }\n\n /**\n * Update visibility of navigation controls based on scroll position\n */\n const updateControlsVisibility = (): void => {\n const feedRect = getFeedRect()\n const isAtStart = settings.feed.scrollLeft <= 1 // Allow 1px tolerance\n const isAtEnd =\n settings.feed.scrollLeft + feedRect.width >= settings.feed.scrollWidth - 1\n const shouldHideScrollbar = settings.feed.scrollWidth <= feedRect.width\n\n // Hide/show scrollbar track\n if (settings.scrollbarTrack) {\n settings.scrollbarTrack.style.display = shouldHideScrollbar ? 'none' : 'block'\n }\n\n // When loop is enabled, always show both buttons (unless scrollbar should be hidden)\n if (settings.loop) {\n toggleControlVisibility(\n settings.prevSlideButton,\n !shouldHideScrollbar,\n settings.feed\n )\n toggleControlVisibility(\n settings.nextSlideButton,\n !shouldHideScrollbar,\n settings.feed\n )\n return\n }\n\n // Hide/show navigation buttons based on position\n toggleControlVisibility(\n settings.prevSlideButton,\n !isAtStart && !shouldHideScrollbar,\n settings.feed\n )\n toggleControlVisibility(\n settings.nextSlideButton,\n !isAtEnd && !shouldHideScrollbar,\n settings.feed\n )\n }\n\n /**\n * Calculate current slide index based on viewport position\n */\n const updateCurrentSlideIndex = (): void => {\n const feedRect = getFeedRect()\n\n // Use real slides for index calculation when loop is enabled\n const slidesToCheck = loopState.initialized\n ? loopState.realSlides\n : getVisibleSlides()\n\n // Find slides that are visible in the viewport\n const viewportVisibleSlides = slidesToCheck.filter((slide) => {\n const slideRect = slide.getBoundingClientRect()\n const tolerance = 20 // px tolerance for edge detection\n return (\n slideRect.right > feedRect.left + tolerance &&\n slideRect.left < feedRect.right - tolerance\n )\n })\n\n if (viewportVisibleSlides.length && viewportVisibleSlides[0]) {\n const newIndex = slidesToCheck.indexOf(viewportVisibleSlides[0])\n if (newIndex !== -1) {\n state.currentSlideIndex = newIndex\n settings.onScroll?.({\n currentScroll: settings.feed.scrollLeft,\n currentSlideIndex: state.currentSlideIndex\n })\n }\n }\n }\n\n /**\n * Smooth scroll to a target position using requestAnimationFrame\n */\n const smoothScrollTo = (\n target: number,\n customEasing: EasingFunction = easing,\n onComplete?: () => void\n ): void => {\n const start = settings.feed.scrollLeft\n const distance = Math.abs(target - start)\n\n // Dynamic duration based on distance\n const duration = Math.min(\n ANIMATION.MAX_DURATION,\n Math.max(ANIMATION.MIN_DURATION, distance / ANIMATION.SPEED_FACTOR)\n )\n\n const startTime = performance.now()\n\n const animateScroll = (currentTime: number): void => {\n const elapsed = (currentTime - startTime) / duration\n const progress = Math.min(elapsed, 1)\n const ease = customEasing(progress)\n\n settings.feed.scrollLeft = start + (target - start) * ease\n\n if (progress < 1) {\n requestAnimationFrame(animateScroll)\n } else {\n settings.feed.scrollLeft = target\n onComplete?.()\n }\n }\n\n requestAnimationFrame(animateScroll)\n }\n\n /**\n * Handle thumbnail click navigation\n */\n const handleThumbClick = (thumb: HTMLElement): void => {\n if (!settings.thumbs) return\n\n const index = settings.thumbs.indexOf(thumb)\n if (index === -1 || !settings.slides[index]) return\n\n state.currentSlideIndex = index\n updateActiveThumb(settings.thumbs, index)\n state.isScrolling = true\n\n // Clear existing timeout\n if (state.updateThumbTimeout) {\n clearTimeout(state.updateThumbTimeout)\n }\n\n // Reset scrolling flag after animation\n state.updateThumbTimeout = setTimeout(() => {\n state.isScrolling = false\n }, ANIMATION.THUMB_UPDATE_DELAY)\n\n smoothScrollTo(settings.slides[index].offsetLeft)\n }\n\n /**\n * Handle navigation button click (prev/next)\n */\n const handleNavButtonClick = (direction: SliderDirection): void => {\n const realSlides = loopState.initialized ? loopState.realSlides : getVisibleSlides()\n const slidesToScroll = isDesktop()\n ? settings.desktopSlidesPerScroll ?? 1\n : settings.mobileSlidesPerScroll ?? 1\n const totalRealSlides = realSlides.length\n\n // Update current index first\n updateCurrentSlideIndex()\n\n let targetSlide: HTMLElement | undefined\n let needsReposition = false\n\n if (direction === 'prev') {\n if (settings.loop && loopState.initialized && state.currentSlideIndex === 0) {\n\n const prependedClones = loopState.clonedSlides.filter(\n (clone) => clone.getAttribute('data-lazer-clone') === 'prepend'\n )\n targetSlide = prependedClones[prependedClones.length - 1]\n needsReposition = true\n } else {\n state.currentSlideIndex = Math.max(0, state.currentSlideIndex - slidesToScroll)\n targetSlide = realSlides[state.currentSlideIndex]\n }\n } else {\n if (settings.loop && loopState.initialized && state.currentSlideIndex >= totalRealSlides - 1) {\n const appendedClones = loopState.clonedSlides.filter(\n (clone) => clone.getAttribute('data-lazer-clone') === 'append'\n )\n targetSlide = appendedClones[0]\n needsReposition = true\n } else {\n state.currentSlideIndex = Math.min(\n totalRealSlides - 1,\n state.currentSlideIndex + slidesToScroll\n )\n targetSlide = realSlides[state.currentSlideIndex]\n }\n }\n\n if (!targetSlide) return\n\n // Fire scroll start callback\n settings.onScrollStart?.({\n currentScroll: settings.feed.scrollLeft,\n target: targetSlide,\n direction\n })\n\n if (needsReposition) {\n // Scroll to clone, then silently reposition to the real slide\n smoothScrollTo(targetSlide.offsetLeft, easing, () => {\n handleLoopReposition(direction)\n })\n } else {\n smoothScrollTo(targetSlide.offsetLeft)\n }\n }\n\n /**\n * Update all scroll-related state\n */\n const updateScrollPosition = (): void => {\n updateScrollbarPosition()\n updateControlsVisibility()\n updateCurrentSlideIndex()\n\n // Update thumbs only when not programmatically scrolling\n if (!state.isScrolling) {\n updateActiveThumb(settings.thumbs, state.currentSlideIndex)\n }\n\n // Clear existing timeout\n if (state.scrollEndTimeout) {\n clearTimeout(state.scrollEndTimeout)\n }\n\n // Fire scroll end callback after scroll settles\n state.scrollEndTimeout = setTimeout(() => {\n state.isScrolling = false\n settings.onScrollEnd?.({\n currentScroll: settings.feed.scrollLeft,\n currentSlideIndex: state.currentSlideIndex\n })\n }, ANIMATION.SCROLL_END_DELAY)\n }\n\n /**\n * Throttled scroll event handler\n */\n const handleFeedScroll = (): void => {\n if (!state.ticking) {\n requestAnimationFrame(() => {\n updateScrollPosition()\n state.ticking = false\n })\n state.ticking = true\n }\n }\n\n /**\n * Handle window resize\n */\n const handleWindowResize = (): void => {\n state.cachedFeedRect = null\n refresh()\n }\n\n /**\n * Attach all event listeners\n */\n const attachEventListeners = (): void => {\n const { signal } = state.abortController\n\n // Resize handler (not abortable, cleaned up manually)\n window.addEventListener('resize', handleWindowResize)\n\n // Scroll handler\n settings.feed.addEventListener('scroll', handleFeedScroll, {\n passive: true,\n signal\n })\n\n // Navigation button handlers\n if (settings.prevSlideButton) {\n settings.prevSlideButton.addEventListener(\n 'click',\n () => handleNavButtonClick('prev'),\n { signal }\n )\n }\n\n if (settings.nextSlideButton) {\n settings.nextSlideButton.addEventListener(\n 'click',\n () => handleNavButtonClick('next'),\n { signal }\n )\n }\n\n // Thumbnail handlers\n if (settings.thumbs?.length) {\n settings.thumbs[0]?.classList.add('active')\n settings.thumbs.forEach((thumb) => {\n thumb.addEventListener('click', () => handleThumbClick(thumb), { signal })\n })\n }\n\n // Keyboard navigation\n setupKeyboardNavigation(\n settings.feed,\n () => handleNavButtonClick('prev'),\n () => handleNavButtonClick('next'),\n signal\n )\n\n // Drag-to-scroll\n if (settings.enableDragToScroll) {\n dragState = setupDragToScroll({\n feed: settings.feed,\n slides: settings.slides,\n abortSignal: signal,\n smoothScrollTo,\n onDragEnd: () => {\n updateCurrentSlideIndex()\n updateActiveThumb(settings.thumbs, state.currentSlideIndex)\n }\n })\n }\n\n // Autoplay pause on hover/touch\n if (settings.autoplay && settings.pauseOnHover !== false) {\n settings.feed.addEventListener(\n 'mouseenter',\n pauseAutoplay,\n { signal }\n )\n settings.feed.addEventListener(\n 'mouseleave',\n resumeAutoplay,\n { signal }\n )\n settings.feed.addEventListener(\n 'touchstart',\n pauseAutoplay,\n { passive: true, signal }\n )\n settings.feed.addEventListener(\n 'touchend',\n resumeAutoplay,\n { signal }\n )\n }\n\n // Marquee pause on hover/touch\n attachMarqueeEventListeners(settings, state, signal)\n }\n\n /**\n * Start autoplay\n */\n const startAutoplay = (): void => {\n if (state.autoplayIntervalId) return;\n\n const interval = settings.autoplayInterval ?? 3000\n state.autoplayIntervalId = setInterval(() => {\n if (!state.autoplayPaused) {\n handleNavButtonClick('next')\n }\n }, interval)\n }\n\n /**\n * Stop autoplay\n */\n const stopAutoplay = (): void => {\n if (state.autoplayIntervalId) {\n clearInterval(state.autoplayIntervalId)\n state.autoplayIntervalId = null\n }\n }\n\n /**\n * Pause autoplay (temporary, resumes on mouse leave)\n */\n const pauseAutoplay = (): void => {\n state.autoplayPaused = true\n }\n\n /**\n * Resume autoplay after pause\n */\n const resumeAutoplay = (): void => {\n state.autoplayPaused = false\n }\n\n /**\n * Navigate to a specific slide by index\n */\n const goToIndex = (index: number): void => {\n // Use real slides when loop is enabled, otherwise use visible slides\n const slides = loopState.initialized ? loopState.realSlides : getVisibleSlides()\n const safeIndex = Math.max(0, Math.min(index, slides.length - 1))\n const targetSlide = slides[safeIndex]\n\n if (!targetSlide) return\n\n state.currentSlideIndex = safeIndex\n updateActiveThumb(settings.thumbs, safeIndex)\n smoothScrollTo(targetSlide.offsetLeft)\n }\n\n /**\n * Refresh slider state (recalculate dimensions, update controls)\n */\n const refresh = (): void => {\n state.cachedFeedRect = null\n applySlideWidths()\n updateScrollbar()\n updateControlsVisibility()\n\n // Recalculate marquee animation if in marquee mode\n if (settings.marquee && !state.marqueePaused) {\n startMarquee(settings, state)\n }\n }\n\n /**\n * Clean up all event listeners and timers\n */\n const unload = (): void => {\n // Stop autoplay and marquee\n stopAutoplay()\n stopMarquee(state, settings)\n\n // Abort all event listeners\n state.abortController.abort()\n\n // Remove resize listener\n window.removeEventListener('resize', handleWindowResize)\n\n // Clear timeouts\n if (state.updateThumbTimeout) {\n clearTimeout(state.updateThumbTimeout)\n }\n if (state.scrollEndTimeout) {\n clearTimeout(state.scrollEndTimeout)\n }\n\n // Clean up drag state\n if (dragState) {\n cleanupDrag(dragState)\n }\n\n // Clean up loop clones and marquee clones\n cleanupLoopClones()\n cleanupMarqueeClones(marqueeState)\n\n // Reset cached rect\n state.cachedFeedRect = null\n }\n\n // Initialize slider\n initAria(settings)\n applySlideWidths()\n\n // Marquee mode takes precedence over loop/autoplay\n if (settings.marquee) {\n setupMarquee(settings, state, marqueeState)\n } else {\n setupLoopClones()\n // Start autoplay if enabled (only in non-marquee mode)\n if (settings.autoplay) {\n startAutoplay()\n }\n }\n\n updateControlsVisibility()\n attachEventListeners()\n updateScrollbar()\n\n // Unified play/pause that works for both autoplay and marquee\n const play = (): void => {\n if (settings.marquee) {\n if (state.marqueePaused) {\n resumeMarquee(state, settings)\n } else {\n startMarquee(settings, state)\n }\n } else if (settings.autoplay) {\n startAutoplay()\n }\n }\n\n const pause = (): void => {\n if (settings.marquee) {\n pauseMarquee(state, settings)\n } else {\n stopAutoplay()\n }\n }\n\n return {\n goToIndex,\n refresh,\n unload,\n play,\n pause,\n next: () => handleNavButtonClick('next'),\n prev: () => handleNavButtonClick('prev')\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/easing.ts","../src/core/accessibility.ts","../src/core/drag.ts","../src/core/bullets.ts","../src/core/marquee.ts","../src/core/slider.ts"],"sourcesContent":["import type { EasingFunction } from './types.js'\n\n/**\n * Exponential ease-out - starts fast, decelerates smoothly\n * Best for scroll animations as it feels natural and responsive\n */\nexport const easeOutExpo: EasingFunction = (t) =>\n t === 1 ? 1 : 1 - Math.pow(2, -10 * t)\n\n/**\n * Cubic ease-out - smoother deceleration than exponential\n */\nexport const easeOutCubic: EasingFunction = (t) => 1 - Math.pow(1 - t, 3)\n\n/**\n * Cubic ease-in-out - smooth acceleration and deceleration\n */\nexport const easeInOutCubic: EasingFunction = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n\n/**\n * Quadratic ease-out - gentle deceleration\n */\nexport const easeOutQuad: EasingFunction = (t) => 1 - (1 - t) * (1 - t)\n\n/**\n * Linear - no easing, constant speed\n */\nexport const linear: EasingFunction = (t) => t\n","import type { SliderSettings } from './types.js'\n\n/**\n * Generate a unique ID for the slider\n */\nexport const generateSliderId = (): string =>\n `slider-${Math.random().toString(36).substring(2, 9)}`\n\n/**\n * Initialize ARIA attributes\n */\nexport const initAria = (settings: SliderSettings): void => {\n const { feed, prevSlideButton, nextSlideButton, thumbs, slides } = settings\n\n if (!feed.id) {\n feed.id = generateSliderId()\n }\n\n feed.setAttribute('role', 'region')\n feed.setAttribute('aria-label', 'Carousel')\n feed.setAttribute('aria-roledescription', 'carousel')\n\n feed.removeAttribute('tabindex')\n\n slides.forEach((slide, index) => {\n slide.setAttribute('role', 'group')\n slide.setAttribute('aria-roledescription', 'slide')\n slide.setAttribute('aria-label', `Slide ${index + 1} of ${slides.length}`)\n })\n\n if (prevSlideButton) {\n prevSlideButton.setAttribute('aria-label', 'Previous slide')\n prevSlideButton.setAttribute('aria-controls', feed.id)\n prevSlideButton.setAttribute('tabindex', '0')\n if (prevSlideButton.tagName !== 'BUTTON') {\n prevSlideButton.setAttribute('role', 'button')\n }\n }\n\n if (nextSlideButton) {\n nextSlideButton.setAttribute('aria-label', 'Next slide')\n nextSlideButton.setAttribute('aria-controls', feed.id)\n nextSlideButton.setAttribute('tabindex', '0')\n if (nextSlideButton.tagName !== 'BUTTON') {\n nextSlideButton.setAttribute('role', 'button')\n }\n }\n\n if (thumbs?.length) {\n thumbs.forEach((thumb, index) => {\n if (thumb.tagName !== 'BUTTON') {\n thumb.setAttribute('role', 'button')\n }\n thumb.setAttribute('aria-label', `Go to slide ${index + 1}`)\n thumb.setAttribute('tabindex', '0')\n thumb.setAttribute('aria-controls', feed.id)\n })\n }\n}\n\n/**\n * Toggle visibility of navigation controls\n */\nexport const toggleControlVisibility = (\n button: HTMLElement | null | undefined,\n shouldShow: boolean,\n feedElement?: HTMLElement\n): void => {\n if (!button) return\n\n if (!shouldShow && button === document.activeElement && feedElement) {\n feedElement.focus()\n }\n\n const transition = 'opacity 0.3s ease'\n const opacity = shouldShow ? '1' : '0'\n\n Object.assign(button.style, {\n opacity,\n transition,\n pointerEvents: shouldShow ? 'auto' : 'none'\n })\n\n if (!shouldShow) {\n button.setAttribute('aria-hidden', 'true')\n button.setAttribute('tabindex', '-1')\n } else {\n button.removeAttribute('aria-hidden')\n button.setAttribute('tabindex', '0')\n }\n\n if (!shouldShow) {\n setTimeout(() => {\n if (button.style.opacity === '0') {\n button.style.visibility = 'hidden'\n }\n }, 300)\n } else {\n button.style.visibility = 'visible'\n }\n}\n\n/**\n * Update active state on thumbs\n */\nexport const updateActiveThumb = (\n thumbs: HTMLElement[] | undefined,\n currentIndex: number,\n activeClass: string = 'active'\n): void => {\n if (!thumbs?.length) return\n\n thumbs.forEach((thumb, index) => {\n const isActive = index === currentIndex\n thumb.classList.toggle(activeClass, isActive)\n thumb.setAttribute('aria-selected', isActive.toString())\n })\n}\n\n/**\n * Keyboard navigation\n */\nexport const setupKeyboardNavigation = (\n feed: HTMLElement,\n onPrev: () => void,\n onNext: () => void,\n abortSignal: AbortSignal\n): void => {\n feed.addEventListener(\n 'keydown',\n (event: KeyboardEvent) => {\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault()\n onPrev()\n break\n case 'ArrowRight':\n event.preventDefault()\n onNext()\n break\n }\n },\n { signal: abortSignal }\n )\n\n if (!feed.hasAttribute('tabindex')) {\n feed.setAttribute('tabindex', '0')\n }\n}\n","import type { DragState, EasingFunction } from './types.js'\nimport { easeOutCubic } from './easing.js'\n\n/**\n * Configuration for drag behavior\n */\ninterface DragConfig {\n /** Feed element to enable dragging on */\n feed: HTMLElement\n /** Slide elements for snap-to-slide calculation */\n slides: HTMLElement[]\n /** AbortSignal for cleanup */\n abortSignal: AbortSignal\n /** Callback to smooth scroll to a position */\n smoothScrollTo: (target: number, easing?: EasingFunction) => void\n /** Callback when drag ends (for updating state) */\n onDragEnd?: () => void\n /** Enable free mode scrolling (momentum-based) instead of snap-to-slide */\n dragFree?: boolean\n}\n\nexport const createDragState = (): DragState => ({\n isDragging: false,\n startX: 0,\n startScrollLeft: 0,\n velocity: 0,\n lastX: 0,\n lastTime: 0,\n momentumId: null\n})\n\nconst findNearestSlide = (\n feed: HTMLElement,\n slides: HTMLElement[]\n): HTMLElement | null => {\n const feedRect = feed.getBoundingClientRect()\n const feedCenter = feedRect.left + feedRect.width / 2\n\n let nearestSlide: HTMLElement | null = null\n let minDistance = Infinity\n\n for (const slide of slides) {\n if (slide.offsetParent === null) continue\n\n const slideRect = slide.getBoundingClientRect()\n const slideCenter = slideRect.left + slideRect.width / 2\n const distance = Math.abs(feedCenter - slideCenter)\n\n if (distance < minDistance) {\n minDistance = distance\n nearestSlide = slide\n }\n }\n\n return nearestSlide\n}\n\nconst applyMomentum = (\n state: DragState,\n feed: HTMLElement,\n slides: HTMLElement[],\n smoothScrollTo: (target: number, easing?: EasingFunction) => void,\n onDragEnd?: () => void\n): void => {\n const friction = 0.95\n const minVelocity = 0.5\n\n const animate = () => {\n if (Math.abs(state.velocity) < minVelocity) {\n state.momentumId = null\n\n const nearestSlide = findNearestSlide(feed, slides)\n if (nearestSlide) {\n smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic)\n }\n\n onDragEnd?.()\n return\n }\n\n feed.scrollLeft += state.velocity\n state.velocity *= friction\n\n state.momentumId = requestAnimationFrame(animate)\n }\n\n state.momentumId = requestAnimationFrame(animate)\n}\n\nconst getEventX = (event: MouseEvent | TouchEvent): number => {\n if ('touches' in event) {\n return event.touches[0]?.clientX ?? 0\n }\n return event.clientX\n}\n\nexport const setupDragToScroll = (config: DragConfig): DragState => {\n const { feed, slides, abortSignal, smoothScrollTo, onDragEnd, dragFree = false } = config\n const state = createDragState()\n\n const handleDragStart = (event: MouseEvent | TouchEvent) => {\n if (state.momentumId !== null) {\n cancelAnimationFrame(state.momentumId)\n state.momentumId = null\n }\n\n state.isDragging = true\n state.startX = getEventX(event)\n state.startScrollLeft = feed.scrollLeft\n state.velocity = 0\n state.lastX = state.startX\n state.lastTime = performance.now()\n\n feed.style.cursor = 'grabbing'\n feed.style.userSelect = 'none'\n\n if (event.type === 'mousedown') {\n event.preventDefault()\n }\n }\n\n const handleDragMove = (event: MouseEvent | TouchEvent) => {\n if (!state.isDragging) return\n\n const currentX = getEventX(event)\n const currentTime = performance.now()\n const deltaX = state.startX - currentX\n const deltaTime = currentTime - state.lastTime\n\n feed.scrollLeft = state.startScrollLeft + deltaX\n\n if (deltaTime > 0) {\n state.velocity = (state.lastX - currentX) / deltaTime * 16\n }\n\n state.lastX = currentX\n state.lastTime = currentTime\n\n if (event.type === 'touchmove') {\n event.preventDefault()\n }\n }\n\n const handleDragEnd = () => {\n if (!state.isDragging) return\n\n state.isDragging = false\n\n feed.style.cursor = 'grab'\n feed.style.userSelect = ''\n\n if (dragFree) {\n // Free mode: apply momentum scrolling then snap to nearest slide\n if (Math.abs(state.velocity) > 1) {\n applyMomentum(state, feed, slides, smoothScrollTo, onDragEnd)\n } else {\n const nearestSlide = findNearestSlide(feed, slides)\n if (nearestSlide) {\n smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic)\n }\n onDragEnd?.()\n }\n } else {\n // Snap mode: immediately snap to next/prev slide based on swipe direction\n const swipeDistance = state.startX - state.lastX\n const swipeThreshold = 50 // Minimum swipe distance in pixels to trigger slide change\n\n const nearestSlide = findNearestSlide(feed, slides)\n\n if (nearestSlide && Math.abs(swipeDistance) > swipeThreshold) {\n // Get visible slides only (filter out hidden ones)\n const visibleSlides = slides.filter((slide) => slide.offsetParent !== null)\n const visibleIndex = visibleSlides.indexOf(nearestSlide)\n\n let targetSlide: HTMLElement | null = null\n\n if (swipeDistance > 0 && visibleIndex < visibleSlides.length - 1) {\n // Swiped left (next slide)\n targetSlide = visibleSlides[visibleIndex + 1] ?? nearestSlide\n } else if (swipeDistance < 0 && visibleIndex > 0) {\n // Swiped right (prev slide)\n targetSlide = visibleSlides[visibleIndex - 1] ?? nearestSlide\n } else {\n // At boundary, stay on current slide\n targetSlide = nearestSlide\n }\n\n smoothScrollTo(targetSlide.offsetLeft, easeOutCubic)\n } else if (nearestSlide) {\n // Small swipe - snap back to nearest slide\n smoothScrollTo(nearestSlide.offsetLeft, easeOutCubic)\n }\n\n onDragEnd?.()\n }\n }\n\n feed.style.cursor = 'grab'\n\n feed.addEventListener('mousedown', handleDragStart, { signal: abortSignal })\n document.addEventListener('mousemove', handleDragMove, { signal: abortSignal })\n document.addEventListener('mouseup', handleDragEnd, { signal: abortSignal })\n\n feed.addEventListener('touchstart', handleDragStart, {\n passive: true,\n signal: abortSignal\n })\n feed.addEventListener('touchmove', handleDragMove, {\n passive: false,\n signal: abortSignal\n })\n feed.addEventListener('touchend', handleDragEnd, { signal: abortSignal })\n\n document.addEventListener('mouseleave', handleDragEnd, { signal: abortSignal })\n\n return state\n}\n\nexport const cleanupDrag = (state: DragState): void => {\n if (state.momentumId !== null) {\n cancelAnimationFrame(state.momentumId)\n state.momentumId = null\n }\n}\n","export interface GenerateBulletsParams {\n bulletsContainer: HTMLElement\n slides: HTMLElement[]\n bulletClass: string\n bulletActiveClass: string\n feedId: string\n}\n\nexport const generateBullets = ({\n bulletsContainer,\n slides,\n bulletClass,\n bulletActiveClass,\n feedId,\n}: GenerateBulletsParams): HTMLElement[] => {\n if (!bulletsContainer || !(bulletsContainer instanceof HTMLElement)) {\n throw new Error('Invalid bulletsContainer: must be a valid HTMLElement')\n }\n\n if (!Array.isArray(slides) || slides.length === 0) {\n throw new Error('Invalid slides: must be a non-empty array')\n }\n\n if (!feedId || typeof feedId !== 'string') {\n throw new Error('Invalid feedId: must be a non-empty string')\n }\n\n if (!bulletClass || typeof bulletClass !== 'string') {\n throw new Error('Invalid bulletClass: must be a non-empty string')\n }\n\n bulletsContainer.innerHTML = ''\n bulletsContainer.setAttribute('role', 'tablist')\n bulletsContainer.setAttribute('aria-label', 'Slide navigation')\n\n const visibleSlides = slides\n .map((slide, originalIndex) => ({ slide, originalIndex }))\n .filter(({ slide }) => slide.offsetParent !== null)\n\n if (visibleSlides.length === 0) {\n console.warn('No visible slides found')\n return []\n }\n\n const bullets = visibleSlides.map(({ slide, originalIndex }, visibleIndex) => {\n const bullet = document.createElement('button')\n bullet.type = 'button'\n\n bullet.classList.add(bulletClass)\n if (visibleIndex === 0) {\n bullet.classList.add(bulletActiveClass)\n }\n\n bullet.setAttribute('role', 'tab')\n bullet.setAttribute('aria-selected', visibleIndex === 0 ? 'true' : 'false')\n bullet.setAttribute('aria-controls', feedId)\n bullet.setAttribute('aria-label', `Go to slide ${visibleIndex + 1}`)\n bullet.setAttribute('data-slide-index', String(visibleIndex))\n\n bulletsContainer.appendChild(bullet)\n\n return bullet\n })\n\n return bullets\n}\n\nexport const updateActiveBullet = (\n bullets: HTMLElement[],\n activeIndex: number,\n bulletActiveClass: string,\n): void => {\n if (!Array.isArray(bullets) || activeIndex < 0 || activeIndex >= bullets.length) {\n console.warn('Invalid activeIndex or bullets array')\n return\n }\n\n bullets.forEach((bullet, index) => {\n const isActive = index === activeIndex\n bullet.classList.toggle(bulletActiveClass, isActive)\n bullet.setAttribute('aria-selected', isActive ? 'true' : 'false')\n })\n}","import type { SliderSettings, SliderState } from './types.js'\n\n/**\n * Marquee state - tracks cloned slides for marquee mode\n */\nexport interface MarqueeState {\n initialized: boolean\n clonedSlides: HTMLElement[]\n styleElement: HTMLStyleElement | null\n}\n\n/**\n * Create initial marquee state\n */\nexport const createMarqueeState = (): MarqueeState => ({\n initialized: false,\n clonedSlides: [],\n styleElement: null\n})\n\n/**\n * Inject CSS keyframes for smooth marquee animation\n */\nconst injectMarqueeKeyframes = (): HTMLStyleElement => {\n // Check if keyframes already exist\n const existingStyle = document.getElementById('lazer-marquee-keyframes')\n if (existingStyle) {\n return existingStyle as HTMLStyleElement\n }\n\n const style = document.createElement('style')\n style.id = 'lazer-marquee-keyframes'\n style.textContent = `\n @keyframes lazer-marquee-scroll {\n 0% {\n transform: translateX(0);\n }\n 100% {\n transform: translateX(-50%);\n }\n }\n `\n document.head.appendChild(style)\n return style\n}\n\n/**\n * Clone all slides and append for seamless marquee looping\n */\nexport const setupMarqueeClones = (\n settings: SliderSettings,\n marqueeState: MarqueeState\n): void => {\n if (marqueeState.initialized) return\n\n // Inject CSS keyframes\n marqueeState.styleElement = injectMarqueeKeyframes()\n\n // Ensure feed has proper CSS for transform animation\n // Note: Parent container should have overflow: hidden for marquee effect\n settings.feed.style.display = 'flex'\n settings.feed.style.willChange = 'transform'\n\n // Clone all original slides and append to create seamless loop\n settings.slides.forEach((slide) => {\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-marquee-clone', 'true')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.appendChild(clone)\n marqueeState.clonedSlides.push(clone)\n })\n\n marqueeState.initialized = true\n}\n\n/**\n * Remove marquee cloned slides from the DOM\n */\nexport const cleanupMarqueeClones = (marqueeState: MarqueeState): void => {\n if (!marqueeState.initialized) return\n\n marqueeState.clonedSlides.forEach((clone) => {\n clone.remove()\n })\n\n marqueeState.clonedSlides = []\n marqueeState.initialized = false\n}\n\n/**\n * Setup marquee CSS animation for smooth hardware-accelerated scrolling\n */\nconst setupMarqueeCss = (\n settings: SliderSettings,\n state: SliderState\n): void => {\n // Ensure keyframes exist first\n injectMarqueeKeyframes()\n\n // Wait a frame to ensure keyframes are parsed and layout is complete\n requestAnimationFrame(() => {\n const scrollWidth = settings.feed.scrollWidth\n const speed = settings.marqueeSpeed ?? 50 // pixels per second\n const direction = settings.marqueeDirection ?? 'left'\n\n // Distance is half the scroll width (the original content width)\n const distance = scrollWidth / 2\n\n // Validate values\n if (distance <= 0 || speed <= 0) {\n console.warn('[lazer-slider] Invalid marquee values:', { distance, speed, scrollWidth })\n return\n }\n\n // Calculate duration: distance / speed (how long to scroll through original content)\n const duration = distance / speed\n const animationDirection = direction === 'right' ? 'reverse' : 'normal'\n\n // Apply animation - use percentage-based keyframes for seamless loop\n const animationValue = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`\n\n // Remove any existing animation first\n settings.feed.style.animation = 'none'\n\n // Force reflow to reset animation\n void settings.feed.offsetWidth\n\n // Apply new animation\n settings.feed.style.animation = animationValue\n settings.feed.style.animationPlayState = state.marqueePaused ? 'paused' : 'running'\n })\n}\n\n/**\n * Start marquee animation using smooth CSS animations\n */\nexport const startMarquee = (\n settings: SliderSettings,\n state: SliderState\n): void => {\n // Setup CSS animation for smooth hardware-accelerated scrolling\n setupMarqueeCss(settings, state)\n}\n\n/**\n * Stop marquee animation\n */\nexport const stopMarquee = (state: SliderState, settings: SliderSettings): void => {\n // Remove animation\n settings.feed.style.animation = ''\n settings.feed.style.animationPlayState = ''\n\n // Reset transform\n settings.feed.style.transform = ''\n settings.feed.style.willChange = ''\n}\n\n/**\n * Pause marquee animation (temporary, resumes on mouse leave)\n */\nexport const pauseMarquee = (state: SliderState, settings: SliderSettings): void => {\n state.marqueePaused = true\n settings.feed.style.animationPlayState = 'paused'\n}\n\n/**\n * Resume marquee animation after pause\n */\nexport const resumeMarquee = (state: SliderState, settings: SliderSettings): void => {\n state.marqueePaused = false\n settings.feed.style.animationPlayState = 'running'\n}\n\n/**\n * Setup marquee mode (clones + animation)\n */\nexport const setupMarquee = (\n settings: SliderSettings,\n state: SliderState,\n marqueeState: MarqueeState\n): void => {\n if (!settings.marquee) return\n\n setupMarqueeClones(settings, marqueeState)\n startMarquee(settings, state)\n}\n\n/**\n * Attach marquee pause-on-hover event listeners\n */\nexport const attachMarqueeEventListeners = (\n settings: SliderSettings,\n state: SliderState,\n signal: AbortSignal\n): void => {\n if (!settings.marquee || settings.pauseOnHover === false) return\n\n settings.feed.addEventListener(\n 'mouseenter',\n () => pauseMarquee(state, settings),\n { signal }\n )\n settings.feed.addEventListener(\n 'mouseleave',\n () => resumeMarquee(state, settings),\n { signal }\n )\n settings.feed.addEventListener(\n 'touchstart',\n () => pauseMarquee(state, settings),\n { passive: true, signal }\n )\n settings.feed.addEventListener(\n 'touchend',\n () => resumeMarquee(state, settings),\n { signal }\n )\n}\n","import type {\n SliderSettings,\n SliderState,\n SliderDirection,\n EasingFunction,\n Slider,\n DragState\n} from './types.js'\nimport { easeOutExpo } from './easing.js'\nimport {\n initAria,\n toggleControlVisibility,\n updateActiveThumb,\n setupKeyboardNavigation\n} from './accessibility.js'\nimport { setupDragToScroll, cleanupDrag } from './drag.js'\nimport { generateBullets } from './bullets.js'\nimport {\n createMarqueeState,\n setupMarquee,\n startMarquee,\n stopMarquee,\n pauseMarquee,\n resumeMarquee,\n cleanupMarqueeClones,\n attachMarqueeEventListeners\n} from './marquee.js'\n\nconst ANIMATION = {\n MIN_DURATION: 400,\n MAX_DURATION: 1000,\n SPEED_FACTOR: 1.5,\n SCROLL_END_DELAY: 50,\n THUMB_UPDATE_DELAY: 500\n} as const\n\nconst DESKTOP_BREAKPOINT = '(min-width: 64rem)'\n\nexport const createSlider = (settings: SliderSettings): Slider => {\n if (!settings.feed) {\n throw new Error('lazer-slider: feed element is required')\n }\n\n if (!settings.slides?.length) {\n throw new Error('lazer-slider: slides array is required and must not be empty')\n }\n\n if (!settings.feed.id) {\n settings.feed.id = `lazer-slider-feed-${Math.random().toString(36).substr(2, 9)}`\n }\n\n if (settings.bulletsContainer && !settings.thumbs) {\n const bullets = generateBullets({\n bulletsContainer: settings.bulletsContainer,\n slides: settings.slides,\n bulletClass: settings.bulletsClass ?? 'slider-bullet',\n bulletActiveClass: settings.bulletsActiveClass ?? 'active',\n feedId: settings.feed.id\n })\n settings.thumbs = bullets\n }\n\n const state: SliderState = {\n currentSlideIndex: 0,\n isScrolling: false,\n ticking: false,\n cachedFeedRect: null,\n lastWidth: 0,\n updateThumbTimeout: null,\n scrollEndTimeout: null,\n resizeTimeout: null,\n abortController: new AbortController(),\n autoplayIntervalId: null,\n autoplayPaused: false,\n marqueeAnimationId: null,\n marqueePaused: false,\n marqueeLastTimestamp: 0,\n isLoopRepositioning: false\n }\n\n let dragState: DragState | null = null\n\n const loopState = {\n initialized: false,\n clonedSlides: [] as HTMLElement[],\n realSlides: [...settings.slides] as HTMLElement[],\n clonesPerSide: 0\n }\n\n const marqueeState = createMarqueeState()\n\n const easing = settings.easing ?? easeOutExpo\n\n const getFeedRect = (): DOMRect => {\n const currentWidth = settings.feed.clientWidth\n if (!state.cachedFeedRect || state.lastWidth !== currentWidth) {\n state.cachedFeedRect = settings.feed.getBoundingClientRect()\n state.lastWidth = currentWidth\n }\n return state.cachedFeedRect\n }\n\n const getVisibleSlides = (): HTMLElement[] => {\n return settings.slides.filter((slide) => slide.offsetParent !== null)\n }\n\n const isDesktop = (): boolean => {\n return window.matchMedia(DESKTOP_BREAKPOINT).matches\n }\n\n const getLoopClonesCount = (): number => {\n const perView = isDesktop()\n ? settings.desktopSlidesPerView\n : settings.mobileSlidesPerView\n\n if (!perView || perView === 'auto') {\n return 1\n }\n return Math.ceil(perView)\n }\n\n const setupLoopClones = (): void => {\n if (!settings.loop || loopState.initialized) return\n\n const realSlides = loopState.realSlides\n const clonesCount = getLoopClonesCount()\n loopState.clonesPerSide = clonesCount\n\n for (let i = realSlides.length - clonesCount; i < realSlides.length; i++) {\n const slide = realSlides[i]\n if (!slide) continue\n\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-clone', 'prepend')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.insertBefore(clone, settings.feed.firstChild)\n loopState.clonedSlides.push(clone)\n }\n\n for (let i = 0; i < clonesCount; i++) {\n const slide = realSlides[i]\n if (!slide) continue\n\n const clone = slide.cloneNode(true) as HTMLElement\n clone.setAttribute('data-lazer-clone', 'append')\n clone.setAttribute('aria-hidden', 'true')\n settings.feed.appendChild(clone)\n loopState.clonedSlides.push(clone)\n }\n\n requestAnimationFrame(() => {\n const firstRealSlide = realSlides[0]\n if (firstRealSlide) {\n settings.feed.scrollLeft = firstRealSlide.offsetLeft\n }\n })\n\n loopState.initialized = true\n }\n\n const handleLoopReposition = (direction: SliderDirection): void => {\n if (!settings.loop || !loopState.initialized) return\n\n state.isLoopRepositioning = true\n\n const realSlides = loopState.realSlides\n const totalRealSlides = realSlides.length\n\n if (direction === 'next') {\n const firstRealSlide = realSlides[0]\n if (firstRealSlide) {\n settings.feed.scrollLeft = firstRealSlide.offsetLeft\n }\n state.currentSlideIndex = 0\n } else {\n const lastRealSlide = realSlides[totalRealSlides - 1]\n if (lastRealSlide) {\n settings.feed.scrollLeft = lastRealSlide.offsetLeft\n }\n state.currentSlideIndex = totalRealSlides - 1\n }\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n state.isLoopRepositioning = false\n updateControlsVisibility()\n })\n })\n }\n\n const cleanupLoopClones = (): void => {\n if (!loopState.initialized) return\n\n loopState.clonedSlides.forEach((clone) => {\n clone.remove()\n })\n\n loopState.clonedSlides = []\n loopState.initialized = false\n loopState.clonesPerSide = 0\n }\n\n const applySlideWidths = (): void => {\n const perView = isDesktop()\n ? settings.desktopSlidesPerView\n : settings.mobileSlidesPerView\n\n const gap = settings.slideGap ?? 0\n\n if (gap > 0) {\n settings.feed.style.gap = `${gap}px`\n }\n\n if (!perView || perView === 'auto') {\n settings.slides.forEach((slide) => {\n slide.style.flex = ''\n slide.style.minWidth = ''\n })\n return\n }\n\n const totalGapWidth = gap * (perView - 1)\n const slideWidth = `calc((100% - ${totalGapWidth}px) / ${perView})`\n\n settings.slides.forEach((slide) => {\n slide.style.flex = `0 0 ${slideWidth}`\n slide.style.minWidth = slideWidth\n })\n }\n\n const updateScrollbar = (): void => {\n if (!settings.scrollbarThumb) return\n\n const feedRect = getFeedRect()\n const thumbWidth = (feedRect.width / settings.feed.scrollWidth) * 100\n settings.scrollbarThumb.style.width = `${thumbWidth}%`\n }\n\n const updateScrollbarPosition = (): void => {\n if (!settings.scrollbarThumb || !settings.scrollbarTrack) return\n\n const trackWidth = settings.scrollbarTrack.getBoundingClientRect().width\n const thumbWidth = settings.scrollbarThumb.getBoundingClientRect().width\n const totalTransform = trackWidth - thumbWidth\n\n const maxScroll = settings.feed.scrollWidth - settings.feed.clientWidth\n const scrollProgress = maxScroll > 0 ? settings.feed.scrollLeft / maxScroll : 0\n\n settings.scrollbarThumb.style.transform = `translateX(${totalTransform * scrollProgress}px)`\n }\n\n const updateControlsVisibility = (): void => {\n // Skip visibility updates during loop repositioning to prevent flicker\n if (state.isLoopRepositioning) {\n return\n }\n\n const feedRect = getFeedRect()\n const isAtStart = settings.feed.scrollLeft <= 1\n const isAtEnd =\n settings.feed.scrollLeft + feedRect.width >= settings.feed.scrollWidth - 1\n const shouldHideScrollbar = settings.feed.scrollWidth <= feedRect.width\n\n if (settings.scrollbarTrack) {\n settings.scrollbarTrack.style.display = shouldHideScrollbar ? 'none' : 'block'\n }\n\n if (settings.loop) {\n toggleControlVisibility(\n settings.prevSlideButton,\n !shouldHideScrollbar,\n settings.feed\n )\n toggleControlVisibility(\n settings.nextSlideButton,\n !shouldHideScrollbar,\n settings.feed\n )\n return\n }\n\n toggleControlVisibility(\n settings.prevSlideButton,\n !isAtStart && !shouldHideScrollbar,\n settings.feed\n )\n toggleControlVisibility(\n settings.nextSlideButton,\n !isAtEnd && !shouldHideScrollbar,\n settings.feed\n )\n }\n\n const updateCurrentSlideIndex = (): void => {\n const feedRect = getFeedRect()\n\n const slidesToCheck = loopState.initialized\n ? loopState.realSlides\n : getVisibleSlides()\n\n const viewportVisibleSlides = slidesToCheck.filter((slide) => {\n const slideRect = slide.getBoundingClientRect()\n const tolerance = 20\n return (\n slideRect.right > feedRect.left + tolerance &&\n slideRect.left < feedRect.right - tolerance\n )\n })\n\n if (viewportVisibleSlides.length && viewportVisibleSlides[0]) {\n const newIndex = slidesToCheck.indexOf(viewportVisibleSlides[0])\n if (newIndex !== -1) {\n state.currentSlideIndex = newIndex\n settings.onScroll?.({\n currentScroll: settings.feed.scrollLeft,\n currentSlideIndex: state.currentSlideIndex\n })\n }\n }\n }\n\n const smoothScrollTo = (\n target: number,\n customEasing: EasingFunction = easing,\n onComplete?: () => void\n ): void => {\n const start = settings.feed.scrollLeft\n const distance = Math.abs(target - start)\n\n const duration = Math.min(\n ANIMATION.MAX_DURATION,\n Math.max(ANIMATION.MIN_DURATION, distance / ANIMATION.SPEED_FACTOR)\n )\n\n const startTime = performance.now()\n\n const animateScroll = (currentTime: number): void => {\n const elapsed = (currentTime - startTime) / duration\n const progress = Math.min(elapsed, 1)\n const ease = customEasing(progress)\n\n settings.feed.scrollLeft = start + (target - start) * ease\n\n if (progress < 1) {\n requestAnimationFrame(animateScroll)\n } else {\n settings.feed.scrollLeft = target\n onComplete?.()\n }\n }\n\n requestAnimationFrame(animateScroll)\n }\n\n const handleThumbClick = (thumb: HTMLElement): void => {\n if (!settings.thumbs) return\n\n const index = settings.thumbs.indexOf(thumb)\n if (index === -1 || !settings.slides[index]) return\n\n state.currentSlideIndex = index\n updateActiveThumb(settings.thumbs, index)\n state.isScrolling = true\n\n if (state.updateThumbTimeout) {\n clearTimeout(state.updateThumbTimeout)\n }\n\n state.updateThumbTimeout = setTimeout(() => {\n state.isScrolling = false\n }, ANIMATION.THUMB_UPDATE_DELAY)\n\n smoothScrollTo(settings.slides[index].offsetLeft)\n }\n\n const handleNavButtonClick = (direction: SliderDirection): void => {\n const realSlides = loopState.initialized ? loopState.realSlides : getVisibleSlides()\n const slidesToScroll = isDesktop()\n ? settings.desktopSlidesPerScroll ?? 1\n : settings.mobileSlidesPerScroll ?? 1\n const totalRealSlides = realSlides.length\n\n updateCurrentSlideIndex()\n\n let targetSlide: HTMLElement | undefined\n let needsReposition = false\n\n if (direction === 'prev') {\n if (settings.loop && loopState.initialized && state.currentSlideIndex === 0) {\n\n const prependedClones = loopState.clonedSlides.filter(\n (clone) => clone.getAttribute('data-lazer-clone') === 'prepend'\n )\n targetSlide = prependedClones[prependedClones.length - 1]\n needsReposition = true\n } else {\n state.currentSlideIndex = Math.max(0, state.currentSlideIndex - slidesToScroll)\n targetSlide = realSlides[state.currentSlideIndex]\n }\n } else {\n if (settings.loop && loopState.initialized && state.currentSlideIndex >= totalRealSlides - 1) {\n const appendedClones = loopState.clonedSlides.filter(\n (clone) => clone.getAttribute('data-lazer-clone') === 'append'\n )\n targetSlide = appendedClones[0]\n needsReposition = true\n } else {\n state.currentSlideIndex = Math.min(\n totalRealSlides - 1,\n state.currentSlideIndex + slidesToScroll\n )\n targetSlide = realSlides[state.currentSlideIndex]\n }\n }\n\n if (!targetSlide) return\n\n settings.onScrollStart?.({\n currentScroll: settings.feed.scrollLeft,\n target: targetSlide,\n direction\n })\n\n if (needsReposition) {\n smoothScrollTo(targetSlide.offsetLeft, easing, () => {\n handleLoopReposition(direction)\n })\n } else {\n smoothScrollTo(targetSlide.offsetLeft)\n }\n }\n\n const updateScrollPosition = (): void => {\n updateScrollbarPosition()\n updateControlsVisibility()\n updateCurrentSlideIndex()\n\n if (!state.isScrolling) {\n updateActiveThumb(settings.thumbs, state.currentSlideIndex)\n }\n\n if (state.scrollEndTimeout) {\n clearTimeout(state.scrollEndTimeout)\n }\n\n state.scrollEndTimeout = setTimeout(() => {\n state.isScrolling = false\n settings.onScrollEnd?.({\n currentScroll: settings.feed.scrollLeft,\n currentSlideIndex: state.currentSlideIndex\n })\n }, ANIMATION.SCROLL_END_DELAY)\n }\n\n const handleFeedScroll = (): void => {\n if (!state.ticking) {\n requestAnimationFrame(() => {\n updateScrollPosition()\n state.ticking = false\n })\n state.ticking = true\n }\n }\n\n const handleWindowResize = (): void => {\n if (state.resizeTimeout) {\n clearTimeout(state.resizeTimeout)\n }\n\n // Debounce resize handling (150ms is a good balance for performance)\n state.resizeTimeout = setTimeout(() => {\n state.cachedFeedRect = null\n\n updateCurrentSlideIndex()\n const currentIndex = state.currentSlideIndex\n\n refresh()\n\n const slides = loopState.initialized ? loopState.realSlides : getVisibleSlides()\n\n const targetSlide = slides[currentIndex]\n if (targetSlide) {\n settings.feed.scrollLeft = targetSlide.offsetLeft\n }\n }, 150)\n }\n\n const attachEventListeners = (): void => {\n const { signal } = state.abortController\n\n window.addEventListener('resize', handleWindowResize)\n\n settings.feed.addEventListener('scroll', handleFeedScroll, {\n passive: true,\n signal\n })\n\n if (settings.prevSlideButton) {\n settings.prevSlideButton.addEventListener(\n 'click',\n () => handleNavButtonClick('prev'),\n { signal }\n )\n }\n\n if (settings.nextSlideButton) {\n settings.nextSlideButton.addEventListener(\n 'click',\n () => handleNavButtonClick('next'),\n { signal }\n )\n }\n\n if (settings.thumbs?.length) {\n settings.thumbs[0]?.classList.add('active')\n settings.thumbs.forEach((thumb) => {\n thumb.addEventListener('click', () => handleThumbClick(thumb), { signal })\n })\n }\n\n setupKeyboardNavigation(\n settings.feed,\n () => handleNavButtonClick('prev'),\n () => handleNavButtonClick('next'),\n signal\n )\n\n if (settings.enableDragToScroll) {\n dragState = setupDragToScroll({\n feed: settings.feed,\n slides: settings.slides,\n abortSignal: signal,\n smoothScrollTo,\n onDragEnd: () => {\n updateCurrentSlideIndex()\n updateActiveThumb(settings.thumbs, state.currentSlideIndex)\n },\n dragFree: settings.dragFree\n })\n }\n\n if (settings.autoplay && settings.pauseOnHover !== false) {\n settings.feed.addEventListener(\n 'mouseenter',\n pauseAutoplay,\n { signal }\n )\n settings.feed.addEventListener(\n 'mouseleave',\n resumeAutoplay,\n { signal }\n )\n settings.feed.addEventListener(\n 'touchstart',\n pauseAutoplay,\n { passive: true, signal }\n )\n settings.feed.addEventListener(\n 'touchend',\n resumeAutoplay,\n { signal }\n )\n }\n\n attachMarqueeEventListeners(settings, state, signal)\n }\n\n const startAutoplay = (): void => {\n if (state.autoplayIntervalId) return;\n\n const interval = settings.autoplayInterval ?? 3000\n state.autoplayIntervalId = setInterval(() => {\n if (!state.autoplayPaused) {\n handleNavButtonClick('next')\n }\n }, interval)\n }\n\n const stopAutoplay = (): void => {\n if (state.autoplayIntervalId) {\n clearInterval(state.autoplayIntervalId)\n state.autoplayIntervalId = null\n }\n }\n\n const pauseAutoplay = (): void => {\n state.autoplayPaused = true\n }\n\n const resumeAutoplay = (): void => {\n state.autoplayPaused = false\n }\n\n const goToIndex = (index: number): void => {\n const slides = loopState.initialized ? loopState.realSlides : getVisibleSlides()\n const safeIndex = Math.max(0, Math.min(index, slides.length - 1))\n const targetSlide = slides[safeIndex]\n\n if (!targetSlide) return\n\n state.currentSlideIndex = safeIndex\n updateActiveThumb(settings.thumbs, safeIndex)\n smoothScrollTo(targetSlide.offsetLeft)\n }\n\n const refresh = (): void => {\n state.cachedFeedRect = null\n applySlideWidths()\n updateScrollbar()\n updateControlsVisibility()\n\n if (settings.marquee && !state.marqueePaused) {\n startMarquee(settings, state)\n }\n }\n\n const unload = (): void => {\n stopAutoplay()\n stopMarquee(state, settings)\n\n state.abortController.abort()\n window.removeEventListener('resize', handleWindowResize)\n\n if (state.updateThumbTimeout) {\n clearTimeout(state.updateThumbTimeout)\n }\n if (state.scrollEndTimeout) {\n clearTimeout(state.scrollEndTimeout)\n }\n if (state.resizeTimeout) {\n clearTimeout(state.resizeTimeout)\n }\n\n if (dragState) {\n cleanupDrag(dragState)\n }\n\n cleanupLoopClones()\n cleanupMarqueeClones(marqueeState)\n\n state.cachedFeedRect = null\n }\n\n initAria(settings)\n applySlideWidths()\n\n if (settings.marquee) {\n setupMarquee(settings, state, marqueeState)\n } else {\n setupLoopClones()\n if (settings.autoplay) {\n startAutoplay()\n }\n }\n\n updateControlsVisibility()\n attachEventListeners()\n updateScrollbar()\n\n const play = (): void => {\n if (settings.marquee) {\n if (state.marqueePaused) {\n resumeMarquee(state, settings)\n } else {\n startMarquee(settings, state)\n }\n } else if (settings.autoplay) {\n startAutoplay()\n }\n }\n\n const pause = (): void => {\n if (settings.marquee) {\n pauseMarquee(state, settings)\n } else {\n stopAutoplay()\n }\n }\n\n return {\n goToIndex,\n refresh,\n unload,\n play,\n pause,\n next: () => handleNavButtonClick('next'),\n prev: () => handleNavButtonClick('prev')\n }\n}"],"mappings":"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","names":[]}
|
package/package.json
CHANGED