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 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