lazer-slider 1.0.2 → 1.0.4
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 +457 -0
- package/dist/index.cjs +613 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +166 -2
- package/dist/index.d.ts +166 -2
- package/dist/index.js +606 -5
- package/dist/index.js.map +1 -1
- package/package.json +26 -6
package/README.md
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
# Lazer Slider
|
|
2
|
+
|
|
3
|
+
A lightweight, accessible slider with smooth scroll-to-snap animations, drag-to-scroll support, and full keyboard navigation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Smooth Animations** - Buttery smooth scroll animations using `requestAnimationFrame` with customizable easing
|
|
8
|
+
- **Drag to Scroll** - Mouse and touch drag support with momentum physics
|
|
9
|
+
- **Responsive** - Separate settings for mobile and desktop (slidesPerView, slidesPerScroll)
|
|
10
|
+
- **Loop Mode** - Infinite loop navigation
|
|
11
|
+
- **Autoplay** - Automatic slide advancement with pause on hover
|
|
12
|
+
- **Accessible** - Full ARIA support, keyboard navigation (arrow keys)
|
|
13
|
+
- **Lightweight** - Zero dependencies, ~20KB unminified
|
|
14
|
+
- **TypeScript** - Full type definitions included
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install lazer-slider
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### HTML Structure
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<div class="slider">
|
|
28
|
+
<button class="slider-prev">Previous</button>
|
|
29
|
+
<button class="slider-next">Next</button>
|
|
30
|
+
|
|
31
|
+
<div class="slider-feed">
|
|
32
|
+
<div class="slide">Slide 1</div>
|
|
33
|
+
<div class="slide">Slide 2</div>
|
|
34
|
+
<div class="slide">Slide 3</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="slider-dots">
|
|
38
|
+
<button class="dot"></button>
|
|
39
|
+
<button class="dot"></button>
|
|
40
|
+
<button class="dot"></button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### CSS (Required)
|
|
46
|
+
|
|
47
|
+
```css
|
|
48
|
+
.slider-feed {
|
|
49
|
+
display: flex;
|
|
50
|
+
overflow-x: auto;
|
|
51
|
+
scroll-snap-type: x mandatory;
|
|
52
|
+
-webkit-overflow-scrolling: touch;
|
|
53
|
+
scrollbar-width: none; /* Firefox */
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.slider-feed::-webkit-scrollbar {
|
|
57
|
+
display: none; /* Chrome, Safari */
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.slide {
|
|
61
|
+
scroll-snap-align: start;
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### JavaScript
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { createSlider } from 'lazer-slider'
|
|
70
|
+
|
|
71
|
+
const slider = createSlider({
|
|
72
|
+
feed: document.querySelector('.slider-feed'),
|
|
73
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
74
|
+
prevSlideButton: document.querySelector('.slider-prev'),
|
|
75
|
+
nextSlideButton: document.querySelector('.slider-next'),
|
|
76
|
+
thumbs: [...document.querySelectorAll('.dot')],
|
|
77
|
+
enableDragToScroll: true
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Cleanup when done
|
|
81
|
+
slider.unload()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Configuration Options
|
|
85
|
+
|
|
86
|
+
### Required
|
|
87
|
+
|
|
88
|
+
| Option | Type | Description |
|
|
89
|
+
|--------|------|-------------|
|
|
90
|
+
| `feed` | `HTMLElement` | Container element that holds the slides (scrollable) |
|
|
91
|
+
| `slides` | `HTMLElement[]` | Array of slide elements |
|
|
92
|
+
|
|
93
|
+
### Navigation
|
|
94
|
+
|
|
95
|
+
| Option | Type | Default | Description |
|
|
96
|
+
|--------|------|---------|-------------|
|
|
97
|
+
| `prevSlideButton` | `HTMLElement \| null` | `null` | Previous slide button |
|
|
98
|
+
| `nextSlideButton` | `HTMLElement \| null` | `null` | Next slide button |
|
|
99
|
+
| `thumbs` | `HTMLElement[]` | `undefined` | Thumbnail/dot elements for direct navigation |
|
|
100
|
+
|
|
101
|
+
### Responsive
|
|
102
|
+
|
|
103
|
+
| Option | Type | Default | Description |
|
|
104
|
+
|--------|------|---------|-------------|
|
|
105
|
+
| `mobileSlidesPerView` | `number \| 'auto'` | `undefined` | Slides visible at once on mobile |
|
|
106
|
+
| `desktopSlidesPerView` | `number \| 'auto'` | `undefined` | Slides visible at once on desktop |
|
|
107
|
+
| `mobileSlidesPerScroll` | `number` | `1` | Slides to scroll per nav click on mobile |
|
|
108
|
+
| `desktopSlidesPerScroll` | `number` | `1` | Slides to scroll per nav click on desktop |
|
|
109
|
+
| `slideGap` | `number` | `0` | Gap between slides in pixels |
|
|
110
|
+
|
|
111
|
+
> **Note:** Desktop breakpoint is `min-width: 64rem` (1024px)
|
|
112
|
+
|
|
113
|
+
> **Tip:** Use `'auto'` for `slidesPerView` when slides have different/natural widths defined in CSS.
|
|
114
|
+
|
|
115
|
+
### Behavior
|
|
116
|
+
|
|
117
|
+
| Option | Type | Default | Description |
|
|
118
|
+
|--------|------|---------|-------------|
|
|
119
|
+
| `enableDragToScroll` | `boolean` | `false` | Enable mouse/touch drag to scroll |
|
|
120
|
+
| `loop` | `boolean` | `false` | Enable infinite loop navigation |
|
|
121
|
+
| `autoplay` | `boolean` | `false` | Enable automatic slide advancement |
|
|
122
|
+
| `autoplayInterval` | `number` | `3000` | Autoplay interval in milliseconds |
|
|
123
|
+
| `pauseOnHover` | `boolean` | `true` | Pause autoplay on hover/touch |
|
|
124
|
+
| `easing` | `EasingFunction` | `easeOutExpo` | Custom easing function |
|
|
125
|
+
|
|
126
|
+
### Scrollbar (Optional)
|
|
127
|
+
|
|
128
|
+
| Option | Type | Default | Description |
|
|
129
|
+
|--------|------|---------|-------------|
|
|
130
|
+
| `scrollbarThumb` | `HTMLElement \| null` | `null` | Custom scrollbar thumb element |
|
|
131
|
+
| `scrollbarTrack` | `HTMLElement \| null` | `null` | Custom scrollbar track element |
|
|
132
|
+
|
|
133
|
+
### Callbacks
|
|
134
|
+
|
|
135
|
+
| Option | Type | Description |
|
|
136
|
+
|--------|------|-------------|
|
|
137
|
+
| `onScrollStart` | `(params) => void` | Fired when scroll animation starts |
|
|
138
|
+
| `onScroll` | `(params) => void` | Fired during scroll |
|
|
139
|
+
| `onScrollEnd` | `(params) => void` | Fired when scroll animation ends |
|
|
140
|
+
|
|
141
|
+
#### Callback Parameters
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// onScrollStart
|
|
145
|
+
{
|
|
146
|
+
currentScroll: number // Current scroll position in pixels
|
|
147
|
+
target: HTMLElement // Target slide element
|
|
148
|
+
direction: 'prev' | 'next'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// onScroll, onScrollEnd
|
|
152
|
+
{
|
|
153
|
+
currentScroll: number // Current scroll position in pixels
|
|
154
|
+
currentSlideIndex: number // Index of the current slide
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## API Methods
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const slider = createSlider({ /* options */ })
|
|
162
|
+
|
|
163
|
+
// Navigate to specific slide (0-indexed)
|
|
164
|
+
slider.goToIndex(2)
|
|
165
|
+
|
|
166
|
+
// Navigate prev/next (respects loop setting)
|
|
167
|
+
slider.next()
|
|
168
|
+
slider.prev()
|
|
169
|
+
|
|
170
|
+
// Autoplay control
|
|
171
|
+
slider.play() // Start autoplay
|
|
172
|
+
slider.pause() // Stop autoplay
|
|
173
|
+
|
|
174
|
+
// Recalculate dimensions (call after DOM changes)
|
|
175
|
+
slider.refresh()
|
|
176
|
+
|
|
177
|
+
// Cleanup all event listeners
|
|
178
|
+
slider.unload()
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Easing Functions
|
|
182
|
+
|
|
183
|
+
Built-in easing functions for smooth animations:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import {
|
|
187
|
+
createSlider,
|
|
188
|
+
easeOutExpo, // Default - smooth deceleration
|
|
189
|
+
easeOutCubic, // Gentler deceleration
|
|
190
|
+
easeInOutCubic, // Smooth acceleration & deceleration
|
|
191
|
+
easeOutQuad, // Gentle deceleration
|
|
192
|
+
linear // Constant speed
|
|
193
|
+
} from 'lazer-slider'
|
|
194
|
+
|
|
195
|
+
const slider = createSlider({
|
|
196
|
+
// ... options
|
|
197
|
+
easing: easeOutCubic
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Custom Easing
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// Custom easing function (t goes from 0 to 1)
|
|
205
|
+
const customEase = (t: number) => t * t * t
|
|
206
|
+
|
|
207
|
+
const slider = createSlider({
|
|
208
|
+
// ... options
|
|
209
|
+
easing: customEase
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Examples
|
|
214
|
+
|
|
215
|
+
### Basic Slider
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
const slider = createSlider({
|
|
219
|
+
feed: document.querySelector('.slider-feed'),
|
|
220
|
+
slides: [...document.querySelectorAll('.slide')]
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### With Navigation Buttons
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
const slider = createSlider({
|
|
228
|
+
feed: document.querySelector('.slider-feed'),
|
|
229
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
230
|
+
prevSlideButton: document.querySelector('.prev'),
|
|
231
|
+
nextSlideButton: document.querySelector('.next')
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Responsive Multi-Slide
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
const slider = createSlider({
|
|
239
|
+
feed: document.querySelector('.slider-feed'),
|
|
240
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
241
|
+
mobileSlidesPerView: 1,
|
|
242
|
+
desktopSlidesPerView: 3,
|
|
243
|
+
slideGap: 16,
|
|
244
|
+
mobileSlidesPerScroll: 1,
|
|
245
|
+
desktopSlidesPerScroll: 3
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Autoplay Carousel
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
const slider = createSlider({
|
|
253
|
+
feed: document.querySelector('.slider-feed'),
|
|
254
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
255
|
+
loop: true,
|
|
256
|
+
autoplay: true,
|
|
257
|
+
autoplayInterval: 5000,
|
|
258
|
+
pauseOnHover: true
|
|
259
|
+
})
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Bullets/Dots Navigation
|
|
263
|
+
|
|
264
|
+
Use the `thumbs` option to add clickable dots that navigate to specific slides. The slider automatically manages the `active` class.
|
|
265
|
+
|
|
266
|
+
```html
|
|
267
|
+
<div class="slider">
|
|
268
|
+
<div class="slider-feed">
|
|
269
|
+
<div class="slide">Slide 1</div>
|
|
270
|
+
<div class="slide">Slide 2</div>
|
|
271
|
+
<div class="slide">Slide 3</div>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<div class="slider-dots">
|
|
275
|
+
<button class="dot" aria-label="Go to slide 1"></button>
|
|
276
|
+
<button class="dot" aria-label="Go to slide 2"></button>
|
|
277
|
+
<button class="dot" aria-label="Go to slide 3"></button>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
```css
|
|
283
|
+
.slider-dots {
|
|
284
|
+
display: flex;
|
|
285
|
+
gap: 8px;
|
|
286
|
+
justify-content: center;
|
|
287
|
+
margin-top: 16px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.dot {
|
|
291
|
+
width: 12px;
|
|
292
|
+
height: 12px;
|
|
293
|
+
border-radius: 50%;
|
|
294
|
+
border: none;
|
|
295
|
+
background: #ccc;
|
|
296
|
+
cursor: pointer;
|
|
297
|
+
transition: background 0.3s;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.dot.active {
|
|
301
|
+
background: #333;
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
const slider = createSlider({
|
|
307
|
+
feed: document.querySelector('.slider-feed'),
|
|
308
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
309
|
+
thumbs: [...document.querySelectorAll('.dot')]
|
|
310
|
+
})
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Custom Scrollbar
|
|
314
|
+
|
|
315
|
+
Create a draggable scrollbar that syncs with the slider position.
|
|
316
|
+
|
|
317
|
+
```html
|
|
318
|
+
<div class="slider">
|
|
319
|
+
<div class="slider-feed">
|
|
320
|
+
<div class="slide">Slide 1</div>
|
|
321
|
+
<div class="slide">Slide 2</div>
|
|
322
|
+
<div class="slide">Slide 3</div>
|
|
323
|
+
</div>
|
|
324
|
+
|
|
325
|
+
<div class="scrollbar-track">
|
|
326
|
+
<div class="scrollbar-thumb"></div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
```css
|
|
332
|
+
.scrollbar-track {
|
|
333
|
+
width: 100%;
|
|
334
|
+
height: 4px;
|
|
335
|
+
background: #eee;
|
|
336
|
+
border-radius: 2px;
|
|
337
|
+
margin-top: 16px;
|
|
338
|
+
position: relative;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.scrollbar-thumb {
|
|
342
|
+
height: 100%;
|
|
343
|
+
background: #333;
|
|
344
|
+
border-radius: 2px;
|
|
345
|
+
/* Width is set automatically by the slider */
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
const slider = createSlider({
|
|
351
|
+
feed: document.querySelector('.slider-feed'),
|
|
352
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
353
|
+
scrollbarThumb: document.querySelector('.scrollbar-thumb'),
|
|
354
|
+
scrollbarTrack: document.querySelector('.scrollbar-track')
|
|
355
|
+
})
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The slider automatically:
|
|
359
|
+
- Sets the thumb width based on visible content ratio
|
|
360
|
+
- Updates thumb position on scroll
|
|
361
|
+
- Hides the scrollbar when all content is visible
|
|
362
|
+
|
|
363
|
+
### Auto Width Slides
|
|
364
|
+
|
|
365
|
+
Use `slidesPerView: 'auto'` when slides have different natural widths defined in CSS.
|
|
366
|
+
|
|
367
|
+
```html
|
|
368
|
+
<div class="slider-feed">
|
|
369
|
+
<div class="slide slide--small">Small</div>
|
|
370
|
+
<div class="slide slide--medium">Medium</div>
|
|
371
|
+
<div class="slide slide--large">Large content here</div>
|
|
372
|
+
</div>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```css
|
|
376
|
+
.slide--small { width: 150px; }
|
|
377
|
+
.slide--medium { width: 250px; }
|
|
378
|
+
.slide--large { width: 400px; }
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
const slider = createSlider({
|
|
383
|
+
feed: document.querySelector('.slider-feed'),
|
|
384
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
385
|
+
mobileSlidesPerView: 'auto',
|
|
386
|
+
desktopSlidesPerView: 'auto',
|
|
387
|
+
slideGap: 16,
|
|
388
|
+
enableDragToScroll: true
|
|
389
|
+
})
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Full Featured
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
const slider = createSlider({
|
|
396
|
+
feed: document.querySelector('.slider-feed'),
|
|
397
|
+
slides: [...document.querySelectorAll('.slide')],
|
|
398
|
+
prevSlideButton: document.querySelector('.prev'),
|
|
399
|
+
nextSlideButton: document.querySelector('.next'),
|
|
400
|
+
thumbs: [...document.querySelectorAll('.dot')],
|
|
401
|
+
|
|
402
|
+
// Responsive
|
|
403
|
+
mobileSlidesPerView: 1,
|
|
404
|
+
desktopSlidesPerView: 3,
|
|
405
|
+
slideGap: 20,
|
|
406
|
+
|
|
407
|
+
// Behavior
|
|
408
|
+
enableDragToScroll: true,
|
|
409
|
+
loop: true,
|
|
410
|
+
autoplay: true,
|
|
411
|
+
autoplayInterval: 4000,
|
|
412
|
+
|
|
413
|
+
// Callbacks
|
|
414
|
+
onScrollEnd: ({ currentSlideIndex }) => {
|
|
415
|
+
console.log('Now viewing slide:', currentSlideIndex)
|
|
416
|
+
}
|
|
417
|
+
})
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Accessibility
|
|
421
|
+
|
|
422
|
+
The slider automatically adds ARIA attributes for accessibility:
|
|
423
|
+
|
|
424
|
+
- `role="region"` and `aria-roledescription="carousel"` on the feed
|
|
425
|
+
- `role="group"` and `aria-label="Slide X of Y"` on each slide
|
|
426
|
+
- `aria-controls` linking buttons to the feed
|
|
427
|
+
- `aria-hidden` and `tabindex` management for visibility
|
|
428
|
+
- Keyboard navigation with arrow keys when feed is focused
|
|
429
|
+
|
|
430
|
+
## TypeScript
|
|
431
|
+
|
|
432
|
+
Full TypeScript support with exported types:
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
import {
|
|
436
|
+
createSlider,
|
|
437
|
+
type SliderSettings,
|
|
438
|
+
type Slider,
|
|
439
|
+
type EasingFunction,
|
|
440
|
+
type ScrollParams,
|
|
441
|
+
type ScrollStartParams,
|
|
442
|
+
type SliderDirection
|
|
443
|
+
} from 'lazer-slider'
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Browser Support
|
|
447
|
+
|
|
448
|
+
- Chrome (latest)
|
|
449
|
+
- Firefox (latest)
|
|
450
|
+
- Safari (latest)
|
|
451
|
+
- Edge (latest)
|
|
452
|
+
|
|
453
|
+
Requires `scroll-snap-type` CSS support for snap behavior.
|
|
454
|
+
|
|
455
|
+
## License
|
|
456
|
+
|
|
457
|
+
UNLICENSED
|