use-snap-slider 0.0.3 → 0.0.5
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 +200 -1
- package/dist/lib/snap-slider.d.ts +1 -1
- package/dist/lib/throttle.d.ts +1 -1
- package/dist/lib/use-snap-slider.d.ts +2 -2
- package/dist/snap-slider.cjs.js +2 -241
- package/dist/snap-slider.cjs.js.map +1 -0
- package/dist/snap-slider.es.js +125 -210
- package/dist/snap-slider.es.js.map +1 -0
- package/dist/use-snap-slider.cjs.js +2 -45
- package/dist/use-snap-slider.cjs.js.map +1 -0
- package/dist/use-snap-slider.es.js +25 -37
- package/dist/use-snap-slider.es.js.map +1 -0
- package/package.json +18 -4
package/README.md
CHANGED
|
@@ -1,3 +1,202 @@
|
|
|
1
1
|
# use-snap-slider
|
|
2
2
|
|
|
3
|
-
React hook to manage
|
|
3
|
+
React hook / Vanilla JS to manage scroll-state for [CSS Scroll Snap](https://caniuse.com/?search=scroll-snap)
|
|
4
|
+
|
|
5
|
+
Gives you states and actions for CSS Scroll Snap sliders:
|
|
6
|
+
|
|
7
|
+
* `count:number` - total pages
|
|
8
|
+
* `countDelta:number` - total slides, for 1/1 width slides the same as count
|
|
9
|
+
* `index:number` - current page index
|
|
10
|
+
* `indexDelto:number` - current slide index, for 1/1 width slides the same as index
|
|
11
|
+
* `prevEnabled:boolean` - can go to previous slide
|
|
12
|
+
* `nextEnabled:boolean` - can go to next slide
|
|
13
|
+
* `goPrev()` - scroll to previous slide
|
|
14
|
+
* `goNext()` - scroll to next slide
|
|
15
|
+
* `jumpTo(index:number)` - go to a spesified slide
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
`npm i use-snap-slider`
|
|
20
|
+
|
|
21
|
+
### Basic usage (react)
|
|
22
|
+
|
|
23
|
+
In your react component:
|
|
24
|
+
|
|
25
|
+
See a [more complete react-example here](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/react-example/SnapSliderReact.tsx)
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import React, { useRef } from 'react'
|
|
29
|
+
import { useSnapSlider } from 'use-snap-slider'
|
|
30
|
+
|
|
31
|
+
export function MySlider () {
|
|
32
|
+
const ref = useRef<HTMLDivElement | null>(null)
|
|
33
|
+
const slides = [1,2]
|
|
34
|
+
// Passing inital count avoid extra render, for best lighthouse score, pass the same count as you show on mobile
|
|
35
|
+
const {index, count, jumpTo, goPrev, goNext, prevEnabled, nextEnabled} = useSnapSlider(ref, slides.length)
|
|
36
|
+
const pages = Array.from(Array(count).keys())
|
|
37
|
+
return (
|
|
38
|
+
<div>
|
|
39
|
+
<div className="flex scroll-smooth snap-x snap-mandatory overflow-x-auto" ref={ref}>
|
|
40
|
+
{slides.map((slide) => (
|
|
41
|
+
<div key={slide} className="flex snap-start shrink-0 w-full md:w-1/2">
|
|
42
|
+
Slide {slide}
|
|
43
|
+
</div>
|
|
44
|
+
))}
|
|
45
|
+
</div>
|
|
46
|
+
<nav aria-label="Pages navigation">
|
|
47
|
+
{pages.map((page) => (
|
|
48
|
+
<button onClick={() => jumpTo(page)} disabled={page === index}>{page + 1}</button>
|
|
49
|
+
))}
|
|
50
|
+
</nav>
|
|
51
|
+
<nav aria-label="Prev / Next navigation">
|
|
52
|
+
<button onClick={goPrev} disabled={!prevEnabled}>Prev</button>
|
|
53
|
+
<button onClick={goNext} disabled={!nextEnabled}>Next</button>
|
|
54
|
+
</nav>
|
|
55
|
+
</div>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Basic usage (vanilla javascript)
|
|
61
|
+
|
|
62
|
+
See a [more complete vanilla javascript example here](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/vanilla-example/create-snap-slider.ts)
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { createSnapSlider } from 'use-snap-slider/dist/snap-slider'
|
|
66
|
+
|
|
67
|
+
function createSnapSliderVanilla(element: HTMLElement) {
|
|
68
|
+
const { jumpTo, goNext, goPrev, subscribe } = createSnapSlider({
|
|
69
|
+
element,
|
|
70
|
+
count: count,
|
|
71
|
+
index: 0,
|
|
72
|
+
})
|
|
73
|
+
subscribe((state) => {
|
|
74
|
+
// Update UI with sate
|
|
75
|
+
})
|
|
76
|
+
document.querySelector('.prev-btn')?.addEventListener('click', goPrev)
|
|
77
|
+
document.querySelector('.next-btn')?.addEventListener('click', goNext)
|
|
78
|
+
}
|
|
79
|
+
// Expose globally
|
|
80
|
+
window.createSnapSliderVanilla = createSnapSliderVanilla
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API
|
|
84
|
+
|
|
85
|
+
### useSnapSlider react hook
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { useSnapSlider } from 'use-snap-slider'
|
|
89
|
+
|
|
90
|
+
const {
|
|
91
|
+
index: number,
|
|
92
|
+
// If displaying multiple slides on the same page, this will be slide at left position
|
|
93
|
+
indexDelta: number,
|
|
94
|
+
// Count of pages
|
|
95
|
+
count: number,
|
|
96
|
+
countDelta: number,
|
|
97
|
+
prevEnabled: boolean,
|
|
98
|
+
nextEnabled: boolean,
|
|
99
|
+
jumpTo: (index: number) => void,
|
|
100
|
+
goNext: () => void,
|
|
101
|
+
goPrev: () => void,
|
|
102
|
+
} = useSnapSlider(
|
|
103
|
+
ref: MutableRefObject<HTMLDivElement | null>,
|
|
104
|
+
// Pass inital count
|
|
105
|
+
count?: number = 1,
|
|
106
|
+
// Pass inital index
|
|
107
|
+
index?: number = 0,
|
|
108
|
+
// onPrev / next buttons go to end / start
|
|
109
|
+
circular = false,
|
|
110
|
+
// Will reset index on change of count, but pass something here to force a reset even if count dont change
|
|
111
|
+
countHash?: string | number
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### useSnapSlider react hook
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { createSnapSlider } from 'use-snap-slider/dist/snap-slider'
|
|
119
|
+
|
|
120
|
+
const {
|
|
121
|
+
// Removes event listner for window.resize and element.scroll
|
|
122
|
+
destroy: () => void,
|
|
123
|
+
// Get current state
|
|
124
|
+
getState: () => TSnapSliderStateFull,
|
|
125
|
+
// Go to slide index
|
|
126
|
+
jumpTo: (index?: number, indexDelta?: number) => void,
|
|
127
|
+
goNext: () => void,
|
|
128
|
+
goPrev: () => void,
|
|
129
|
+
// Subscribe to updates
|
|
130
|
+
subscribe: (fn: TSnapListner) => () => void,
|
|
131
|
+
// Set element at later stage
|
|
132
|
+
setElement: (el: HTMLElement) => void,
|
|
133
|
+
// Updates count and countDelta, call if you change inner slides
|
|
134
|
+
calculate: () => void,
|
|
135
|
+
// Should subscribe return a inital publish after subscribing
|
|
136
|
+
initalSubscriptionPublish: boolean = true
|
|
137
|
+
} = createSnapSlider({
|
|
138
|
+
element: HTMLDivElement | null,
|
|
139
|
+
count?:number = 1,
|
|
140
|
+
countDelta?:number,
|
|
141
|
+
index?:number = 0,
|
|
142
|
+
circular?:boolean,
|
|
143
|
+
indexDelta?:number,
|
|
144
|
+
itemSelector?:string = ':scope > *',
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Adding nessesary styles
|
|
149
|
+
|
|
150
|
+
This library only delivers javascript for handle the state, you will need to make your own component for complete solution. See examples in this repo:
|
|
151
|
+
|
|
152
|
+
* [React component](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/react-example/SnapSliderReact.tsx)
|
|
153
|
+
* [Vanilla JS function](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/vanilla-example/create-snap-slider.ts)
|
|
154
|
+
|
|
155
|
+
### TailwindCSS
|
|
156
|
+
|
|
157
|
+
See also tailwinds own documentation for [scroll snap](https://tailwindcss.com/docs/scroll-snap-type)
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<div class="flex scroll-smooth snap-x snap-mandatory overflow-x-auto">
|
|
161
|
+
<div class="flex snap-start shrink-0">
|
|
162
|
+
Slide 1
|
|
163
|
+
</div>
|
|
164
|
+
<div class="flex snap-start shrink-0">
|
|
165
|
+
Slide 2
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Basic css
|
|
171
|
+
|
|
172
|
+
```html
|
|
173
|
+
<style>
|
|
174
|
+
.css-slider {
|
|
175
|
+
display: flex;
|
|
176
|
+
overflow-x: auto;
|
|
177
|
+
scroll-snap-type: x mandatory;
|
|
178
|
+
scroll-behavior: smooth;
|
|
179
|
+
-webkit-overflow-scrolling: touch;
|
|
180
|
+
}
|
|
181
|
+
.css-slider::-webkit-scrollbar {
|
|
182
|
+
display: none;
|
|
183
|
+
}
|
|
184
|
+
.css-slider-item {
|
|
185
|
+
display: flex;
|
|
186
|
+
scroll-snap-align: start;
|
|
187
|
+
flex-shrink: 0;
|
|
188
|
+
}
|
|
189
|
+
.css-slider-item-half {
|
|
190
|
+
width: 50%;
|
|
191
|
+
}
|
|
192
|
+
</style>
|
|
193
|
+
<!-- Markup -->
|
|
194
|
+
<div class="css-slider">
|
|
195
|
+
<div class="css-slider-item css-slider-item-half">
|
|
196
|
+
Slide 1
|
|
197
|
+
</div>
|
|
198
|
+
<div class="css-slider-item css-slider-item-half">
|
|
199
|
+
Slide 2
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
```
|
|
@@ -26,7 +26,7 @@ export interface TSnapSliderParams extends TSnapSliderStateUpdate {
|
|
|
26
26
|
export type TSnapSliderJumpToFn = (index?: number, indexDelta?: number) => void;
|
|
27
27
|
export interface TSnapSlider {
|
|
28
28
|
destroy: () => void;
|
|
29
|
-
getState: (
|
|
29
|
+
getState: () => TSnapSliderStateFull;
|
|
30
30
|
jumpTo: TSnapSliderJumpToFn;
|
|
31
31
|
goNext: () => void;
|
|
32
32
|
goPrev: () => void;
|
package/dist/lib/throttle.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const throttle: (fn: Function, wait
|
|
1
|
+
export declare const throttle: (fn: Function, wait: number) => (this: any) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MutableRefObject } from
|
|
2
|
-
import { TSnapSliderStateFull } from
|
|
1
|
+
import { MutableRefObject } from 'react';
|
|
2
|
+
import { TSnapSliderStateFull } from './snap-slider';
|
|
3
3
|
export interface TUseSnapSlider extends TSnapSliderStateFull {
|
|
4
4
|
jumpTo: (index: number) => void;
|
|
5
5
|
goNext: () => void;
|
package/dist/snap-slider.cjs.js
CHANGED
|
@@ -1,241 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const throttle = (fn, wait = 300) => {
|
|
4
|
-
let inThrottle, lastFn, lastTime;
|
|
5
|
-
return function() {
|
|
6
|
-
const context = this, args = arguments;
|
|
7
|
-
if (!inThrottle) {
|
|
8
|
-
fn.apply(context, args);
|
|
9
|
-
lastTime = Date.now();
|
|
10
|
-
inThrottle = true;
|
|
11
|
-
} else {
|
|
12
|
-
clearTimeout(lastFn);
|
|
13
|
-
lastFn = setTimeout(() => {
|
|
14
|
-
if (Date.now() - lastTime >= wait) {
|
|
15
|
-
fn.apply(context, args);
|
|
16
|
-
lastTime = Date.now();
|
|
17
|
-
}
|
|
18
|
-
}, Math.max(wait - (Date.now() - lastTime), 0));
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
function createSnapSlider({
|
|
23
|
-
element: _element,
|
|
24
|
-
count = 1,
|
|
25
|
-
countDelta,
|
|
26
|
-
index = 0,
|
|
27
|
-
circular,
|
|
28
|
-
indexDelta,
|
|
29
|
-
initalSubscriptionPublish = true,
|
|
30
|
-
itemSelector = ":scope > *"
|
|
31
|
-
}) {
|
|
32
|
-
let initalIndex = index;
|
|
33
|
-
let state = {
|
|
34
|
-
index,
|
|
35
|
-
indexDelta: indexDelta || index,
|
|
36
|
-
count,
|
|
37
|
-
countDelta: countDelta || count
|
|
38
|
-
};
|
|
39
|
-
let prevIndexDelta = index;
|
|
40
|
-
let slidesPerPage = 1;
|
|
41
|
-
let itemPositions = [];
|
|
42
|
-
let muteScrollListner = false;
|
|
43
|
-
let left = 0;
|
|
44
|
-
let element;
|
|
45
|
-
function updateIndexDelta() {
|
|
46
|
-
if (!element) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const prev = element.scrollLeft;
|
|
50
|
-
const { indexDelta: indexDelta2 } = state;
|
|
51
|
-
left = indexDelta2 * (element.offsetWidth / slidesPerPage);
|
|
52
|
-
if (prevIndexDelta !== indexDelta2) {
|
|
53
|
-
const distance = Math.abs(prev - left);
|
|
54
|
-
const limitInstantScroll = element.offsetWidth * 2;
|
|
55
|
-
prevIndexDelta = indexDelta2;
|
|
56
|
-
muteScrollListner = true;
|
|
57
|
-
element.scroll({
|
|
58
|
-
left,
|
|
59
|
-
top: 0,
|
|
60
|
-
behavior: distance > limitInstantScroll ? "smooth" : void 0
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
if (initalIndex) {
|
|
64
|
-
muteScrollListner = true;
|
|
65
|
-
element.scroll({
|
|
66
|
-
left,
|
|
67
|
-
top: 0
|
|
68
|
-
});
|
|
69
|
-
initalIndex = void 0;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
let listeners = [];
|
|
74
|
-
const subscribe = (callback) => {
|
|
75
|
-
listeners.push(callback);
|
|
76
|
-
return () => {
|
|
77
|
-
listeners = listeners.filter((x) => x !== callback);
|
|
78
|
-
if (listeners.length < 1) {
|
|
79
|
-
destroy();
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
function notify() {
|
|
84
|
-
listeners.forEach((callback) => {
|
|
85
|
-
callback(getState());
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
const getState = () => {
|
|
89
|
-
const { indexDelta: indexDelta2, countDelta: countDelta2 } = state;
|
|
90
|
-
return {
|
|
91
|
-
...state,
|
|
92
|
-
prevEnabled: circular || indexDelta2 > 0,
|
|
93
|
-
nextEnabled: circular || countDelta2 - slidesPerPage > indexDelta2
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
let initalPublish = !initalSubscriptionPublish;
|
|
97
|
-
function update(params = {}) {
|
|
98
|
-
let dirty = false;
|
|
99
|
-
let indexDeltaDirty = false;
|
|
100
|
-
const keys = Object.keys(
|
|
101
|
-
params
|
|
102
|
-
);
|
|
103
|
-
keys.forEach((key) => {
|
|
104
|
-
if (state[key] !== params[key]) {
|
|
105
|
-
state[key] = Number(params[key]);
|
|
106
|
-
dirty = true;
|
|
107
|
-
if (key === "indexDelta") {
|
|
108
|
-
indexDeltaDirty = true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
if (dirty || !initalPublish) {
|
|
113
|
-
initalPublish = true;
|
|
114
|
-
notify();
|
|
115
|
-
if (indexDeltaDirty) {
|
|
116
|
-
updateIndexDelta();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function fixIndex(nextIndex) {
|
|
121
|
-
const { index: index2, indexDelta: indexDelta2 } = nextIndex;
|
|
122
|
-
const { countDelta: countDelta2, count: count2 } = state;
|
|
123
|
-
const last = countDelta2 - slidesPerPage;
|
|
124
|
-
return {
|
|
125
|
-
index: indexDelta2 < last ? index2 : count2 - 1,
|
|
126
|
-
indexDelta: indexDelta2
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
function calculate() {
|
|
130
|
-
if (!element) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
let contentWidth = 0;
|
|
134
|
-
let itemWidth = 0;
|
|
135
|
-
itemPositions = [];
|
|
136
|
-
element.querySelectorAll(itemSelector).forEach((slide) => {
|
|
137
|
-
itemPositions.push(contentWidth);
|
|
138
|
-
contentWidth += slide.clientWidth;
|
|
139
|
-
itemWidth = slide.clientWidth;
|
|
140
|
-
});
|
|
141
|
-
slidesPerPage = Math.round(element.offsetWidth / itemWidth);
|
|
142
|
-
const count2 = Math.ceil(contentWidth / element.offsetWidth);
|
|
143
|
-
const countDelta2 = itemPositions.length;
|
|
144
|
-
const { index: index2 } = state;
|
|
145
|
-
const resetIndexMayby = index2 + 1 > count2 ? {
|
|
146
|
-
index: 0,
|
|
147
|
-
indexDelta: 0
|
|
148
|
-
} : {};
|
|
149
|
-
update({
|
|
150
|
-
count: count2,
|
|
151
|
-
countDelta: countDelta2,
|
|
152
|
-
...resetIndexMayby
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
let ticking = false;
|
|
156
|
-
function onScroll() {
|
|
157
|
-
if (!ticking && element) {
|
|
158
|
-
const scrollLeft = element.scrollLeft;
|
|
159
|
-
window.requestAnimationFrame(() => {
|
|
160
|
-
if (muteScrollListner) {
|
|
161
|
-
const leftToScroll = Math.abs(left - scrollLeft);
|
|
162
|
-
if (leftToScroll < 1) {
|
|
163
|
-
muteScrollListner = false;
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
const positionItem = itemPositions.reduce((prev, curr) => {
|
|
167
|
-
return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
|
|
168
|
-
});
|
|
169
|
-
const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
|
|
170
|
-
prevIndexDelta = indexDelta2;
|
|
171
|
-
update(
|
|
172
|
-
fixIndex({
|
|
173
|
-
index: Math.floor(indexDelta2 / slidesPerPage),
|
|
174
|
-
indexDelta: indexDelta2
|
|
175
|
-
})
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
ticking = false;
|
|
179
|
-
});
|
|
180
|
-
ticking = true;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
const onScrollFn = throttle(onScroll, 200);
|
|
184
|
-
const onResizeFn = throttle(calculate, 200);
|
|
185
|
-
function setElement(_el) {
|
|
186
|
-
if (element) {
|
|
187
|
-
destroy();
|
|
188
|
-
}
|
|
189
|
-
element = _el;
|
|
190
|
-
updateIndexDelta();
|
|
191
|
-
calculate();
|
|
192
|
-
element == null ? void 0 : element.addEventListener("scroll", onScrollFn);
|
|
193
|
-
window.addEventListener("resize", onResizeFn);
|
|
194
|
-
}
|
|
195
|
-
_element && setElement(_element);
|
|
196
|
-
const jumpTo = function(index2, indexDelta2) {
|
|
197
|
-
if (indexDelta2 !== void 0) {
|
|
198
|
-
update(
|
|
199
|
-
fixIndex({
|
|
200
|
-
index: Math.floor(indexDelta2 / slidesPerPage),
|
|
201
|
-
indexDelta: indexDelta2
|
|
202
|
-
})
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
if (index2 !== void 0) {
|
|
206
|
-
update(
|
|
207
|
-
fixIndex({
|
|
208
|
-
index: index2,
|
|
209
|
-
indexDelta: index2 * slidesPerPage
|
|
210
|
-
})
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
const destroy = () => {
|
|
215
|
-
element == null ? void 0 : element.removeEventListener("scroll", onScrollFn);
|
|
216
|
-
window.removeEventListener("resize", onResizeFn);
|
|
217
|
-
};
|
|
218
|
-
const goNext = () => {
|
|
219
|
-
const { countDelta: countDelta2, indexDelta: indexDelta2 } = state;
|
|
220
|
-
const last = countDelta2 - slidesPerPage;
|
|
221
|
-
const next = indexDelta2 + slidesPerPage <= last ? indexDelta2 + slidesPerPage : circular && indexDelta2 === last ? 0 : last;
|
|
222
|
-
jumpTo(void 0, next);
|
|
223
|
-
};
|
|
224
|
-
const goPrev = () => {
|
|
225
|
-
const { indexDelta: indexDelta2, countDelta: countDelta2 } = state;
|
|
226
|
-
const last = countDelta2 - slidesPerPage;
|
|
227
|
-
const next = indexDelta2 - slidesPerPage >= 0 ? indexDelta2 - slidesPerPage : circular && indexDelta2 === 0 ? last : 0;
|
|
228
|
-
jumpTo(void 0, next);
|
|
229
|
-
};
|
|
230
|
-
return {
|
|
231
|
-
destroy,
|
|
232
|
-
getState,
|
|
233
|
-
subscribe,
|
|
234
|
-
jumpTo,
|
|
235
|
-
setElement,
|
|
236
|
-
calculate,
|
|
237
|
-
goNext,
|
|
238
|
-
goPrev
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
exports.createSnapSlider = createSnapSlider;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const q=(f,u)=>{let h,r,a;return function(){const v=this,p=arguments;h?(clearTimeout(r),r=setTimeout(()=>{Date.now()-a>=u&&(f.apply(v,p),a=Date.now())},Math.max(u-(Date.now()-a),0))):(f.apply(v,p),a=Date.now(),h=!0)}};function C({element:f,count:u=1,countDelta:h,index:r=0,circular:a,indexDelta:v,initalSubscriptionPublish:p=!0,itemSelector:A=":scope > *"}){let T=r,c={index:r,indexDelta:v||r,count:u,countDelta:h||u},m=r,i=1,D=[],b=!1,x=0,n;function W(){if(n){const t=n.scrollLeft,{indexDelta:e}=c;if(x=e*(n.offsetWidth/i),m!==e){const o=Math.abs(t-x),l=n.offsetWidth*2;m=e,b=!0;const s=o>l?"instant":"smooth";n.scroll({left:x,top:0,behavior:s})}else T&&(b=!0,n.scroll({left:x,top:0,behavior:"instant"}),T=void 0)}}let P=!1,d=[];const O=t=>(d.push(t),n&&(P||p)&&t(S()),()=>{d=d.filter(e=>e!==t),d.length<1&&I()});function R(){d.forEach(t=>{t(S())})}const S=()=>{const{indexDelta:t,countDelta:e}=c;return{...c,prevEnabled:a||t>0,nextEnabled:a||e-i>t}};function g(t){let e=!1,o=!1;Object.keys(t).forEach(s=>{c[s]!==t[s]&&(c[s]=Number(t[s]),e=!0,s==="indexDelta"&&(o=!0))}),e&&(P=d.length===0,R(),o&&W())}function y(t){const{index:e,indexDelta:o}=t,{countDelta:l,count:s}=c,L=l-i;return{index:o<L?e:s-1,indexDelta:o}}function M(){if(n){let t=0,e=0;D=[],n.querySelectorAll(A).forEach(N=>{D.push(t),t+=N.clientWidth,e=N.clientWidth}),i=Math.round(n.offsetWidth/e);const o=D.length,l=Math.ceil(o/i),{index:s}=c,L=s+1>l?{index:0,indexDelta:0}:{};g({count:l,countDelta:o,...L})}}let E=!1;function B(){if(!E&&n){const t=n.scrollLeft;window.requestAnimationFrame(()=>{if(b)Math.abs(x-t)<2&&(b=!1);else{const e=D.reduce((l,s)=>Math.abs(s-t)<Math.abs(l-t)?s:l),o=D.findIndex(l=>l===e);m=o,g(y({index:Math.floor(o/i),indexDelta:o}))}E=!1}),E=!0}}const F=q(B,200),j=q(M,500);function z(t){n&&I(),n=t,W(),M(),n==null||n.addEventListener("scroll",F),window.addEventListener("resize",j)}f&&z(f);const w=function(t,e){e!==void 0&&g(y({index:Math.floor(e/i),indexDelta:e})),t!==void 0&&g(y({index:t,indexDelta:t*i}))},I=()=>{n==null||n.removeEventListener("scroll",F),window.removeEventListener("resize",j)};return{destroy:I,getState:S,subscribe:O,jumpTo:w,setElement:z,calculate:M,goNext:()=>{const{countDelta:t,indexDelta:e}=c,o=t-i,l=e+i<=o?e+i:a&&e===o?0:o;w(void 0,l)},goPrev:()=>{const{indexDelta:t,countDelta:e}=c,o=e-i,l=t-i>=0?t-i:a&&t===0?o:0;w(void 0,l)}}}exports.createSnapSlider=C;
|
|
2
|
+
//# sourceMappingURL=snap-slider.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snap-slider.cjs.js","sources":["../src/lib/throttle.ts","../src/lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport interface TSnapSliderParams extends TSnapSliderStateUpdate {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n circular?: boolean\n}\n\nexport type TSnapSliderJumpToFn = (index?: number, indexDelta?: number) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n // @ts-expect-error [mildly irritated message]\n const behavior: ScrollBehavior =\n distance > limitInstantScroll ? 'instant' : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n // @ts-expect-error [mildly irritated message]\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n keys.forEach((key) => {\n if (state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n element.querySelectorAll(itemSelector).forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n update({\n count,\n countDelta,\n ...resetIndexMayby,\n })\n }\n }\n\n let ticking = false\n function onScroll() {\n if (!ticking && element) {\n const scrollLeft = element.scrollLeft\n window.requestAnimationFrame(() => {\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n prevIndexDelta = indexDelta\n update(\n fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n })\n )\n }\n ticking = false\n })\n ticking = true\n }\n }\n const onScrollFn = throttle(onScroll, 200)\n const onResizeFn = throttle(calculate, 500)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n element?.addEventListener('scroll', onScrollFn)\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (index, indexDelta) {\n if (indexDelta !== undefined) {\n update(\n fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n })\n )\n }\n if (index !== undefined) {\n update(\n fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n })\n )\n }\n }\n const destroy = () => {\n element?.removeEventListener('scroll', onScrollFn)\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["throttle","fn","wait","inThrottle","lastFn","lastTime","context","args","createSnapSlider","_element","count","countDelta","index","circular","indexDelta","initalSubscriptionPublish","itemSelector","initalIndex","state","prevIndexDelta","slidesPerPage","itemPositions","muteScrollListner","left","element","updateIndexDelta","prev","distance","limitInstantScroll","behavior","publishDirty","listeners","subscribe","callback","getState","x","destroy","notify","update","params","dirty","indexDeltaDirty","key","fixIndex","nextIndex","last","calculate","contentWidth","itemWidth","slide","resetIndexMayby","ticking","onScroll","scrollLeft","positionItem","curr","onScrollFn","onResizeFn","setElement","_el","jumpTo","next"],"mappings":"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"}
|
package/dist/snap-slider.es.js
CHANGED
|
@@ -1,241 +1,156 @@
|
|
|
1
|
-
const
|
|
2
|
-
let
|
|
1
|
+
const q = (f, u) => {
|
|
2
|
+
let h, r, c;
|
|
3
3
|
return function() {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
inThrottle = true;
|
|
9
|
-
} else {
|
|
10
|
-
clearTimeout(lastFn);
|
|
11
|
-
lastFn = setTimeout(() => {
|
|
12
|
-
if (Date.now() - lastTime >= wait) {
|
|
13
|
-
fn.apply(context, args);
|
|
14
|
-
lastTime = Date.now();
|
|
15
|
-
}
|
|
16
|
-
}, Math.max(wait - (Date.now() - lastTime), 0));
|
|
17
|
-
}
|
|
4
|
+
const v = this, p = arguments;
|
|
5
|
+
h ? (clearTimeout(r), r = setTimeout(() => {
|
|
6
|
+
Date.now() - c >= u && (f.apply(v, p), c = Date.now());
|
|
7
|
+
}, Math.max(u - (Date.now() - c), 0))) : (f.apply(v, p), c = Date.now(), h = !0);
|
|
18
8
|
};
|
|
19
9
|
};
|
|
20
|
-
function
|
|
21
|
-
element:
|
|
22
|
-
count = 1,
|
|
23
|
-
countDelta,
|
|
24
|
-
index = 0,
|
|
25
|
-
circular,
|
|
26
|
-
indexDelta,
|
|
27
|
-
initalSubscriptionPublish =
|
|
28
|
-
itemSelector = ":scope > *"
|
|
10
|
+
function H({
|
|
11
|
+
element: f,
|
|
12
|
+
count: u = 1,
|
|
13
|
+
countDelta: h,
|
|
14
|
+
index: r = 0,
|
|
15
|
+
circular: c,
|
|
16
|
+
indexDelta: v,
|
|
17
|
+
initalSubscriptionPublish: p = !0,
|
|
18
|
+
itemSelector: A = ":scope > *"
|
|
29
19
|
}) {
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const prev = element.scrollLeft;
|
|
48
|
-
const { indexDelta: indexDelta2 } = state;
|
|
49
|
-
left = indexDelta2 * (element.offsetWidth / slidesPerPage);
|
|
50
|
-
if (prevIndexDelta !== indexDelta2) {
|
|
51
|
-
const distance = Math.abs(prev - left);
|
|
52
|
-
const limitInstantScroll = element.offsetWidth * 2;
|
|
53
|
-
prevIndexDelta = indexDelta2;
|
|
54
|
-
muteScrollListner = true;
|
|
55
|
-
element.scroll({
|
|
56
|
-
left,
|
|
57
|
-
top: 0,
|
|
58
|
-
behavior: distance > limitInstantScroll ? "smooth" : void 0
|
|
59
|
-
});
|
|
60
|
-
} else {
|
|
61
|
-
if (initalIndex) {
|
|
62
|
-
muteScrollListner = true;
|
|
63
|
-
element.scroll({
|
|
64
|
-
left,
|
|
65
|
-
top: 0
|
|
20
|
+
let T = r, a = {
|
|
21
|
+
index: r,
|
|
22
|
+
indexDelta: v || r,
|
|
23
|
+
count: u,
|
|
24
|
+
countDelta: h || u
|
|
25
|
+
}, g = r, i = 1, x = [], m = !1, D = 0, n;
|
|
26
|
+
function W() {
|
|
27
|
+
if (n) {
|
|
28
|
+
const t = n.scrollLeft, { indexDelta: e } = a;
|
|
29
|
+
if (D = e * (n.offsetWidth / i), g !== e) {
|
|
30
|
+
const o = Math.abs(t - D), l = n.offsetWidth * 2;
|
|
31
|
+
g = e, m = !0;
|
|
32
|
+
const s = o > l ? "instant" : "smooth";
|
|
33
|
+
n.scroll({
|
|
34
|
+
left: D,
|
|
35
|
+
top: 0,
|
|
36
|
+
behavior: s
|
|
66
37
|
});
|
|
67
|
-
|
|
68
|
-
|
|
38
|
+
} else
|
|
39
|
+
T && (m = !0, n.scroll({
|
|
40
|
+
left: D,
|
|
41
|
+
top: 0,
|
|
42
|
+
// @ts-expect-error [mildly irritated message]
|
|
43
|
+
behavior: "instant"
|
|
44
|
+
}), T = void 0);
|
|
69
45
|
}
|
|
70
46
|
}
|
|
71
|
-
let
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
function notify() {
|
|
82
|
-
listeners.forEach((callback) => {
|
|
83
|
-
callback(getState());
|
|
47
|
+
let P = !1, d = [];
|
|
48
|
+
const O = (t) => (d.push(t), n && (P || p) && t(E()), () => {
|
|
49
|
+
d = d.filter((e) => e !== t), d.length < 1 && I();
|
|
50
|
+
});
|
|
51
|
+
function R() {
|
|
52
|
+
d.forEach((t) => {
|
|
53
|
+
t(E());
|
|
84
54
|
});
|
|
85
55
|
}
|
|
86
|
-
const
|
|
87
|
-
const { indexDelta:
|
|
56
|
+
const E = () => {
|
|
57
|
+
const { indexDelta: t, countDelta: e } = a;
|
|
88
58
|
return {
|
|
89
|
-
...
|
|
90
|
-
prevEnabled:
|
|
91
|
-
nextEnabled:
|
|
59
|
+
...a,
|
|
60
|
+
prevEnabled: c || t > 0,
|
|
61
|
+
nextEnabled: c || e - i > t
|
|
92
62
|
};
|
|
93
63
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
);
|
|
101
|
-
keys.forEach((key) => {
|
|
102
|
-
if (state[key] !== params[key]) {
|
|
103
|
-
state[key] = Number(params[key]);
|
|
104
|
-
dirty = true;
|
|
105
|
-
if (key === "indexDelta") {
|
|
106
|
-
indexDeltaDirty = true;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
if (dirty || !initalPublish) {
|
|
111
|
-
initalPublish = true;
|
|
112
|
-
notify();
|
|
113
|
-
if (indexDeltaDirty) {
|
|
114
|
-
updateIndexDelta();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
64
|
+
function b(t) {
|
|
65
|
+
let e = !1, o = !1;
|
|
66
|
+
Object.keys(
|
|
67
|
+
t
|
|
68
|
+
).forEach((s) => {
|
|
69
|
+
a[s] !== t[s] && (a[s] = Number(t[s]), e = !0, s === "indexDelta" && (o = !0));
|
|
70
|
+
}), e && (P = d.length === 0, R(), o && W());
|
|
117
71
|
}
|
|
118
|
-
function
|
|
119
|
-
const { index:
|
|
120
|
-
const { countDelta: countDelta2, count: count2 } = state;
|
|
121
|
-
const last = countDelta2 - slidesPerPage;
|
|
72
|
+
function M(t) {
|
|
73
|
+
const { index: e, indexDelta: o } = t, { countDelta: l, count: s } = a, L = l - i;
|
|
122
74
|
return {
|
|
123
|
-
index:
|
|
124
|
-
indexDelta:
|
|
75
|
+
index: o < L ? e : s - 1,
|
|
76
|
+
indexDelta: o
|
|
125
77
|
};
|
|
126
78
|
}
|
|
127
|
-
function
|
|
128
|
-
if (
|
|
129
|
-
|
|
79
|
+
function S() {
|
|
80
|
+
if (n) {
|
|
81
|
+
let t = 0, e = 0;
|
|
82
|
+
x = [], n.querySelectorAll(A).forEach((j) => {
|
|
83
|
+
x.push(t), t += j.clientWidth, e = j.clientWidth;
|
|
84
|
+
}), i = Math.round(n.offsetWidth / e);
|
|
85
|
+
const o = x.length, l = Math.ceil(o / i), { index: s } = a, L = s + 1 > l ? {
|
|
86
|
+
index: 0,
|
|
87
|
+
indexDelta: 0
|
|
88
|
+
} : {};
|
|
89
|
+
b({
|
|
90
|
+
count: l,
|
|
91
|
+
countDelta: o,
|
|
92
|
+
...L
|
|
93
|
+
});
|
|
130
94
|
}
|
|
131
|
-
let contentWidth = 0;
|
|
132
|
-
let itemWidth = 0;
|
|
133
|
-
itemPositions = [];
|
|
134
|
-
element.querySelectorAll(itemSelector).forEach((slide) => {
|
|
135
|
-
itemPositions.push(contentWidth);
|
|
136
|
-
contentWidth += slide.clientWidth;
|
|
137
|
-
itemWidth = slide.clientWidth;
|
|
138
|
-
});
|
|
139
|
-
slidesPerPage = Math.round(element.offsetWidth / itemWidth);
|
|
140
|
-
const count2 = Math.ceil(contentWidth / element.offsetWidth);
|
|
141
|
-
const countDelta2 = itemPositions.length;
|
|
142
|
-
const { index: index2 } = state;
|
|
143
|
-
const resetIndexMayby = index2 + 1 > count2 ? {
|
|
144
|
-
index: 0,
|
|
145
|
-
indexDelta: 0
|
|
146
|
-
} : {};
|
|
147
|
-
update({
|
|
148
|
-
count: count2,
|
|
149
|
-
countDelta: countDelta2,
|
|
150
|
-
...resetIndexMayby
|
|
151
|
-
});
|
|
152
95
|
}
|
|
153
|
-
let
|
|
154
|
-
function
|
|
155
|
-
if (!
|
|
156
|
-
const
|
|
96
|
+
let w = !1;
|
|
97
|
+
function B() {
|
|
98
|
+
if (!w && n) {
|
|
99
|
+
const t = n.scrollLeft;
|
|
157
100
|
window.requestAnimationFrame(() => {
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
167
|
-
const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
|
|
168
|
-
prevIndexDelta = indexDelta2;
|
|
169
|
-
update(
|
|
170
|
-
fixIndex({
|
|
171
|
-
index: Math.floor(indexDelta2 / slidesPerPage),
|
|
172
|
-
indexDelta: indexDelta2
|
|
101
|
+
if (m)
|
|
102
|
+
Math.abs(D - t) < 2 && (m = !1);
|
|
103
|
+
else {
|
|
104
|
+
const e = x.reduce((l, s) => Math.abs(s - t) < Math.abs(l - t) ? s : l), o = x.findIndex((l) => l === e);
|
|
105
|
+
g = o, b(
|
|
106
|
+
M({
|
|
107
|
+
index: Math.floor(o / i),
|
|
108
|
+
indexDelta: o
|
|
173
109
|
})
|
|
174
110
|
);
|
|
175
111
|
}
|
|
176
|
-
|
|
177
|
-
});
|
|
178
|
-
ticking = true;
|
|
112
|
+
w = !1;
|
|
113
|
+
}), w = !0;
|
|
179
114
|
}
|
|
180
115
|
}
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (element) {
|
|
185
|
-
destroy();
|
|
186
|
-
}
|
|
187
|
-
element = _el;
|
|
188
|
-
updateIndexDelta();
|
|
189
|
-
calculate();
|
|
190
|
-
element == null ? void 0 : element.addEventListener("scroll", onScrollFn);
|
|
191
|
-
window.addEventListener("resize", onResizeFn);
|
|
116
|
+
const F = q(B, 200), z = q(S, 500);
|
|
117
|
+
function N(t) {
|
|
118
|
+
n && I(), n = t, W(), S(), n == null || n.addEventListener("scroll", F), window.addEventListener("resize", z);
|
|
192
119
|
}
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
})
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
const destroy = () => {
|
|
213
|
-
element == null ? void 0 : element.removeEventListener("scroll", onScrollFn);
|
|
214
|
-
window.removeEventListener("resize", onResizeFn);
|
|
215
|
-
};
|
|
216
|
-
const goNext = () => {
|
|
217
|
-
const { countDelta: countDelta2, indexDelta: indexDelta2 } = state;
|
|
218
|
-
const last = countDelta2 - slidesPerPage;
|
|
219
|
-
const next = indexDelta2 + slidesPerPage <= last ? indexDelta2 + slidesPerPage : circular && indexDelta2 === last ? 0 : last;
|
|
220
|
-
jumpTo(void 0, next);
|
|
221
|
-
};
|
|
222
|
-
const goPrev = () => {
|
|
223
|
-
const { indexDelta: indexDelta2, countDelta: countDelta2 } = state;
|
|
224
|
-
const last = countDelta2 - slidesPerPage;
|
|
225
|
-
const next = indexDelta2 - slidesPerPage >= 0 ? indexDelta2 - slidesPerPage : circular && indexDelta2 === 0 ? last : 0;
|
|
226
|
-
jumpTo(void 0, next);
|
|
120
|
+
f && N(f);
|
|
121
|
+
const y = function(t, e) {
|
|
122
|
+
e !== void 0 && b(
|
|
123
|
+
M({
|
|
124
|
+
index: Math.floor(e / i),
|
|
125
|
+
indexDelta: e
|
|
126
|
+
})
|
|
127
|
+
), t !== void 0 && b(
|
|
128
|
+
M({
|
|
129
|
+
index: t,
|
|
130
|
+
indexDelta: t * i
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
}, I = () => {
|
|
134
|
+
n == null || n.removeEventListener("scroll", F), window.removeEventListener("resize", z);
|
|
227
135
|
};
|
|
228
136
|
return {
|
|
229
|
-
destroy,
|
|
230
|
-
getState,
|
|
231
|
-
subscribe,
|
|
232
|
-
jumpTo,
|
|
233
|
-
setElement,
|
|
234
|
-
calculate,
|
|
235
|
-
goNext
|
|
236
|
-
|
|
137
|
+
destroy: I,
|
|
138
|
+
getState: E,
|
|
139
|
+
subscribe: O,
|
|
140
|
+
jumpTo: y,
|
|
141
|
+
setElement: N,
|
|
142
|
+
calculate: S,
|
|
143
|
+
goNext: () => {
|
|
144
|
+
const { countDelta: t, indexDelta: e } = a, o = t - i, l = e + i <= o ? e + i : c && e === o ? 0 : o;
|
|
145
|
+
y(void 0, l);
|
|
146
|
+
},
|
|
147
|
+
goPrev: () => {
|
|
148
|
+
const { indexDelta: t, countDelta: e } = a, o = e - i, l = t - i >= 0 ? t - i : c && t === 0 ? o : 0;
|
|
149
|
+
y(void 0, l);
|
|
150
|
+
}
|
|
237
151
|
};
|
|
238
152
|
}
|
|
239
153
|
export {
|
|
240
|
-
createSnapSlider
|
|
154
|
+
H as createSnapSlider
|
|
241
155
|
};
|
|
156
|
+
//# sourceMappingURL=snap-slider.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snap-slider.es.js","sources":["../src/lib/throttle.ts","../src/lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport interface TSnapSliderParams extends TSnapSliderStateUpdate {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n circular?: boolean\n}\n\nexport type TSnapSliderJumpToFn = (index?: number, indexDelta?: number) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n // @ts-expect-error [mildly irritated message]\n const behavior: ScrollBehavior =\n distance > limitInstantScroll ? 'instant' : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n // @ts-expect-error [mildly irritated message]\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n keys.forEach((key) => {\n if (state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n element.querySelectorAll(itemSelector).forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n update({\n count,\n countDelta,\n ...resetIndexMayby,\n })\n }\n }\n\n let ticking = false\n function onScroll() {\n if (!ticking && element) {\n const scrollLeft = element.scrollLeft\n window.requestAnimationFrame(() => {\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n prevIndexDelta = indexDelta\n update(\n fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n })\n )\n }\n ticking = false\n })\n ticking = true\n }\n }\n const onScrollFn = throttle(onScroll, 200)\n const onResizeFn = throttle(calculate, 500)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n element?.addEventListener('scroll', onScrollFn)\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (index, indexDelta) {\n if (indexDelta !== undefined) {\n update(\n fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n })\n )\n }\n if (index !== undefined) {\n update(\n fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n })\n )\n }\n }\n const destroy = () => {\n element?.removeEventListener('scroll', onScrollFn)\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["throttle","fn","wait","inThrottle","lastFn","lastTime","context","args","createSnapSlider","_element","count","countDelta","index","circular","indexDelta","initalSubscriptionPublish","itemSelector","initalIndex","state","prevIndexDelta","slidesPerPage","itemPositions","muteScrollListner","left","element","updateIndexDelta","prev","distance","limitInstantScroll","behavior","publishDirty","listeners","subscribe","callback","getState","x","destroy","notify","update","params","dirty","indexDeltaDirty","key","fixIndex","nextIndex","last","calculate","contentWidth","itemWidth","slide","resetIndexMayby","ticking","onScroll","scrollLeft","positionItem","curr","onScrollFn","onResizeFn","setElement","_el","jumpTo","next"],"mappings":"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"}
|
|
@@ -1,45 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const react = require("react");
|
|
4
|
-
const snapSlider = require("./snap-slider.cjs.js");
|
|
5
|
-
function useSnapSlider(ref, count = 1, index = 0, circular = false, countHash) {
|
|
6
|
-
const [, forceUpdate] = react.useState(0);
|
|
7
|
-
const mountedRef = react.useRef();
|
|
8
|
-
const [observer] = react.useState(
|
|
9
|
-
() => snapSlider.createSnapSlider({
|
|
10
|
-
element: ref.current,
|
|
11
|
-
count,
|
|
12
|
-
index,
|
|
13
|
-
circular,
|
|
14
|
-
initalSubscriptionPublish: false
|
|
15
|
-
})
|
|
16
|
-
);
|
|
17
|
-
const result = observer.getState(count, index);
|
|
18
|
-
react.useEffect(() => {
|
|
19
|
-
if (mountedRef.current) {
|
|
20
|
-
console.log("change count", count, countHash);
|
|
21
|
-
observer.jumpTo(0);
|
|
22
|
-
observer.calculate();
|
|
23
|
-
}
|
|
24
|
-
}, [count, countHash, observer]);
|
|
25
|
-
react.useEffect(() => {
|
|
26
|
-
mountedRef.current = true;
|
|
27
|
-
const unsubscribe = observer.subscribe(() => {
|
|
28
|
-
if (mountedRef.current) {
|
|
29
|
-
forceUpdate((x) => x + 1);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
ref.current && observer.setElement(ref.current);
|
|
33
|
-
return () => {
|
|
34
|
-
mountedRef.current = false;
|
|
35
|
-
unsubscribe();
|
|
36
|
-
};
|
|
37
|
-
}, [observer, forceUpdate]);
|
|
38
|
-
return {
|
|
39
|
-
...result,
|
|
40
|
-
jumpTo: observer.jumpTo,
|
|
41
|
-
goNext: observer.goNext,
|
|
42
|
-
goPrev: observer.goPrev
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
exports.useSnapSlider = useSnapSlider;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react"),f=require("./snap-slider.cjs.js");function p(u,n=1,c=0,o=!1,i){const[,s]=t.useState(0),r=t.useRef(),[e]=t.useState(()=>f.createSnapSlider({element:u.current,count:n,index:c,circular:o,initalSubscriptionPublish:!1})),a=e.getState();return t.useEffect(()=>{r.current&&(e.jumpTo(0),e.calculate())},[n,i,e]),t.useEffect(()=>{r.current=!0,u.current&&e.setElement(u.current);const l=e.subscribe(()=>{r.current&&s(S=>S+1)});return()=>{r.current=!1,l()}},[e,s]),{...a,jumpTo:e.jumpTo,goNext:e.goNext,goPrev:e.goPrev}}exports.useSnapSlider=p;
|
|
2
|
+
//# sourceMappingURL=use-snap-slider.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-snap-slider.cjs.js","sources":["../src/lib/use-snap-slider.ts"],"sourcesContent":["import { MutableRefObject, useEffect, useRef, useState } from 'react'\nimport { createSnapSlider, TSnapSliderStateFull } from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: (index: number) => void\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: MutableRefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n circular = false,\n countHash?: string | number\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>()\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n circular,\n initalSubscriptionPublish: false,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":["useSnapSlider","ref","count","index","circular","countHash","forceUpdate","useState","mountedRef","useRef","observer","createSnapSlider","result","useEffect","unsubscribe","x"],"mappings":"2IASgB,SAAAA,EACdC,EACAC,EAAgB,EAChBC,EAAgB,EAChBC,EAAW,GACXC,EACgB,CAChB,KAAM,EAAGC,CAAW,EAAIC,WAAiB,CAAC,EACpCC,EAAaC,EAAAA,SACb,CAACC,CAAQ,EAAIH,EAAA,SAAS,IAC1BI,mBAAiB,CACf,QAASV,EAAI,QACb,MAAAC,EACA,MAAAC,EACA,SAAAC,EACA,0BAA2B,EAAA,CAC5B,CAAA,EAEGQ,EAASF,EAAS,WACxBG,OAAAA,EAAAA,UAAU,IAAM,CACVL,EAAW,UACbE,EAAS,OAAO,CAAC,EACjBA,EAAS,UAAU,EAEpB,EAAA,CAACR,EAAOG,EAAWK,CAAQ,CAAC,EAC/BG,EAAAA,UAAU,IAAM,CACdL,EAAW,QAAU,GACrBP,EAAI,SAAWS,EAAS,WAAWT,EAAI,OAAO,EACxC,MAAAa,EAAcJ,EAAS,UAAU,IAAM,CACvCF,EAAW,SACDF,EAACS,GAAMA,EAAI,CAAC,CAC1B,CACD,EAED,MAAO,IAAM,CACXP,EAAW,QAAU,GACTM,GAAA,CACd,EACC,CAACJ,EAAUJ,CAAW,CAAC,EACnB,CACL,GAAGM,EACH,OAAQF,EAAS,OACjB,OAAQA,EAAS,OACjB,OAAQA,EAAS,MAAA,CAErB"}
|
|
@@ -1,45 +1,33 @@
|
|
|
1
|
-
import { useState, useRef, useEffect } from "react";
|
|
2
|
-
import { createSnapSlider } from "./snap-slider.es.js";
|
|
3
|
-
function
|
|
4
|
-
const [,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
circular,
|
|
12
|
-
initalSubscriptionPublish: false
|
|
1
|
+
import { useState as o, useRef as p, useEffect as s } from "react";
|
|
2
|
+
import { createSnapSlider as b } from "./snap-slider.es.js";
|
|
3
|
+
function d(r, u = 1, c = 0, i = !1, a) {
|
|
4
|
+
const [, n] = o(0), t = p(), [e] = o(
|
|
5
|
+
() => b({
|
|
6
|
+
element: r.current,
|
|
7
|
+
count: u,
|
|
8
|
+
index: c,
|
|
9
|
+
circular: i,
|
|
10
|
+
initalSubscriptionPublish: !1
|
|
13
11
|
})
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}, [count, countHash, observer]);
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
mountedRef.current = true;
|
|
25
|
-
const unsubscribe = observer.subscribe(() => {
|
|
26
|
-
if (mountedRef.current) {
|
|
27
|
-
forceUpdate((x) => x + 1);
|
|
28
|
-
}
|
|
12
|
+
), l = e.getState();
|
|
13
|
+
return s(() => {
|
|
14
|
+
t.current && (e.jumpTo(0), e.calculate());
|
|
15
|
+
}, [u, a, e]), s(() => {
|
|
16
|
+
t.current = !0, r.current && e.setElement(r.current);
|
|
17
|
+
const f = e.subscribe(() => {
|
|
18
|
+
t.current && n((m) => m + 1);
|
|
29
19
|
});
|
|
30
|
-
ref.current && observer.setElement(ref.current);
|
|
31
20
|
return () => {
|
|
32
|
-
|
|
33
|
-
unsubscribe();
|
|
21
|
+
t.current = !1, f();
|
|
34
22
|
};
|
|
35
|
-
}, [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
goPrev: observer.goPrev
|
|
23
|
+
}, [e, n]), {
|
|
24
|
+
...l,
|
|
25
|
+
jumpTo: e.jumpTo,
|
|
26
|
+
goNext: e.goNext,
|
|
27
|
+
goPrev: e.goPrev
|
|
41
28
|
};
|
|
42
29
|
}
|
|
43
30
|
export {
|
|
44
|
-
useSnapSlider
|
|
31
|
+
d as useSnapSlider
|
|
45
32
|
};
|
|
33
|
+
//# sourceMappingURL=use-snap-slider.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-snap-slider.es.js","sources":["../src/lib/use-snap-slider.ts"],"sourcesContent":["import { MutableRefObject, useEffect, useRef, useState } from 'react'\nimport { createSnapSlider, TSnapSliderStateFull } from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: (index: number) => void\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: MutableRefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n circular = false,\n countHash?: string | number\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>()\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n circular,\n initalSubscriptionPublish: false,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":["useSnapSlider","ref","count","index","circular","countHash","forceUpdate","useState","mountedRef","useRef","observer","createSnapSlider","result","useEffect","unsubscribe","x"],"mappings":";;AASgB,SAAAA,EACdC,GACAC,IAAgB,GAChBC,IAAgB,GAChBC,IAAW,IACXC,GACgB;AAChB,QAAM,GAAGC,CAAW,IAAIC,EAAiB,CAAC,GACpCC,IAAaC,KACb,CAACC,CAAQ,IAAIH;AAAA,IAAS,MAC1BI,EAAiB;AAAA,MACf,SAASV,EAAI;AAAA,MACb,OAAAC;AAAA,MACA,OAAAC;AAAA,MACA,UAAAC;AAAA,MACA,2BAA2B;AAAA,IAAA,CAC5B;AAAA,EAAA,GAEGQ,IAASF,EAAS;AACxB,SAAAG,EAAU,MAAM;AACd,IAAIL,EAAW,YACbE,EAAS,OAAO,CAAC,GACjBA,EAAS,UAAU;AAAA,EAEpB,GAAA,CAACR,GAAOG,GAAWK,CAAQ,CAAC,GAC/BG,EAAU,MAAM;AACd,IAAAL,EAAW,UAAU,IACrBP,EAAI,WAAWS,EAAS,WAAWT,EAAI,OAAO;AACxC,UAAAa,IAAcJ,EAAS,UAAU,MAAM;AAC3C,MAAIF,EAAW,WACDF,EAAA,CAACS,MAAMA,IAAI,CAAC;AAAA,IAC1B,CACD;AAED,WAAO,MAAM;AACX,MAAAP,EAAW,UAAU,IACTM;IAAA;AAAA,EACd,GACC,CAACJ,GAAUJ,CAAW,CAAC,GACnB;AAAA,IACL,GAAGM;AAAA,IACH,QAAQF,EAAS;AAAA,IACjB,QAAQA,EAAS;AAAA,IACjB,QAAQA,EAAS;AAAA,EAAA;AAErB;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-snap-slider",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "React hook to manage css snap sliders",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/use-snap-slider.cjs.js",
|
|
@@ -16,22 +16,36 @@
|
|
|
16
16
|
"homepage": "https://use-snap-slider.vercel.app",
|
|
17
17
|
"scripts": {
|
|
18
18
|
"dev": "vite",
|
|
19
|
-
"build": "tsc && vite build",
|
|
19
|
+
"build": "tsc -p tsconfig.prod.json && vite build",
|
|
20
|
+
"build::source": "DISABLE_MINIFY=1 npm run build",
|
|
20
21
|
"prepare": "npm run build",
|
|
21
|
-
"build-vercel": "tsc && vite build --config vite.config.vercel.ts",
|
|
22
|
-
"preview": "vite preview"
|
|
22
|
+
"build-vercel": "tsc -p tsconfig.prod.json && vite build --config vite.config.vercel.ts",
|
|
23
|
+
"preview": "vite preview",
|
|
24
|
+
"test": "npm run jest",
|
|
25
|
+
"jest": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest",
|
|
26
|
+
"coverage": "npm run jest -- --coverage=true"
|
|
27
|
+
},
|
|
28
|
+
"prettier": {
|
|
29
|
+
"semi": false,
|
|
30
|
+
"singleQuote": true
|
|
23
31
|
},
|
|
24
32
|
"devDependencies": {
|
|
33
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
34
|
+
"@testing-library/react": "^14.0.0",
|
|
35
|
+
"@types/jest": "^29.5.0",
|
|
25
36
|
"@types/node": "^18.15.11",
|
|
26
37
|
"@types/react": "^18.0.28",
|
|
27
38
|
"@types/react-dom": "^18.0.11",
|
|
28
39
|
"@vitejs/plugin-react": "^3.1.0",
|
|
29
40
|
"autoprefixer": "^10.4.14",
|
|
30
41
|
"classnames": "^2.3.2",
|
|
42
|
+
"jest": "^29.5.0",
|
|
43
|
+
"jest-environment-jsdom": "^29.5.0",
|
|
31
44
|
"postcss": "^8.4.21",
|
|
32
45
|
"react": "^18.2.0",
|
|
33
46
|
"react-dom": "^18.2.0",
|
|
34
47
|
"tailwindcss": "^3.2.7",
|
|
48
|
+
"ts-jest": "^29.1.0",
|
|
35
49
|
"typescript": "^4.9.3",
|
|
36
50
|
"vite": "^4.2.0",
|
|
37
51
|
"vite-plugin-dts": "^2.2.0"
|