use-snap-slider 0.0.2 → 0.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 +198 -1
- package/dist/lib/snap-slider.d.ts +2 -3
- 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 +120 -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 +24 -37
- package/dist/use-snap-slider.es.js.map +1 -0
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -1,3 +1,200 @@
|
|
|
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 state = useSnapSlider(ref, slides.count)
|
|
36
|
+
const pages = Array.from(Array(state.count).keys())
|
|
37
|
+
return (
|
|
38
|
+
<div>
|
|
39
|
+
<div className="flex scroll-smooth snap-x snap-mandatory overflow-x-auto w-full" 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={() => state.jumpTo(page)} disabled={page === state.index}>{page + 1}</button>
|
|
49
|
+
))}
|
|
50
|
+
</nav>
|
|
51
|
+
<nav aria-label="Prev / Next navigation">
|
|
52
|
+
<button onClick={state.goPrev} disabled={!state.prevEnabled}>Prev</button>
|
|
53
|
+
<button onClick={state.goNext} disabled={!state.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
|
+
} = createSnapSlider({
|
|
136
|
+
element: HTMLDivElement | null,
|
|
137
|
+
count?:number = 1,
|
|
138
|
+
countDelta?:number,
|
|
139
|
+
index?:number = 0,
|
|
140
|
+
circular?:boolean,
|
|
141
|
+
indexDelta?:number,
|
|
142
|
+
itemSelector?:string = ':scope > *',
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Adding nessesary styles
|
|
147
|
+
|
|
148
|
+
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:
|
|
149
|
+
|
|
150
|
+
* [React component](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/react-example/SnapSliderReact.tsx)
|
|
151
|
+
* [Vanilla JS function](https://github.com/gerhardsletten/use-snap-slider/blob/main/src/vanilla-example/create-snap-slider.ts)
|
|
152
|
+
|
|
153
|
+
### TailwindCSS
|
|
154
|
+
|
|
155
|
+
See also tailwinds own documentation for [scroll snap](https://tailwindcss.com/docs/scroll-snap-type)
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<div class="flex scroll-smooth snap-x snap-mandatory overflow-x-auto">
|
|
159
|
+
<div class="flex snap-start shrink-0">
|
|
160
|
+
Slide 1
|
|
161
|
+
</div>
|
|
162
|
+
<div class="flex snap-start shrink-0">
|
|
163
|
+
Slide 2
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Basic css
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<style>
|
|
172
|
+
.css-slider {
|
|
173
|
+
display: flex;
|
|
174
|
+
overflow-x: auto;
|
|
175
|
+
scroll-snap-type: x mandatory;
|
|
176
|
+
scroll-behavior: smooth;
|
|
177
|
+
-webkit-overflow-scrolling: touch;
|
|
178
|
+
}
|
|
179
|
+
.css-slider::-webkit-scrollbar {
|
|
180
|
+
@apply hidden;
|
|
181
|
+
}
|
|
182
|
+
.css-slider-item {
|
|
183
|
+
display: flex;
|
|
184
|
+
scroll-snap-align: start;
|
|
185
|
+
flex-shrink: 0;
|
|
186
|
+
}
|
|
187
|
+
.css-slider-item-half {
|
|
188
|
+
width: 50%;
|
|
189
|
+
}
|
|
190
|
+
</style>
|
|
191
|
+
<!-- Markup -->
|
|
192
|
+
<div class="css-slider">
|
|
193
|
+
<div class="css-slider-item css-slider-item-half">
|
|
194
|
+
Slide 1
|
|
195
|
+
</div>
|
|
196
|
+
<div class="css-slider-item css-slider-item-half">
|
|
197
|
+
Slide 2
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
```
|
|
@@ -20,13 +20,12 @@ export type TSnapListner = (params: TSnapSliderStateFull) => void;
|
|
|
20
20
|
export interface TSnapSliderParams extends TSnapSliderStateUpdate {
|
|
21
21
|
element: HTMLElement | null;
|
|
22
22
|
itemSelector?: string;
|
|
23
|
-
initalSubscriptionPublish?: boolean;
|
|
24
23
|
circular?: boolean;
|
|
25
24
|
}
|
|
26
25
|
export type TSnapSliderJumpToFn = (index?: number, indexDelta?: number) => void;
|
|
27
26
|
export interface TSnapSlider {
|
|
28
27
|
destroy: () => void;
|
|
29
|
-
getState: (
|
|
28
|
+
getState: () => TSnapSliderStateFull;
|
|
30
29
|
jumpTo: TSnapSliderJumpToFn;
|
|
31
30
|
goNext: () => void;
|
|
32
31
|
goPrev: () => void;
|
|
@@ -34,5 +33,5 @@ export interface TSnapSlider {
|
|
|
34
33
|
setElement: (el: HTMLElement) => void;
|
|
35
34
|
calculate: () => void;
|
|
36
35
|
}
|
|
37
|
-
export declare function createSnapSlider({ element: _element, count, countDelta, index, circular, indexDelta,
|
|
36
|
+
export declare function createSnapSlider({ element: _element, count, countDelta, index, circular, indexDelta, itemSelector, }: TSnapSliderParams): TSnapSlider;
|
|
38
37
|
export {};
|
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,c;return function(){const v=this,p=arguments;h?(clearTimeout(r),r=setTimeout(()=>{Date.now()-c>=u&&(f.apply(v,p),c=Date.now())},Math.max(u-(Date.now()-c),0))):(f.apply(v,p),c=Date.now(),h=!0)}};function B({element:f,count:u=1,countDelta:h,index:r=0,circular:c,indexDelta:v,itemSelector:p=":scope > *"}){let T=r,a={index:r,indexDelta:v||r,count:u,countDelta:h||u},S=r,i=1,D=[],g=!1,x=0,o;function W(){if(o){const t=o.scrollLeft,{indexDelta:e}=a;if(x=e*(o.offsetWidth/i),S!==e){const n=Math.abs(t-x),l=o.offsetWidth*2;S=e,g=!0,o.scroll({left:x,top:0,behavior:n>l?"smooth":void 0})}else T&&(g=!0,o.scroll({left:x,top:0}),T=void 0)}}let P=!1,d=[];const A=t=>(d.push(t),P&&t(b()),()=>{d=d.filter(e=>e!==t),d.length<1&&I()});function O(){d.forEach(t=>{t(b())})}const b=()=>{const{indexDelta:t,countDelta:e}=a;return{...a,prevEnabled:c||t>0,nextEnabled:c||e-i>t}};function m(t){let e=!1,n=!1;Object.keys(t).forEach(s=>{a[s]!==t[s]&&(a[s]=Number(t[s]),e=!0,s==="indexDelta"&&(n=!0))}),e&&(P=d.length===0,O(),n&&W())}function y(t){const{index:e,indexDelta:n}=t,{countDelta:l,count:s}=a,L=l-i;return{index:n<L?e:s-1,indexDelta:n}}function M(){if(o){let t=0,e=0;D=[],o.querySelectorAll(p).forEach(N=>{D.push(t),t+=N.clientWidth,e=N.clientWidth}),i=Math.round(o.offsetWidth/e);const n=D.length,l=Math.ceil(n/i),{index:s}=a,L=s+1>l?{index:0,indexDelta:0}:{};m({count:l,countDelta:n,...L})}}let E=!1;function R(){if(!E&&o){const t=o.scrollLeft;window.requestAnimationFrame(()=>{if(g)Math.abs(x-t)<1&&(g=!1);else{const e=D.reduce((l,s)=>Math.abs(s-t)<Math.abs(l-t)?s:l),n=D.findIndex(l=>l===e);S=n,m(y({index:Math.floor(n/i),indexDelta:n}))}E=!1}),E=!0}}const F=q(R,200),j=q(M,500);function z(t){o&&I(),o=t,W(),M(),o==null||o.addEventListener("scroll",F),window.addEventListener("resize",j)}f&&z(f);const w=function(t,e){e!==void 0&&m(y({index:Math.floor(e/i),indexDelta:e})),t!==void 0&&m(y({index:t,indexDelta:t*i}))},I=()=>{o==null||o.removeEventListener("scroll",F),window.removeEventListener("resize",j)};return{destroy:I,getState:b,subscribe:A,jumpTo:w,setElement:z,calculate:M,goNext:()=>{const{countDelta:t,indexDelta:e}=a,n=t-i,l=e+i<=n?e+i:c&&e===n?0:n;w(void 0,l)},goPrev:()=>{const{indexDelta:t,countDelta:e}=a,n=e-i,l=t-i>=0?t-i:c&&t===0?n:0;w(void 0,l)}}}exports.createSnapSlider=B;
|
|
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 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 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 element.scroll({\n left,\n top: 0,\n behavior: distance > limitInstantScroll ? 'smooth' : undefined,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\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 (publishDirty) {\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 < 1) {\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","itemSelector","initalIndex","state","prevIndexDelta","slidesPerPage","itemPositions","muteScrollListner","left","element","updateIndexDelta","prev","distance","limitInstantScroll","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,151 @@
|
|
|
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
|
-
|
|
28
|
-
itemSelector = ":scope > *"
|
|
10
|
+
function G({
|
|
11
|
+
element: f,
|
|
12
|
+
count: u = 1,
|
|
13
|
+
countDelta: h,
|
|
14
|
+
index: r = 0,
|
|
15
|
+
circular: c,
|
|
16
|
+
indexDelta: v,
|
|
17
|
+
itemSelector: p = ":scope > *"
|
|
29
18
|
}) {
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return;
|
|
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
|
|
19
|
+
let T = r, a = {
|
|
20
|
+
index: r,
|
|
21
|
+
indexDelta: v || r,
|
|
22
|
+
count: u,
|
|
23
|
+
countDelta: h || u
|
|
24
|
+
}, b = r, i = 1, x = [], m = !1, D = 0, o;
|
|
25
|
+
function W() {
|
|
26
|
+
if (o) {
|
|
27
|
+
const t = o.scrollLeft, { indexDelta: e } = a;
|
|
28
|
+
if (D = e * (o.offsetWidth / i), b !== e) {
|
|
29
|
+
const n = Math.abs(t - D), l = o.offsetWidth * 2;
|
|
30
|
+
b = e, m = !0, o.scroll({
|
|
31
|
+
left: D,
|
|
32
|
+
top: 0,
|
|
33
|
+
behavior: n > l ? "smooth" : void 0
|
|
66
34
|
});
|
|
67
|
-
|
|
68
|
-
|
|
35
|
+
} else
|
|
36
|
+
T && (m = !0, o.scroll({
|
|
37
|
+
left: D,
|
|
38
|
+
top: 0
|
|
39
|
+
}), T = void 0);
|
|
69
40
|
}
|
|
70
41
|
}
|
|
71
|
-
let
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
function notify() {
|
|
82
|
-
listeners.forEach((callback) => {
|
|
83
|
-
callback(getState());
|
|
42
|
+
let P = !1, d = [];
|
|
43
|
+
const A = (t) => (d.push(t), P && t(E()), () => {
|
|
44
|
+
d = d.filter((e) => e !== t), d.length < 1 && I();
|
|
45
|
+
});
|
|
46
|
+
function O() {
|
|
47
|
+
d.forEach((t) => {
|
|
48
|
+
t(E());
|
|
84
49
|
});
|
|
85
50
|
}
|
|
86
|
-
const
|
|
87
|
-
const { indexDelta:
|
|
51
|
+
const E = () => {
|
|
52
|
+
const { indexDelta: t, countDelta: e } = a;
|
|
88
53
|
return {
|
|
89
|
-
...
|
|
90
|
-
prevEnabled:
|
|
91
|
-
nextEnabled:
|
|
54
|
+
...a,
|
|
55
|
+
prevEnabled: c || t > 0,
|
|
56
|
+
nextEnabled: c || e - i > t
|
|
92
57
|
};
|
|
93
58
|
};
|
|
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
|
-
}
|
|
59
|
+
function g(t) {
|
|
60
|
+
let e = !1, n = !1;
|
|
61
|
+
Object.keys(
|
|
62
|
+
t
|
|
63
|
+
).forEach((s) => {
|
|
64
|
+
a[s] !== t[s] && (a[s] = Number(t[s]), e = !0, s === "indexDelta" && (n = !0));
|
|
65
|
+
}), e && (P = d.length === 0, O(), n && W());
|
|
117
66
|
}
|
|
118
|
-
function
|
|
119
|
-
const { index:
|
|
120
|
-
const { countDelta: countDelta2, count: count2 } = state;
|
|
121
|
-
const last = countDelta2 - slidesPerPage;
|
|
67
|
+
function M(t) {
|
|
68
|
+
const { index: e, indexDelta: n } = t, { countDelta: l, count: s } = a, L = l - i;
|
|
122
69
|
return {
|
|
123
|
-
index:
|
|
124
|
-
indexDelta:
|
|
70
|
+
index: n < L ? e : s - 1,
|
|
71
|
+
indexDelta: n
|
|
125
72
|
};
|
|
126
73
|
}
|
|
127
|
-
function
|
|
128
|
-
if (
|
|
129
|
-
|
|
74
|
+
function S() {
|
|
75
|
+
if (o) {
|
|
76
|
+
let t = 0, e = 0;
|
|
77
|
+
x = [], o.querySelectorAll(p).forEach((j) => {
|
|
78
|
+
x.push(t), t += j.clientWidth, e = j.clientWidth;
|
|
79
|
+
}), i = Math.round(o.offsetWidth / e);
|
|
80
|
+
const n = x.length, l = Math.ceil(n / i), { index: s } = a, L = s + 1 > l ? {
|
|
81
|
+
index: 0,
|
|
82
|
+
indexDelta: 0
|
|
83
|
+
} : {};
|
|
84
|
+
g({
|
|
85
|
+
count: l,
|
|
86
|
+
countDelta: n,
|
|
87
|
+
...L
|
|
88
|
+
});
|
|
130
89
|
}
|
|
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
90
|
}
|
|
153
|
-
let
|
|
154
|
-
function
|
|
155
|
-
if (!
|
|
156
|
-
const
|
|
91
|
+
let w = !1;
|
|
92
|
+
function R() {
|
|
93
|
+
if (!w && o) {
|
|
94
|
+
const t = o.scrollLeft;
|
|
157
95
|
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
|
|
96
|
+
if (m)
|
|
97
|
+
Math.abs(D - t) < 1 && (m = !1);
|
|
98
|
+
else {
|
|
99
|
+
const e = x.reduce((l, s) => Math.abs(s - t) < Math.abs(l - t) ? s : l), n = x.findIndex((l) => l === e);
|
|
100
|
+
b = n, g(
|
|
101
|
+
M({
|
|
102
|
+
index: Math.floor(n / i),
|
|
103
|
+
indexDelta: n
|
|
173
104
|
})
|
|
174
105
|
);
|
|
175
106
|
}
|
|
176
|
-
|
|
177
|
-
});
|
|
178
|
-
ticking = true;
|
|
107
|
+
w = !1;
|
|
108
|
+
}), w = !0;
|
|
179
109
|
}
|
|
180
110
|
}
|
|
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);
|
|
111
|
+
const F = q(R, 200), z = q(S, 500);
|
|
112
|
+
function N(t) {
|
|
113
|
+
o && I(), o = t, W(), S(), o == null || o.addEventListener("scroll", F), window.addEventListener("resize", z);
|
|
192
114
|
}
|
|
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);
|
|
115
|
+
f && N(f);
|
|
116
|
+
const y = function(t, e) {
|
|
117
|
+
e !== void 0 && g(
|
|
118
|
+
M({
|
|
119
|
+
index: Math.floor(e / i),
|
|
120
|
+
indexDelta: e
|
|
121
|
+
})
|
|
122
|
+
), t !== void 0 && g(
|
|
123
|
+
M({
|
|
124
|
+
index: t,
|
|
125
|
+
indexDelta: t * i
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
}, I = () => {
|
|
129
|
+
o == null || o.removeEventListener("scroll", F), window.removeEventListener("resize", z);
|
|
227
130
|
};
|
|
228
131
|
return {
|
|
229
|
-
destroy,
|
|
230
|
-
getState,
|
|
231
|
-
subscribe,
|
|
232
|
-
jumpTo,
|
|
233
|
-
setElement,
|
|
234
|
-
calculate,
|
|
235
|
-
goNext
|
|
236
|
-
|
|
132
|
+
destroy: I,
|
|
133
|
+
getState: E,
|
|
134
|
+
subscribe: A,
|
|
135
|
+
jumpTo: y,
|
|
136
|
+
setElement: N,
|
|
137
|
+
calculate: S,
|
|
138
|
+
goNext: () => {
|
|
139
|
+
const { countDelta: t, indexDelta: e } = a, n = t - i, l = e + i <= n ? e + i : c && e === n ? 0 : n;
|
|
140
|
+
y(void 0, l);
|
|
141
|
+
},
|
|
142
|
+
goPrev: () => {
|
|
143
|
+
const { indexDelta: t, countDelta: e } = a, n = e - i, l = t - i >= 0 ? t - i : c && t === 0 ? n : 0;
|
|
144
|
+
y(void 0, l);
|
|
145
|
+
}
|
|
237
146
|
};
|
|
238
147
|
}
|
|
239
148
|
export {
|
|
240
|
-
createSnapSlider
|
|
149
|
+
G as createSnapSlider
|
|
241
150
|
};
|
|
151
|
+
//# 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 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 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 element.scroll({\n left,\n top: 0,\n behavior: distance > limitInstantScroll ? 'smooth' : undefined,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\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 (publishDirty) {\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 < 1) {\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","itemSelector","initalIndex","state","prevIndexDelta","slidesPerPage","itemPositions","muteScrollListner","left","element","updateIndexDelta","prev","distance","limitInstantScroll","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,a){const[,s]=t.useState(0),r=t.useRef(),[e]=t.useState(()=>f.createSnapSlider({element:u.current,count:n,index:c,circular:o})),i=e.getState();return t.useEffect(()=>{r.current&&(e.jumpTo(0),e.calculate())},[n,a,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]),{...i,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 })\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,CAAA,CACD,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,32 @@
|
|
|
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
|
-
index,
|
|
11
|
-
circular,
|
|
12
|
-
initalSubscriptionPublish: false
|
|
1
|
+
import { useState as o, useRef as p, useEffect as c } from "react";
|
|
2
|
+
import { createSnapSlider as S } from "./snap-slider.es.js";
|
|
3
|
+
function d(r, u = 1, s = 0, a = !1, f) {
|
|
4
|
+
const [, n] = o(0), t = p(), [e] = o(
|
|
5
|
+
() => S({
|
|
6
|
+
element: r.current,
|
|
7
|
+
count: u,
|
|
8
|
+
index: s,
|
|
9
|
+
circular: a
|
|
13
10
|
})
|
|
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
|
-
}
|
|
11
|
+
), m = e.getState();
|
|
12
|
+
return c(() => {
|
|
13
|
+
t.current && (e.jumpTo(0), e.calculate());
|
|
14
|
+
}, [u, f, e]), c(() => {
|
|
15
|
+
t.current = !0, r.current && e.setElement(r.current);
|
|
16
|
+
const i = e.subscribe(() => {
|
|
17
|
+
t.current && n((l) => l + 1);
|
|
29
18
|
});
|
|
30
|
-
ref.current && observer.setElement(ref.current);
|
|
31
19
|
return () => {
|
|
32
|
-
|
|
33
|
-
unsubscribe();
|
|
20
|
+
t.current = !1, i();
|
|
34
21
|
};
|
|
35
|
-
}, [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
goPrev: observer.goPrev
|
|
22
|
+
}, [e, n]), {
|
|
23
|
+
...m,
|
|
24
|
+
jumpTo: e.jumpTo,
|
|
25
|
+
goNext: e.goNext,
|
|
26
|
+
goPrev: e.goPrev
|
|
41
27
|
};
|
|
42
28
|
}
|
|
43
29
|
export {
|
|
44
|
-
useSnapSlider
|
|
30
|
+
d as useSnapSlider
|
|
45
31
|
};
|
|
32
|
+
//# 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 })\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,IAAA,CACD;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.4",
|
|
4
4
|
"description": "React hook to manage css snap sliders",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/use-snap-slider.cjs.js",
|
|
@@ -13,24 +13,39 @@
|
|
|
13
13
|
"type": "git",
|
|
14
14
|
"url": "git+https://github.com/gerhardsletten/use-snap-slider.git"
|
|
15
15
|
},
|
|
16
|
+
"homepage": "https://use-snap-slider.vercel.app",
|
|
16
17
|
"scripts": {
|
|
17
18
|
"dev": "vite",
|
|
18
|
-
"build": "tsc && vite build",
|
|
19
|
+
"build": "tsc -p tsconfig.prod.json && vite build",
|
|
20
|
+
"build::source": "DISABLE_MINIFY=1 npm run build",
|
|
19
21
|
"prepare": "npm run build",
|
|
20
|
-
"build-vercel": "tsc && vite build --config vite.config.vercel.ts",
|
|
21
|
-
"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
|
|
22
31
|
},
|
|
23
32
|
"devDependencies": {
|
|
33
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
34
|
+
"@testing-library/react": "^14.0.0",
|
|
35
|
+
"@types/jest": "^29.5.0",
|
|
24
36
|
"@types/node": "^18.15.11",
|
|
25
37
|
"@types/react": "^18.0.28",
|
|
26
38
|
"@types/react-dom": "^18.0.11",
|
|
27
39
|
"@vitejs/plugin-react": "^3.1.0",
|
|
28
40
|
"autoprefixer": "^10.4.14",
|
|
29
41
|
"classnames": "^2.3.2",
|
|
42
|
+
"jest": "^29.5.0",
|
|
43
|
+
"jest-environment-jsdom": "^29.5.0",
|
|
30
44
|
"postcss": "^8.4.21",
|
|
31
45
|
"react": "^18.2.0",
|
|
32
46
|
"react-dom": "^18.2.0",
|
|
33
47
|
"tailwindcss": "^3.2.7",
|
|
48
|
+
"ts-jest": "^29.1.0",
|
|
34
49
|
"typescript": "^4.9.3",
|
|
35
50
|
"vite": "^4.2.0",
|
|
36
51
|
"vite-plugin-dts": "^2.2.0"
|