lazer-slider 1.0.6 → 1.0.8
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 +41 -4
- package/dist/index.cjs +145 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +145 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ A lightweight, accessible slider with smooth scroll-to-snap animations, drag-to-
|
|
|
9
9
|
- **Responsive** - Separate settings for mobile and desktop (slidesPerView, slidesPerScroll)
|
|
10
10
|
- **Loop Mode** - Infinite loop navigation
|
|
11
11
|
- **Autoplay** - Automatic slide advancement with pause on hover
|
|
12
|
+
- **Marquee Mode** - Continuous smooth scrolling with seamless infinite loop
|
|
12
13
|
- **Accessible** - Full ARIA support, keyboard navigation (arrow keys)
|
|
13
14
|
- **Lightweight** - Zero dependencies, ~20KB unminified
|
|
14
15
|
- **TypeScript** - Full type definitions included
|
|
@@ -120,8 +121,13 @@ slider.unload()
|
|
|
120
121
|
| `autoplay` | `boolean` | `false` | Enable automatic slide advancement |
|
|
121
122
|
| `autoplayInterval` | `number` | `3000` | Autoplay interval in milliseconds |
|
|
122
123
|
| `pauseOnHover` | `boolean` | `true` | Pause autoplay on hover/touch |
|
|
124
|
+
| `marquee` | `boolean` | `false` | Enable marquee mode (continuous scroll, overrides autoplay/loop) |
|
|
125
|
+
| `marqueeSpeed` | `number` | `50` | Marquee scroll speed in pixels per second |
|
|
126
|
+
| `marqueeDirection` | `'left' \| 'right'` | `'left'` | Marquee scroll direction |
|
|
123
127
|
| `easing` | `EasingFunction` | `easeOutExpo` | Custom easing function |
|
|
124
128
|
|
|
129
|
+
> **Note:** When `marquee` is enabled, it takes precedence over `loop` and `autoplay` settings. Marquee mode provides continuous smooth scrolling suitable for ticker-style content displays.
|
|
130
|
+
|
|
125
131
|
### Scrollbar (Optional)
|
|
126
132
|
|
|
127
133
|
| Option | Type | Default | Description |
|
|
@@ -166,9 +172,9 @@ slider.goToIndex(2)
|
|
|
166
172
|
slider.next()
|
|
167
173
|
slider.prev()
|
|
168
174
|
|
|
169
|
-
// Autoplay control
|
|
170
|
-
slider.play() // Start autoplay
|
|
171
|
-
slider.pause() // Stop autoplay
|
|
175
|
+
// Autoplay/Marquee control
|
|
176
|
+
slider.play() // Start autoplay or marquee
|
|
177
|
+
slider.pause() // Stop autoplay or marquee
|
|
172
178
|
|
|
173
179
|
// Recalculate dimensions (call after DOM changes)
|
|
174
180
|
slider.refresh()
|
|
@@ -258,6 +264,36 @@ const slider = createSlider({
|
|
|
258
264
|
})
|
|
259
265
|
```
|
|
260
266
|
|
|
267
|
+
### Marquee Mode
|
|
268
|
+
|
|
269
|
+
Create a continuous scrolling marquee effect with seamless infinite loop. Perfect for ticker-style content, logos, or announcements.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
const marquee = createSlider({
|
|
273
|
+
feed: document.querySelector('.marquee-feed'),
|
|
274
|
+
slides: [...document.querySelectorAll('.marquee-item')],
|
|
275
|
+
marquee: true,
|
|
276
|
+
marqueeSpeed: 80, // 80 pixels per second
|
|
277
|
+
marqueeDirection: 'left', // or 'right'
|
|
278
|
+
pauseOnHover: true // Pause on hover (default: true)
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
// Control programmatically
|
|
282
|
+
marquee.pause() // Stop marquee
|
|
283
|
+
marquee.play() // Resume marquee
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Key Features:**
|
|
287
|
+
- Continuous smooth scrolling (not slide-by-slide)
|
|
288
|
+
- Frame-rate independent animation for consistent speed
|
|
289
|
+
- Automatic content cloning for seamless infinite loop
|
|
290
|
+
- Pause on hover/touch support
|
|
291
|
+
- Works with any number of slides
|
|
292
|
+
|
|
293
|
+
**When to use Marquee vs Autoplay:**
|
|
294
|
+
- **Marquee**: For continuous ticker-style scrolling (news tickers, logo carousels, announcements)
|
|
295
|
+
- **Autoplay**: For slide-by-slide carousel navigation (image galleries, product showcases)
|
|
296
|
+
|
|
261
297
|
### Bullets/Dots Navigation
|
|
262
298
|
|
|
263
299
|
Use the `thumbs` option to add clickable dots that navigate to specific slides. The slider automatically manages the `active` class.
|
|
@@ -438,7 +474,8 @@ import {
|
|
|
438
474
|
type EasingFunction,
|
|
439
475
|
type ScrollParams,
|
|
440
476
|
type ScrollStartParams,
|
|
441
|
-
type SliderDirection
|
|
477
|
+
type SliderDirection,
|
|
478
|
+
type MarqueeDirection
|
|
442
479
|
} from 'lazer-slider'
|
|
443
480
|
```
|
|
444
481
|
|
package/dist/index.cjs
CHANGED
|
@@ -265,6 +265,112 @@ var cleanupDrag = (state) => {
|
|
|
265
265
|
}
|
|
266
266
|
};
|
|
267
267
|
|
|
268
|
+
// src/core/marquee.ts
|
|
269
|
+
var createMarqueeState = () => ({
|
|
270
|
+
initialized: false,
|
|
271
|
+
clonedSlides: [],
|
|
272
|
+
styleElement: null
|
|
273
|
+
});
|
|
274
|
+
var injectMarqueeKeyframes = () => {
|
|
275
|
+
const existingStyle = document.getElementById("lazer-marquee-keyframes");
|
|
276
|
+
if (existingStyle) {
|
|
277
|
+
return existingStyle;
|
|
278
|
+
}
|
|
279
|
+
const style = document.createElement("style");
|
|
280
|
+
style.id = "lazer-marquee-keyframes";
|
|
281
|
+
style.textContent = `
|
|
282
|
+
@keyframes lazer-marquee-scroll {
|
|
283
|
+
from {
|
|
284
|
+
transform: translateX(0);
|
|
285
|
+
}
|
|
286
|
+
to {
|
|
287
|
+
transform: translateX(calc(-1 * var(--lazer-marquee-distance) * 1px));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
`;
|
|
291
|
+
document.head.appendChild(style);
|
|
292
|
+
return style;
|
|
293
|
+
};
|
|
294
|
+
var setupMarqueeClones = (settings, marqueeState) => {
|
|
295
|
+
if (marqueeState.initialized) return;
|
|
296
|
+
marqueeState.styleElement = injectMarqueeKeyframes();
|
|
297
|
+
settings.feed.style.display = "flex";
|
|
298
|
+
settings.feed.style.willChange = "transform";
|
|
299
|
+
settings.slides.forEach((slide) => {
|
|
300
|
+
const clone = slide.cloneNode(true);
|
|
301
|
+
clone.setAttribute("data-lazer-marquee-clone", "true");
|
|
302
|
+
clone.setAttribute("aria-hidden", "true");
|
|
303
|
+
settings.feed.appendChild(clone);
|
|
304
|
+
marqueeState.clonedSlides.push(clone);
|
|
305
|
+
});
|
|
306
|
+
marqueeState.initialized = true;
|
|
307
|
+
};
|
|
308
|
+
var cleanupMarqueeClones = (marqueeState) => {
|
|
309
|
+
if (!marqueeState.initialized) return;
|
|
310
|
+
marqueeState.clonedSlides.forEach((clone) => {
|
|
311
|
+
clone.remove();
|
|
312
|
+
});
|
|
313
|
+
marqueeState.clonedSlides = [];
|
|
314
|
+
marqueeState.initialized = false;
|
|
315
|
+
};
|
|
316
|
+
var setupMarqueeCss = (settings, state) => {
|
|
317
|
+
const scrollWidth = settings.feed.scrollWidth;
|
|
318
|
+
const speed = settings.marqueeSpeed ?? 50;
|
|
319
|
+
const direction = settings.marqueeDirection ?? "left";
|
|
320
|
+
const distance = scrollWidth / 2;
|
|
321
|
+
settings.feed.style.setProperty("--lazer-marquee-distance", String(distance));
|
|
322
|
+
const duration = distance / speed;
|
|
323
|
+
const animationDirection = direction === "right" ? "reverse" : "normal";
|
|
324
|
+
settings.feed.style.animation = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`;
|
|
325
|
+
settings.feed.style.animationPlayState = state.marqueePaused ? "paused" : "running";
|
|
326
|
+
};
|
|
327
|
+
var startMarquee = (settings, state) => {
|
|
328
|
+
setupMarqueeCss(settings, state);
|
|
329
|
+
};
|
|
330
|
+
var stopMarquee = (state, settings) => {
|
|
331
|
+
settings.feed.style.animation = "";
|
|
332
|
+
settings.feed.style.animationPlayState = "";
|
|
333
|
+
settings.feed.style.transform = "";
|
|
334
|
+
settings.feed.style.willChange = "";
|
|
335
|
+
settings.feed.style.removeProperty("--lazer-marquee-distance");
|
|
336
|
+
};
|
|
337
|
+
var pauseMarquee = (state, settings) => {
|
|
338
|
+
state.marqueePaused = true;
|
|
339
|
+
settings.feed.style.animationPlayState = "paused";
|
|
340
|
+
};
|
|
341
|
+
var resumeMarquee = (state, settings) => {
|
|
342
|
+
state.marqueePaused = false;
|
|
343
|
+
settings.feed.style.animationPlayState = "running";
|
|
344
|
+
};
|
|
345
|
+
var setupMarquee = (settings, state, marqueeState) => {
|
|
346
|
+
if (!settings.marquee) return;
|
|
347
|
+
setupMarqueeClones(settings, marqueeState);
|
|
348
|
+
startMarquee(settings, state);
|
|
349
|
+
};
|
|
350
|
+
var attachMarqueeEventListeners = (settings, state, signal) => {
|
|
351
|
+
if (!settings.marquee || settings.pauseOnHover === false) return;
|
|
352
|
+
settings.feed.addEventListener(
|
|
353
|
+
"mouseenter",
|
|
354
|
+
() => pauseMarquee(state, settings),
|
|
355
|
+
{ signal }
|
|
356
|
+
);
|
|
357
|
+
settings.feed.addEventListener(
|
|
358
|
+
"mouseleave",
|
|
359
|
+
() => resumeMarquee(state, settings),
|
|
360
|
+
{ signal }
|
|
361
|
+
);
|
|
362
|
+
settings.feed.addEventListener(
|
|
363
|
+
"touchstart",
|
|
364
|
+
() => pauseMarquee(state, settings),
|
|
365
|
+
{ passive: true, signal }
|
|
366
|
+
);
|
|
367
|
+
settings.feed.addEventListener(
|
|
368
|
+
"touchend",
|
|
369
|
+
() => resumeMarquee(state, settings),
|
|
370
|
+
{ signal }
|
|
371
|
+
);
|
|
372
|
+
};
|
|
373
|
+
|
|
268
374
|
// src/core/slider.ts
|
|
269
375
|
var ANIMATION = {
|
|
270
376
|
MIN_DURATION: 400,
|
|
@@ -291,7 +397,10 @@ var createSlider = (settings) => {
|
|
|
291
397
|
scrollEndTimeout: null,
|
|
292
398
|
abortController: new AbortController(),
|
|
293
399
|
autoplayIntervalId: null,
|
|
294
|
-
autoplayPaused: false
|
|
400
|
+
autoplayPaused: false,
|
|
401
|
+
marqueeAnimationId: null,
|
|
402
|
+
marqueePaused: false,
|
|
403
|
+
marqueeLastTimestamp: 0
|
|
295
404
|
};
|
|
296
405
|
let dragState = null;
|
|
297
406
|
const loopState = {
|
|
@@ -300,6 +409,7 @@ var createSlider = (settings) => {
|
|
|
300
409
|
realSlides: [...settings.slides],
|
|
301
410
|
clonesPerSide: 0
|
|
302
411
|
};
|
|
412
|
+
const marqueeState = createMarqueeState();
|
|
303
413
|
const easing = settings.easing ?? easeOutExpo;
|
|
304
414
|
const getFeedRect = () => {
|
|
305
415
|
const currentWidth = settings.feed.clientWidth;
|
|
@@ -648,6 +758,7 @@ var createSlider = (settings) => {
|
|
|
648
758
|
{ signal }
|
|
649
759
|
);
|
|
650
760
|
}
|
|
761
|
+
attachMarqueeEventListeners(settings, state, signal);
|
|
651
762
|
};
|
|
652
763
|
const startAutoplay = () => {
|
|
653
764
|
if (state.autoplayIntervalId) return;
|
|
@@ -684,9 +795,13 @@ var createSlider = (settings) => {
|
|
|
684
795
|
applySlideWidths();
|
|
685
796
|
updateScrollbar();
|
|
686
797
|
updateControlsVisibility();
|
|
798
|
+
if (settings.marquee && !state.marqueePaused) {
|
|
799
|
+
startMarquee(settings, state);
|
|
800
|
+
}
|
|
687
801
|
};
|
|
688
802
|
const unload = () => {
|
|
689
803
|
stopAutoplay();
|
|
804
|
+
stopMarquee(state, settings);
|
|
690
805
|
state.abortController.abort();
|
|
691
806
|
window.removeEventListener("resize", handleWindowResize);
|
|
692
807
|
if (state.updateThumbTimeout) {
|
|
@@ -699,23 +814,46 @@ var createSlider = (settings) => {
|
|
|
699
814
|
cleanupDrag(dragState);
|
|
700
815
|
}
|
|
701
816
|
cleanupLoopClones();
|
|
817
|
+
cleanupMarqueeClones(marqueeState);
|
|
702
818
|
state.cachedFeedRect = null;
|
|
703
819
|
};
|
|
704
820
|
initAria(settings);
|
|
705
821
|
applySlideWidths();
|
|
706
|
-
|
|
822
|
+
if (settings.marquee) {
|
|
823
|
+
setupMarquee(settings, state, marqueeState);
|
|
824
|
+
} else {
|
|
825
|
+
setupLoopClones();
|
|
826
|
+
if (settings.autoplay) {
|
|
827
|
+
startAutoplay();
|
|
828
|
+
}
|
|
829
|
+
}
|
|
707
830
|
updateControlsVisibility();
|
|
708
831
|
attachEventListeners();
|
|
709
832
|
updateScrollbar();
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
833
|
+
const play = () => {
|
|
834
|
+
if (settings.marquee) {
|
|
835
|
+
if (state.marqueePaused) {
|
|
836
|
+
resumeMarquee(state, settings);
|
|
837
|
+
} else {
|
|
838
|
+
startMarquee(settings, state);
|
|
839
|
+
}
|
|
840
|
+
} else if (settings.autoplay) {
|
|
841
|
+
startAutoplay();
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
const pause = () => {
|
|
845
|
+
if (settings.marquee) {
|
|
846
|
+
pauseMarquee(state, settings);
|
|
847
|
+
} else {
|
|
848
|
+
stopAutoplay();
|
|
849
|
+
}
|
|
850
|
+
};
|
|
713
851
|
return {
|
|
714
852
|
goToIndex,
|
|
715
853
|
refresh,
|
|
716
854
|
unload,
|
|
717
|
-
play
|
|
718
|
-
pause
|
|
855
|
+
play,
|
|
856
|
+
pause,
|
|
719
857
|
next: () => handleNavButtonClick("next"),
|
|
720
858
|
prev: () => handleNavButtonClick("prev")
|
|
721
859
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/easing.ts","../src/core/accessibility.ts","../src/core/drag.ts","../src/core/slider.ts"],"sourcesContent":["// Main slider factory\nexport { createSlider } from './core/slider.js'\n\n// Types\nexport type {\n SliderSettings,\n SliderState,\n SliderDirection,\n ScrollStartParams,\n ScrollParams,\n EasingFunction,\n Slider,\n DragState\n} from './core/types.js'\n\n// Easing functions\nexport {\n easeOutExpo,\n easeOutCubic,\n easeInOutCubic,\n easeOutQuad,\n linear\n} from './core/easing.js'\n","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 {\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'\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 }\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 // 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\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\n /**\n * Clean up all event listeners and timers\n */\n const unload = (): void => {\n // Stop autoplay\n stopAutoplay()\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\n cleanupLoopClones()\n\n // Reset cached rect\n state.cachedFeedRect = null\n }\n\n // Initialize slider\n initAria(settings)\n applySlideWidths()\n setupLoopClones()\n updateControlsVisibility()\n attachEventListeners()\n updateScrollbar()\n\n // Start autoplay if enabled\n if (settings.autoplay) {\n startAutoplay()\n }\n\n return {\n goToIndex,\n refresh,\n unload,\n play: startAutoplay,\n pause: stopAutoplay,\n next: () => handleNavButtonClick('next'),\n prev: () => handleNavButtonClick('prev')\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/easing.ts","../src/core/accessibility.ts","../src/core/drag.ts","../src/core/marquee.ts","../src/core/slider.ts"],"sourcesContent":["// Main slider factory\nexport { createSlider } from './core/slider.js'\n\n// Types\nexport type {\n SliderSettings,\n SliderState,\n SliderDirection,\n MarqueeDirection,\n ScrollStartParams,\n ScrollParams,\n EasingFunction,\n Slider,\n DragState\n} from './core/types.js'\n\n// Easing functions\nexport {\n easeOutExpo,\n easeOutCubic,\n easeInOutCubic,\n easeOutQuad,\n linear\n} from './core/easing.js'\n","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 from {\n transform: translateX(0);\n }\n to {\n transform: translateX(calc(-1 * var(--lazer-marquee-distance) * 1px));\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 const scrollWidth = settings.feed.scrollWidth\n const speed = settings.marqueeSpeed ?? 50 // pixels per second\n const direction = settings.marqueeDirection ?? 'left'\n const distance = scrollWidth / 2\n\n // Set CSS custom property for the exact pixel distance\n settings.feed.style.setProperty('--lazer-marquee-distance', String(distance))\n\n // Calculate duration: distance / speed\n const duration = distance / speed\n const animationDirection = direction === 'right' ? 'reverse' : 'normal'\n\n // Apply smooth CSS animation with hardware acceleration\n settings.feed.style.animation = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`\n settings.feed.style.animationPlayState = state.marqueePaused ? 'paused' : 'running'\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 and CSS custom property\n settings.feed.style.transform = ''\n settings.feed.style.willChange = ''\n settings.feed.style.removeProperty('--lazer-marquee-distance')\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":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,10 @@ type EasingFunction = (t: number) => number;
|
|
|
6
6
|
* Direction of slider navigation
|
|
7
7
|
*/
|
|
8
8
|
type SliderDirection = 'prev' | 'next';
|
|
9
|
+
/**
|
|
10
|
+
* Direction of marquee scroll
|
|
11
|
+
*/
|
|
12
|
+
type MarqueeDirection = 'left' | 'right';
|
|
9
13
|
/**
|
|
10
14
|
* Parameters passed to scroll start callback
|
|
11
15
|
*/
|
|
@@ -64,6 +68,12 @@ interface SliderSettings {
|
|
|
64
68
|
autoplayInterval?: number;
|
|
65
69
|
/** Pause autoplay on hover/touch (default: true) */
|
|
66
70
|
pauseOnHover?: boolean;
|
|
71
|
+
/** Enable marquee mode (continuous scroll, overrides autoplay/loop) */
|
|
72
|
+
marquee?: boolean;
|
|
73
|
+
/** Marquee scroll speed in pixels per second (default: 50) */
|
|
74
|
+
marqueeSpeed?: number;
|
|
75
|
+
/** Marquee scroll direction (default: 'left') */
|
|
76
|
+
marqueeDirection?: MarqueeDirection;
|
|
67
77
|
/** Custom easing function for smooth scroll animation */
|
|
68
78
|
easing?: EasingFunction;
|
|
69
79
|
/** Callback fired when scroll animation starts */
|
|
@@ -97,6 +107,12 @@ interface SliderState {
|
|
|
97
107
|
autoplayIntervalId: ReturnType<typeof setInterval> | null;
|
|
98
108
|
/** Whether autoplay is currently paused */
|
|
99
109
|
autoplayPaused: boolean;
|
|
110
|
+
/** Animation frame ID for marquee */
|
|
111
|
+
marqueeAnimationId: number | null;
|
|
112
|
+
/** Whether marquee is currently paused */
|
|
113
|
+
marqueePaused: boolean;
|
|
114
|
+
/** Last timestamp for marquee animation (for delta time calculation) */
|
|
115
|
+
marqueeLastTimestamp: number;
|
|
100
116
|
}
|
|
101
117
|
/**
|
|
102
118
|
* Drag state for drag-to-scroll functionality
|
|
@@ -164,4 +180,4 @@ declare const easeOutQuad: EasingFunction;
|
|
|
164
180
|
*/
|
|
165
181
|
declare const linear: EasingFunction;
|
|
166
182
|
|
|
167
|
-
export { type DragState, type EasingFunction, type ScrollParams, type ScrollStartParams, type Slider, type SliderDirection, type SliderSettings, type SliderState, createSlider, easeInOutCubic, easeOutCubic, easeOutExpo, easeOutQuad, linear };
|
|
183
|
+
export { type DragState, type EasingFunction, type MarqueeDirection, type ScrollParams, type ScrollStartParams, type Slider, type SliderDirection, type SliderSettings, type SliderState, createSlider, easeInOutCubic, easeOutCubic, easeOutExpo, easeOutQuad, linear };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ type EasingFunction = (t: number) => number;
|
|
|
6
6
|
* Direction of slider navigation
|
|
7
7
|
*/
|
|
8
8
|
type SliderDirection = 'prev' | 'next';
|
|
9
|
+
/**
|
|
10
|
+
* Direction of marquee scroll
|
|
11
|
+
*/
|
|
12
|
+
type MarqueeDirection = 'left' | 'right';
|
|
9
13
|
/**
|
|
10
14
|
* Parameters passed to scroll start callback
|
|
11
15
|
*/
|
|
@@ -64,6 +68,12 @@ interface SliderSettings {
|
|
|
64
68
|
autoplayInterval?: number;
|
|
65
69
|
/** Pause autoplay on hover/touch (default: true) */
|
|
66
70
|
pauseOnHover?: boolean;
|
|
71
|
+
/** Enable marquee mode (continuous scroll, overrides autoplay/loop) */
|
|
72
|
+
marquee?: boolean;
|
|
73
|
+
/** Marquee scroll speed in pixels per second (default: 50) */
|
|
74
|
+
marqueeSpeed?: number;
|
|
75
|
+
/** Marquee scroll direction (default: 'left') */
|
|
76
|
+
marqueeDirection?: MarqueeDirection;
|
|
67
77
|
/** Custom easing function for smooth scroll animation */
|
|
68
78
|
easing?: EasingFunction;
|
|
69
79
|
/** Callback fired when scroll animation starts */
|
|
@@ -97,6 +107,12 @@ interface SliderState {
|
|
|
97
107
|
autoplayIntervalId: ReturnType<typeof setInterval> | null;
|
|
98
108
|
/** Whether autoplay is currently paused */
|
|
99
109
|
autoplayPaused: boolean;
|
|
110
|
+
/** Animation frame ID for marquee */
|
|
111
|
+
marqueeAnimationId: number | null;
|
|
112
|
+
/** Whether marquee is currently paused */
|
|
113
|
+
marqueePaused: boolean;
|
|
114
|
+
/** Last timestamp for marquee animation (for delta time calculation) */
|
|
115
|
+
marqueeLastTimestamp: number;
|
|
100
116
|
}
|
|
101
117
|
/**
|
|
102
118
|
* Drag state for drag-to-scroll functionality
|
|
@@ -164,4 +180,4 @@ declare const easeOutQuad: EasingFunction;
|
|
|
164
180
|
*/
|
|
165
181
|
declare const linear: EasingFunction;
|
|
166
182
|
|
|
167
|
-
export { type DragState, type EasingFunction, type ScrollParams, type ScrollStartParams, type Slider, type SliderDirection, type SliderSettings, type SliderState, createSlider, easeInOutCubic, easeOutCubic, easeOutExpo, easeOutQuad, linear };
|
|
183
|
+
export { type DragState, type EasingFunction, type MarqueeDirection, type ScrollParams, type ScrollStartParams, type Slider, type SliderDirection, type SliderSettings, type SliderState, createSlider, easeInOutCubic, easeOutCubic, easeOutExpo, easeOutQuad, linear };
|
package/dist/index.js
CHANGED
|
@@ -234,6 +234,112 @@ var cleanupDrag = (state) => {
|
|
|
234
234
|
}
|
|
235
235
|
};
|
|
236
236
|
|
|
237
|
+
// src/core/marquee.ts
|
|
238
|
+
var createMarqueeState = () => ({
|
|
239
|
+
initialized: false,
|
|
240
|
+
clonedSlides: [],
|
|
241
|
+
styleElement: null
|
|
242
|
+
});
|
|
243
|
+
var injectMarqueeKeyframes = () => {
|
|
244
|
+
const existingStyle = document.getElementById("lazer-marquee-keyframes");
|
|
245
|
+
if (existingStyle) {
|
|
246
|
+
return existingStyle;
|
|
247
|
+
}
|
|
248
|
+
const style = document.createElement("style");
|
|
249
|
+
style.id = "lazer-marquee-keyframes";
|
|
250
|
+
style.textContent = `
|
|
251
|
+
@keyframes lazer-marquee-scroll {
|
|
252
|
+
from {
|
|
253
|
+
transform: translateX(0);
|
|
254
|
+
}
|
|
255
|
+
to {
|
|
256
|
+
transform: translateX(calc(-1 * var(--lazer-marquee-distance) * 1px));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
`;
|
|
260
|
+
document.head.appendChild(style);
|
|
261
|
+
return style;
|
|
262
|
+
};
|
|
263
|
+
var setupMarqueeClones = (settings, marqueeState) => {
|
|
264
|
+
if (marqueeState.initialized) return;
|
|
265
|
+
marqueeState.styleElement = injectMarqueeKeyframes();
|
|
266
|
+
settings.feed.style.display = "flex";
|
|
267
|
+
settings.feed.style.willChange = "transform";
|
|
268
|
+
settings.slides.forEach((slide) => {
|
|
269
|
+
const clone = slide.cloneNode(true);
|
|
270
|
+
clone.setAttribute("data-lazer-marquee-clone", "true");
|
|
271
|
+
clone.setAttribute("aria-hidden", "true");
|
|
272
|
+
settings.feed.appendChild(clone);
|
|
273
|
+
marqueeState.clonedSlides.push(clone);
|
|
274
|
+
});
|
|
275
|
+
marqueeState.initialized = true;
|
|
276
|
+
};
|
|
277
|
+
var cleanupMarqueeClones = (marqueeState) => {
|
|
278
|
+
if (!marqueeState.initialized) return;
|
|
279
|
+
marqueeState.clonedSlides.forEach((clone) => {
|
|
280
|
+
clone.remove();
|
|
281
|
+
});
|
|
282
|
+
marqueeState.clonedSlides = [];
|
|
283
|
+
marqueeState.initialized = false;
|
|
284
|
+
};
|
|
285
|
+
var setupMarqueeCss = (settings, state) => {
|
|
286
|
+
const scrollWidth = settings.feed.scrollWidth;
|
|
287
|
+
const speed = settings.marqueeSpeed ?? 50;
|
|
288
|
+
const direction = settings.marqueeDirection ?? "left";
|
|
289
|
+
const distance = scrollWidth / 2;
|
|
290
|
+
settings.feed.style.setProperty("--lazer-marquee-distance", String(distance));
|
|
291
|
+
const duration = distance / speed;
|
|
292
|
+
const animationDirection = direction === "right" ? "reverse" : "normal";
|
|
293
|
+
settings.feed.style.animation = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`;
|
|
294
|
+
settings.feed.style.animationPlayState = state.marqueePaused ? "paused" : "running";
|
|
295
|
+
};
|
|
296
|
+
var startMarquee = (settings, state) => {
|
|
297
|
+
setupMarqueeCss(settings, state);
|
|
298
|
+
};
|
|
299
|
+
var stopMarquee = (state, settings) => {
|
|
300
|
+
settings.feed.style.animation = "";
|
|
301
|
+
settings.feed.style.animationPlayState = "";
|
|
302
|
+
settings.feed.style.transform = "";
|
|
303
|
+
settings.feed.style.willChange = "";
|
|
304
|
+
settings.feed.style.removeProperty("--lazer-marquee-distance");
|
|
305
|
+
};
|
|
306
|
+
var pauseMarquee = (state, settings) => {
|
|
307
|
+
state.marqueePaused = true;
|
|
308
|
+
settings.feed.style.animationPlayState = "paused";
|
|
309
|
+
};
|
|
310
|
+
var resumeMarquee = (state, settings) => {
|
|
311
|
+
state.marqueePaused = false;
|
|
312
|
+
settings.feed.style.animationPlayState = "running";
|
|
313
|
+
};
|
|
314
|
+
var setupMarquee = (settings, state, marqueeState) => {
|
|
315
|
+
if (!settings.marquee) return;
|
|
316
|
+
setupMarqueeClones(settings, marqueeState);
|
|
317
|
+
startMarquee(settings, state);
|
|
318
|
+
};
|
|
319
|
+
var attachMarqueeEventListeners = (settings, state, signal) => {
|
|
320
|
+
if (!settings.marquee || settings.pauseOnHover === false) return;
|
|
321
|
+
settings.feed.addEventListener(
|
|
322
|
+
"mouseenter",
|
|
323
|
+
() => pauseMarquee(state, settings),
|
|
324
|
+
{ signal }
|
|
325
|
+
);
|
|
326
|
+
settings.feed.addEventListener(
|
|
327
|
+
"mouseleave",
|
|
328
|
+
() => resumeMarquee(state, settings),
|
|
329
|
+
{ signal }
|
|
330
|
+
);
|
|
331
|
+
settings.feed.addEventListener(
|
|
332
|
+
"touchstart",
|
|
333
|
+
() => pauseMarquee(state, settings),
|
|
334
|
+
{ passive: true, signal }
|
|
335
|
+
);
|
|
336
|
+
settings.feed.addEventListener(
|
|
337
|
+
"touchend",
|
|
338
|
+
() => resumeMarquee(state, settings),
|
|
339
|
+
{ signal }
|
|
340
|
+
);
|
|
341
|
+
};
|
|
342
|
+
|
|
237
343
|
// src/core/slider.ts
|
|
238
344
|
var ANIMATION = {
|
|
239
345
|
MIN_DURATION: 400,
|
|
@@ -260,7 +366,10 @@ var createSlider = (settings) => {
|
|
|
260
366
|
scrollEndTimeout: null,
|
|
261
367
|
abortController: new AbortController(),
|
|
262
368
|
autoplayIntervalId: null,
|
|
263
|
-
autoplayPaused: false
|
|
369
|
+
autoplayPaused: false,
|
|
370
|
+
marqueeAnimationId: null,
|
|
371
|
+
marqueePaused: false,
|
|
372
|
+
marqueeLastTimestamp: 0
|
|
264
373
|
};
|
|
265
374
|
let dragState = null;
|
|
266
375
|
const loopState = {
|
|
@@ -269,6 +378,7 @@ var createSlider = (settings) => {
|
|
|
269
378
|
realSlides: [...settings.slides],
|
|
270
379
|
clonesPerSide: 0
|
|
271
380
|
};
|
|
381
|
+
const marqueeState = createMarqueeState();
|
|
272
382
|
const easing = settings.easing ?? easeOutExpo;
|
|
273
383
|
const getFeedRect = () => {
|
|
274
384
|
const currentWidth = settings.feed.clientWidth;
|
|
@@ -617,6 +727,7 @@ var createSlider = (settings) => {
|
|
|
617
727
|
{ signal }
|
|
618
728
|
);
|
|
619
729
|
}
|
|
730
|
+
attachMarqueeEventListeners(settings, state, signal);
|
|
620
731
|
};
|
|
621
732
|
const startAutoplay = () => {
|
|
622
733
|
if (state.autoplayIntervalId) return;
|
|
@@ -653,9 +764,13 @@ var createSlider = (settings) => {
|
|
|
653
764
|
applySlideWidths();
|
|
654
765
|
updateScrollbar();
|
|
655
766
|
updateControlsVisibility();
|
|
767
|
+
if (settings.marquee && !state.marqueePaused) {
|
|
768
|
+
startMarquee(settings, state);
|
|
769
|
+
}
|
|
656
770
|
};
|
|
657
771
|
const unload = () => {
|
|
658
772
|
stopAutoplay();
|
|
773
|
+
stopMarquee(state, settings);
|
|
659
774
|
state.abortController.abort();
|
|
660
775
|
window.removeEventListener("resize", handleWindowResize);
|
|
661
776
|
if (state.updateThumbTimeout) {
|
|
@@ -668,23 +783,46 @@ var createSlider = (settings) => {
|
|
|
668
783
|
cleanupDrag(dragState);
|
|
669
784
|
}
|
|
670
785
|
cleanupLoopClones();
|
|
786
|
+
cleanupMarqueeClones(marqueeState);
|
|
671
787
|
state.cachedFeedRect = null;
|
|
672
788
|
};
|
|
673
789
|
initAria(settings);
|
|
674
790
|
applySlideWidths();
|
|
675
|
-
|
|
791
|
+
if (settings.marquee) {
|
|
792
|
+
setupMarquee(settings, state, marqueeState);
|
|
793
|
+
} else {
|
|
794
|
+
setupLoopClones();
|
|
795
|
+
if (settings.autoplay) {
|
|
796
|
+
startAutoplay();
|
|
797
|
+
}
|
|
798
|
+
}
|
|
676
799
|
updateControlsVisibility();
|
|
677
800
|
attachEventListeners();
|
|
678
801
|
updateScrollbar();
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
802
|
+
const play = () => {
|
|
803
|
+
if (settings.marquee) {
|
|
804
|
+
if (state.marqueePaused) {
|
|
805
|
+
resumeMarquee(state, settings);
|
|
806
|
+
} else {
|
|
807
|
+
startMarquee(settings, state);
|
|
808
|
+
}
|
|
809
|
+
} else if (settings.autoplay) {
|
|
810
|
+
startAutoplay();
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
const pause = () => {
|
|
814
|
+
if (settings.marquee) {
|
|
815
|
+
pauseMarquee(state, settings);
|
|
816
|
+
} else {
|
|
817
|
+
stopAutoplay();
|
|
818
|
+
}
|
|
819
|
+
};
|
|
682
820
|
return {
|
|
683
821
|
goToIndex,
|
|
684
822
|
refresh,
|
|
685
823
|
unload,
|
|
686
|
-
play
|
|
687
|
-
pause
|
|
824
|
+
play,
|
|
825
|
+
pause,
|
|
688
826
|
next: () => handleNavButtonClick("next"),
|
|
689
827
|
prev: () => handleNavButtonClick("prev")
|
|
690
828
|
};
|
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/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 {\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'\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 }\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 // 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\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\n /**\n * Clean up all event listeners and timers\n */\n const unload = (): void => {\n // Stop autoplay\n stopAutoplay()\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\n cleanupLoopClones()\n\n // Reset cached rect\n state.cachedFeedRect = null\n }\n\n // Initialize slider\n initAria(settings)\n applySlideWidths()\n setupLoopClones()\n updateControlsVisibility()\n attachEventListeners()\n updateScrollbar()\n\n // Start autoplay if enabled\n if (settings.autoplay) {\n startAutoplay()\n }\n\n return {\n goToIndex,\n refresh,\n unload,\n play: startAutoplay,\n pause: stopAutoplay,\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/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 from {\n transform: translateX(0);\n }\n to {\n transform: translateX(calc(-1 * var(--lazer-marquee-distance) * 1px));\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 const scrollWidth = settings.feed.scrollWidth\n const speed = settings.marqueeSpeed ?? 50 // pixels per second\n const direction = settings.marqueeDirection ?? 'left'\n const distance = scrollWidth / 2\n\n // Set CSS custom property for the exact pixel distance\n settings.feed.style.setProperty('--lazer-marquee-distance', String(distance))\n\n // Calculate duration: distance / speed\n const duration = distance / speed\n const animationDirection = direction === 'right' ? 'reverse' : 'normal'\n\n // Apply smooth CSS animation with hardware acceleration\n settings.feed.style.animation = `lazer-marquee-scroll ${duration}s linear infinite ${animationDirection}`\n settings.feed.style.animationPlayState = state.marqueePaused ? 'paused' : 'running'\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 and CSS custom property\n settings.feed.style.transform = ''\n settings.feed.style.willChange = ''\n settings.feed.style.removeProperty('--lazer-marquee-distance')\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":[]}
|
package/package.json
CHANGED