lenis 1.1.13 → 1.1.14-dev.0
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 +2 -0
- package/dist/lenis-react.d.ts +11 -11
- package/dist/lenis-react.mjs +159 -2
- package/dist/lenis-react.mjs.map +1 -1
- package/dist/lenis-snap.js +298 -332
- package/dist/lenis-snap.js.map +1 -1
- package/dist/lenis-snap.min.js +2 -2
- package/dist/lenis-snap.min.js.map +1 -1
- package/dist/lenis-snap.mjs +308 -2
- package/dist/lenis-snap.mjs.map +1 -1
- package/dist/lenis-vue.d.ts +68 -0
- package/dist/lenis-vue.mjs +198 -0
- package/dist/lenis-vue.mjs.map +1 -0
- package/dist/lenis.css +1 -20
- package/dist/lenis.js +816 -885
- package/dist/lenis.js.map +1 -1
- package/dist/lenis.min.js +2 -2
- package/dist/lenis.min.js.map +1 -1
- package/dist/lenis.mjs +854 -2
- package/dist/lenis.mjs.map +1 -1
- package/package.json +23 -32
package/dist/lenis.js
CHANGED
|
@@ -1,923 +1,854 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Lenis = factory());
|
|
5
|
-
})(this, (function () { 'use strict';
|
|
1
|
+
// package.json
|
|
2
|
+
var version = "1.1.14-dev.0";
|
|
6
3
|
|
|
7
|
-
|
|
4
|
+
// packages/core/src/maths.ts
|
|
5
|
+
function clamp(min, input, max) {
|
|
6
|
+
return Math.max(min, Math.min(input, max));
|
|
7
|
+
}
|
|
8
|
+
function lerp(x, y, t) {
|
|
9
|
+
return (1 - t) * x + t * y;
|
|
10
|
+
}
|
|
11
|
+
function damp(x, y, lambda, deltaTime) {
|
|
12
|
+
return lerp(x, y, 1 - Math.exp(-lambda * deltaTime));
|
|
13
|
+
}
|
|
14
|
+
function modulo(n, d) {
|
|
15
|
+
return (n % d + d) % d;
|
|
16
|
+
}
|
|
8
17
|
|
|
18
|
+
// packages/core/src/animate.ts
|
|
19
|
+
var Animate = class {
|
|
20
|
+
isRunning = false;
|
|
21
|
+
value = 0;
|
|
22
|
+
from = 0;
|
|
23
|
+
to = 0;
|
|
24
|
+
currentTime = 0;
|
|
25
|
+
// These are instanciated in the fromTo method
|
|
26
|
+
lerp;
|
|
27
|
+
duration;
|
|
28
|
+
easing;
|
|
29
|
+
onUpdate;
|
|
9
30
|
/**
|
|
10
|
-
*
|
|
31
|
+
* Advance the animation by the given delta time
|
|
11
32
|
*
|
|
12
|
-
* @param
|
|
13
|
-
* @param input Value to clamp
|
|
14
|
-
* @param max Maximum value
|
|
15
|
-
* @returns Clamped value
|
|
33
|
+
* @param deltaTime - The time in seconds to advance the animation
|
|
16
34
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
35
|
+
advance(deltaTime) {
|
|
36
|
+
if (!this.isRunning) return;
|
|
37
|
+
let completed = false;
|
|
38
|
+
if (this.duration && this.easing) {
|
|
39
|
+
this.currentTime += deltaTime;
|
|
40
|
+
const linearProgress = clamp(0, this.currentTime / this.duration, 1);
|
|
41
|
+
completed = linearProgress >= 1;
|
|
42
|
+
const easedProgress = completed ? 1 : this.easing(linearProgress);
|
|
43
|
+
this.value = this.from + (this.to - this.from) * easedProgress;
|
|
44
|
+
} else if (this.lerp) {
|
|
45
|
+
this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
|
|
46
|
+
if (Math.round(this.value) === this.to) {
|
|
47
|
+
this.value = this.to;
|
|
48
|
+
completed = true;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
this.value = this.to;
|
|
52
|
+
completed = true;
|
|
53
|
+
}
|
|
54
|
+
if (completed) {
|
|
55
|
+
this.stop();
|
|
56
|
+
}
|
|
57
|
+
this.onUpdate?.(this.value, completed);
|
|
58
|
+
}
|
|
59
|
+
/** Stop the animation */
|
|
60
|
+
stop() {
|
|
61
|
+
this.isRunning = false;
|
|
19
62
|
}
|
|
20
63
|
/**
|
|
21
|
-
*
|
|
64
|
+
* Set up the animation from a starting value to an ending value
|
|
65
|
+
* with optional parameters for lerping, duration, easing, and onUpdate callback
|
|
22
66
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @param
|
|
26
|
-
* @returns Interpolated value
|
|
67
|
+
* @param from - The starting value
|
|
68
|
+
* @param to - The ending value
|
|
69
|
+
* @param options - Options for the animation
|
|
27
70
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
71
|
+
fromTo(from, to, { lerp: lerp2, duration, easing, onStart, onUpdate }) {
|
|
72
|
+
this.from = this.value = from;
|
|
73
|
+
this.to = to;
|
|
74
|
+
this.lerp = lerp2;
|
|
75
|
+
this.duration = duration;
|
|
76
|
+
this.easing = easing;
|
|
77
|
+
this.currentTime = 0;
|
|
78
|
+
this.isRunning = true;
|
|
79
|
+
onStart?.();
|
|
80
|
+
this.onUpdate = onUpdate;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// packages/core/src/debounce.ts
|
|
85
|
+
function debounce(callback, delay) {
|
|
86
|
+
let timer;
|
|
87
|
+
return function(...args) {
|
|
88
|
+
let context = this;
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
timer = setTimeout(() => {
|
|
91
|
+
timer = void 0;
|
|
92
|
+
callback.apply(context, args);
|
|
93
|
+
}, delay);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// packages/core/src/dimensions.ts
|
|
98
|
+
var Dimensions = class {
|
|
99
|
+
constructor(wrapper, content, { autoResize = true, debounce: debounceValue = 250 } = {}) {
|
|
100
|
+
this.wrapper = wrapper;
|
|
101
|
+
this.content = content;
|
|
102
|
+
if (autoResize) {
|
|
103
|
+
this.debouncedResize = debounce(this.resize, debounceValue);
|
|
104
|
+
if (this.wrapper instanceof Window) {
|
|
105
|
+
window.addEventListener("resize", this.debouncedResize, false);
|
|
106
|
+
} else {
|
|
107
|
+
this.wrapperResizeObserver = new ResizeObserver(this.debouncedResize);
|
|
108
|
+
this.wrapperResizeObserver.observe(this.wrapper);
|
|
109
|
+
}
|
|
110
|
+
this.contentResizeObserver = new ResizeObserver(this.debouncedResize);
|
|
111
|
+
this.contentResizeObserver.observe(this.content);
|
|
112
|
+
}
|
|
113
|
+
this.resize();
|
|
114
|
+
}
|
|
115
|
+
width = 0;
|
|
116
|
+
height = 0;
|
|
117
|
+
scrollHeight = 0;
|
|
118
|
+
scrollWidth = 0;
|
|
119
|
+
// These are instanciated in the constructor as they need information from the options
|
|
120
|
+
debouncedResize;
|
|
121
|
+
wrapperResizeObserver;
|
|
122
|
+
contentResizeObserver;
|
|
123
|
+
destroy() {
|
|
124
|
+
this.wrapperResizeObserver?.disconnect();
|
|
125
|
+
this.contentResizeObserver?.disconnect();
|
|
126
|
+
if (this.wrapper === window && this.debouncedResize) {
|
|
127
|
+
window.removeEventListener("resize", this.debouncedResize, false);
|
|
128
|
+
}
|
|
30
129
|
}
|
|
130
|
+
resize = () => {
|
|
131
|
+
this.onWrapperResize();
|
|
132
|
+
this.onContentResize();
|
|
133
|
+
};
|
|
134
|
+
onWrapperResize = () => {
|
|
135
|
+
if (this.wrapper instanceof Window) {
|
|
136
|
+
this.width = window.innerWidth;
|
|
137
|
+
this.height = window.innerHeight;
|
|
138
|
+
} else {
|
|
139
|
+
this.width = this.wrapper.clientWidth;
|
|
140
|
+
this.height = this.wrapper.clientHeight;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
onContentResize = () => {
|
|
144
|
+
if (this.wrapper instanceof Window) {
|
|
145
|
+
this.scrollHeight = this.content.scrollHeight;
|
|
146
|
+
this.scrollWidth = this.content.scrollWidth;
|
|
147
|
+
} else {
|
|
148
|
+
this.scrollHeight = this.wrapper.scrollHeight;
|
|
149
|
+
this.scrollWidth = this.wrapper.scrollWidth;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
get limit() {
|
|
153
|
+
return {
|
|
154
|
+
x: this.scrollWidth - this.width,
|
|
155
|
+
y: this.scrollHeight - this.height
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// packages/core/src/emitter.ts
|
|
161
|
+
var Emitter = class {
|
|
162
|
+
events = {};
|
|
31
163
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* @param x Initial value
|
|
36
|
-
* @param y Target value
|
|
37
|
-
* @param lambda Damping factor
|
|
38
|
-
* @param dt Time elapsed since the last update
|
|
39
|
-
* @returns Damped value
|
|
164
|
+
* Emit an event with the given data
|
|
165
|
+
* @param event Event name
|
|
166
|
+
* @param args Data to pass to the event handlers
|
|
40
167
|
*/
|
|
41
|
-
|
|
42
|
-
|
|
168
|
+
emit(event, ...args) {
|
|
169
|
+
let callbacks = this.events[event] || [];
|
|
170
|
+
for (let i = 0, length = callbacks.length; i < length; i++) {
|
|
171
|
+
callbacks[i]?.(...args);
|
|
172
|
+
}
|
|
43
173
|
}
|
|
44
174
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @
|
|
49
|
-
|
|
50
|
-
|
|
175
|
+
* Add a callback to the event
|
|
176
|
+
* @param event Event name
|
|
177
|
+
* @param cb Callback function
|
|
178
|
+
* @returns Unsubscribe function
|
|
179
|
+
*/
|
|
180
|
+
on(event, cb) {
|
|
181
|
+
this.events[event]?.push(cb) || (this.events[event] = [cb]);
|
|
182
|
+
return () => {
|
|
183
|
+
this.events[event] = this.events[event]?.filter((i) => cb !== i);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Remove a callback from the event
|
|
188
|
+
* @param event Event name
|
|
189
|
+
* @param callback Callback function
|
|
190
|
+
*/
|
|
191
|
+
off(event, callback) {
|
|
192
|
+
this.events[event] = this.events[event]?.filter((i) => callback !== i);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Remove all event listeners and clean up
|
|
51
196
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
197
|
+
destroy() {
|
|
198
|
+
this.events = {};
|
|
54
199
|
}
|
|
200
|
+
};
|
|
55
201
|
|
|
202
|
+
// packages/core/src/virtual-scroll.ts
|
|
203
|
+
var LINE_HEIGHT = 100 / 6;
|
|
204
|
+
var listenerOptions = { passive: false };
|
|
205
|
+
var VirtualScroll = class {
|
|
206
|
+
constructor(element, options = { wheelMultiplier: 1, touchMultiplier: 1 }) {
|
|
207
|
+
this.element = element;
|
|
208
|
+
this.options = options;
|
|
209
|
+
window.addEventListener("resize", this.onWindowResize, false);
|
|
210
|
+
this.onWindowResize();
|
|
211
|
+
this.element.addEventListener("wheel", this.onWheel, listenerOptions);
|
|
212
|
+
this.element.addEventListener(
|
|
213
|
+
"touchstart",
|
|
214
|
+
this.onTouchStart,
|
|
215
|
+
listenerOptions
|
|
216
|
+
);
|
|
217
|
+
this.element.addEventListener(
|
|
218
|
+
"touchmove",
|
|
219
|
+
this.onTouchMove,
|
|
220
|
+
listenerOptions
|
|
221
|
+
);
|
|
222
|
+
this.element.addEventListener("touchend", this.onTouchEnd, listenerOptions);
|
|
223
|
+
}
|
|
224
|
+
touchStart = {
|
|
225
|
+
x: 0,
|
|
226
|
+
y: 0
|
|
227
|
+
};
|
|
228
|
+
lastDelta = {
|
|
229
|
+
x: 0,
|
|
230
|
+
y: 0
|
|
231
|
+
};
|
|
232
|
+
window = {
|
|
233
|
+
width: 0,
|
|
234
|
+
height: 0
|
|
235
|
+
};
|
|
236
|
+
emitter = new Emitter();
|
|
56
237
|
/**
|
|
57
|
-
*
|
|
238
|
+
* Add an event listener for the given event and callback
|
|
58
239
|
*
|
|
59
|
-
* @
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class Animate {
|
|
65
|
-
constructor() {
|
|
66
|
-
this.isRunning = false;
|
|
67
|
-
this.value = 0;
|
|
68
|
-
this.from = 0;
|
|
69
|
-
this.to = 0;
|
|
70
|
-
this.currentTime = 0;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Advance the animation by the given delta time
|
|
74
|
-
*
|
|
75
|
-
* @param deltaTime - The time in seconds to advance the animation
|
|
76
|
-
*/
|
|
77
|
-
advance(deltaTime) {
|
|
78
|
-
var _a;
|
|
79
|
-
if (!this.isRunning)
|
|
80
|
-
return;
|
|
81
|
-
let completed = false;
|
|
82
|
-
if (this.duration && this.easing) {
|
|
83
|
-
this.currentTime += deltaTime;
|
|
84
|
-
const linearProgress = clamp(0, this.currentTime / this.duration, 1);
|
|
85
|
-
completed = linearProgress >= 1;
|
|
86
|
-
const easedProgress = completed ? 1 : this.easing(linearProgress);
|
|
87
|
-
this.value = this.from + (this.to - this.from) * easedProgress;
|
|
88
|
-
}
|
|
89
|
-
else if (this.lerp) {
|
|
90
|
-
this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
|
|
91
|
-
if (Math.round(this.value) === this.to) {
|
|
92
|
-
this.value = this.to;
|
|
93
|
-
completed = true;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
// If no easing or lerp, just jump to the end value
|
|
98
|
-
this.value = this.to;
|
|
99
|
-
completed = true;
|
|
100
|
-
}
|
|
101
|
-
if (completed) {
|
|
102
|
-
this.stop();
|
|
103
|
-
}
|
|
104
|
-
// Call the onUpdate callback with the current value and completed status
|
|
105
|
-
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, this.value, completed);
|
|
106
|
-
}
|
|
107
|
-
/** Stop the animation */
|
|
108
|
-
stop() {
|
|
109
|
-
this.isRunning = false;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Set up the animation from a starting value to an ending value
|
|
113
|
-
* with optional parameters for lerping, duration, easing, and onUpdate callback
|
|
114
|
-
*
|
|
115
|
-
* @param from - The starting value
|
|
116
|
-
* @param to - The ending value
|
|
117
|
-
* @param options - Options for the animation
|
|
118
|
-
*/
|
|
119
|
-
fromTo(from, to, { lerp, duration, easing, onStart, onUpdate }) {
|
|
120
|
-
this.from = this.value = from;
|
|
121
|
-
this.to = to;
|
|
122
|
-
this.lerp = lerp;
|
|
123
|
-
this.duration = duration;
|
|
124
|
-
this.easing = easing;
|
|
125
|
-
this.currentTime = 0;
|
|
126
|
-
this.isRunning = true;
|
|
127
|
-
onStart === null || onStart === void 0 ? void 0 : onStart();
|
|
128
|
-
this.onUpdate = onUpdate;
|
|
129
|
-
}
|
|
240
|
+
* @param event Event name
|
|
241
|
+
* @param callback Callback function
|
|
242
|
+
*/
|
|
243
|
+
on(event, callback) {
|
|
244
|
+
return this.emitter.on(event, callback);
|
|
130
245
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
246
|
+
/** Remove all event listeners and clean up */
|
|
247
|
+
destroy() {
|
|
248
|
+
this.emitter.destroy();
|
|
249
|
+
window.removeEventListener("resize", this.onWindowResize, false);
|
|
250
|
+
this.element.removeEventListener("wheel", this.onWheel, listenerOptions);
|
|
251
|
+
this.element.removeEventListener(
|
|
252
|
+
"touchstart",
|
|
253
|
+
this.onTouchStart,
|
|
254
|
+
listenerOptions
|
|
255
|
+
);
|
|
256
|
+
this.element.removeEventListener(
|
|
257
|
+
"touchmove",
|
|
258
|
+
this.onTouchMove,
|
|
259
|
+
listenerOptions
|
|
260
|
+
);
|
|
261
|
+
this.element.removeEventListener(
|
|
262
|
+
"touchend",
|
|
263
|
+
this.onTouchEnd,
|
|
264
|
+
listenerOptions
|
|
265
|
+
);
|
|
142
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Event handler for 'touchstart' event
|
|
269
|
+
*
|
|
270
|
+
* @param event Touch event
|
|
271
|
+
*/
|
|
272
|
+
onTouchStart = (event) => {
|
|
273
|
+
const { clientX, clientY } = event.targetTouches ? event.targetTouches[0] : event;
|
|
274
|
+
this.touchStart.x = clientX;
|
|
275
|
+
this.touchStart.y = clientY;
|
|
276
|
+
this.lastDelta = {
|
|
277
|
+
x: 0,
|
|
278
|
+
y: 0
|
|
279
|
+
};
|
|
280
|
+
this.emitter.emit("scroll", {
|
|
281
|
+
deltaX: 0,
|
|
282
|
+
deltaY: 0,
|
|
283
|
+
event
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
/** Event handler for 'touchmove' event */
|
|
287
|
+
onTouchMove = (event) => {
|
|
288
|
+
const { clientX, clientY } = event.targetTouches ? event.targetTouches[0] : event;
|
|
289
|
+
const deltaX = -(clientX - this.touchStart.x) * this.options.touchMultiplier;
|
|
290
|
+
const deltaY = -(clientY - this.touchStart.y) * this.options.touchMultiplier;
|
|
291
|
+
this.touchStart.x = clientX;
|
|
292
|
+
this.touchStart.y = clientY;
|
|
293
|
+
this.lastDelta = {
|
|
294
|
+
x: deltaX,
|
|
295
|
+
y: deltaY
|
|
296
|
+
};
|
|
297
|
+
this.emitter.emit("scroll", {
|
|
298
|
+
deltaX,
|
|
299
|
+
deltaY,
|
|
300
|
+
event
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
onTouchEnd = (event) => {
|
|
304
|
+
this.emitter.emit("scroll", {
|
|
305
|
+
deltaX: this.lastDelta.x,
|
|
306
|
+
deltaY: this.lastDelta.y,
|
|
307
|
+
event
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
/** Event handler for 'wheel' event */
|
|
311
|
+
onWheel = (event) => {
|
|
312
|
+
let { deltaX, deltaY, deltaMode } = event;
|
|
313
|
+
const multiplierX = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.width : 1;
|
|
314
|
+
const multiplierY = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.height : 1;
|
|
315
|
+
deltaX *= multiplierX;
|
|
316
|
+
deltaY *= multiplierY;
|
|
317
|
+
deltaX *= this.options.wheelMultiplier;
|
|
318
|
+
deltaY *= this.options.wheelMultiplier;
|
|
319
|
+
this.emitter.emit("scroll", { deltaX, deltaY, event });
|
|
320
|
+
};
|
|
321
|
+
onWindowResize = () => {
|
|
322
|
+
this.window = {
|
|
323
|
+
width: window.innerWidth,
|
|
324
|
+
height: window.innerHeight
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
};
|
|
143
328
|
|
|
329
|
+
// packages/core/src/lenis.ts
|
|
330
|
+
var Lenis = class {
|
|
331
|
+
_isScrolling = false;
|
|
332
|
+
// true when scroll is animating
|
|
333
|
+
_isStopped = false;
|
|
334
|
+
// true if user should not be able to scroll - enable/disable programmatically
|
|
335
|
+
_isLocked = false;
|
|
336
|
+
// same as isStopped but enabled/disabled when scroll reaches target
|
|
337
|
+
_preventNextNativeScrollEvent = false;
|
|
338
|
+
_resetVelocityTimeout = null;
|
|
339
|
+
/**
|
|
340
|
+
* Whether or not the user is touching the screen
|
|
341
|
+
*/
|
|
342
|
+
isTouching;
|
|
343
|
+
/**
|
|
344
|
+
* The time in ms since the lenis instance was created
|
|
345
|
+
*/
|
|
346
|
+
time = 0;
|
|
144
347
|
/**
|
|
145
|
-
*
|
|
348
|
+
* User data that will be forwarded through the scroll event
|
|
146
349
|
*
|
|
147
350
|
* @example
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
351
|
+
* lenis.scrollTo(100, {
|
|
352
|
+
* userData: {
|
|
353
|
+
* foo: 'bar'
|
|
354
|
+
* }
|
|
151
355
|
* })
|
|
152
356
|
*/
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
357
|
+
userData = {};
|
|
358
|
+
/**
|
|
359
|
+
* The last velocity of the scroll
|
|
360
|
+
*/
|
|
361
|
+
lastVelocity = 0;
|
|
362
|
+
/**
|
|
363
|
+
* The current velocity of the scroll
|
|
364
|
+
*/
|
|
365
|
+
velocity = 0;
|
|
366
|
+
/**
|
|
367
|
+
* The direction of the scroll
|
|
368
|
+
*/
|
|
369
|
+
direction = 0;
|
|
370
|
+
/**
|
|
371
|
+
* The options passed to the lenis instance
|
|
372
|
+
*/
|
|
373
|
+
options;
|
|
374
|
+
/**
|
|
375
|
+
* The target scroll value
|
|
376
|
+
*/
|
|
377
|
+
targetScroll;
|
|
378
|
+
/**
|
|
379
|
+
* The animated scroll value
|
|
380
|
+
*/
|
|
381
|
+
animatedScroll;
|
|
382
|
+
// These are instanciated here as they don't need information from the options
|
|
383
|
+
animate = new Animate();
|
|
384
|
+
emitter = new Emitter();
|
|
385
|
+
// These are instanciated in the constructor as they need information from the options
|
|
386
|
+
dimensions;
|
|
387
|
+
// This is not private because it's used in the Snap class
|
|
388
|
+
virtualScroll;
|
|
389
|
+
constructor({
|
|
390
|
+
wrapper = window,
|
|
391
|
+
content = document.documentElement,
|
|
392
|
+
eventsTarget = wrapper,
|
|
393
|
+
smoothWheel = true,
|
|
394
|
+
syncTouch = false,
|
|
395
|
+
syncTouchLerp = 0.075,
|
|
396
|
+
touchInertiaMultiplier = 35,
|
|
397
|
+
duration,
|
|
398
|
+
// in seconds
|
|
399
|
+
easing = (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
|
|
400
|
+
lerp: lerp2 = 0.1,
|
|
401
|
+
infinite = false,
|
|
402
|
+
orientation = "vertical",
|
|
403
|
+
// vertical, horizontal
|
|
404
|
+
gestureOrientation = "vertical",
|
|
405
|
+
// vertical, horizontal, both
|
|
406
|
+
touchMultiplier = 1,
|
|
407
|
+
wheelMultiplier = 1,
|
|
408
|
+
autoResize = true,
|
|
409
|
+
prevent,
|
|
410
|
+
virtualScroll,
|
|
411
|
+
__experimental__naiveDimensions = false
|
|
412
|
+
} = {}) {
|
|
413
|
+
window.lenisVersion = version;
|
|
414
|
+
if (!wrapper || wrapper === document.documentElement || wrapper === document.body) {
|
|
415
|
+
wrapper = window;
|
|
416
|
+
}
|
|
417
|
+
this.options = {
|
|
418
|
+
wrapper,
|
|
419
|
+
content,
|
|
420
|
+
eventsTarget,
|
|
421
|
+
smoothWheel,
|
|
422
|
+
syncTouch,
|
|
423
|
+
syncTouchLerp,
|
|
424
|
+
touchInertiaMultiplier,
|
|
425
|
+
duration,
|
|
426
|
+
easing,
|
|
427
|
+
lerp: lerp2,
|
|
428
|
+
infinite,
|
|
429
|
+
gestureOrientation,
|
|
430
|
+
orientation,
|
|
431
|
+
touchMultiplier,
|
|
432
|
+
wheelMultiplier,
|
|
433
|
+
autoResize,
|
|
434
|
+
prevent,
|
|
435
|
+
virtualScroll,
|
|
436
|
+
__experimental__naiveDimensions
|
|
437
|
+
};
|
|
438
|
+
this.dimensions = new Dimensions(wrapper, content, { autoResize });
|
|
439
|
+
this.updateClassName();
|
|
440
|
+
this.targetScroll = this.animatedScroll = this.actualScroll;
|
|
441
|
+
this.options.wrapper.addEventListener("scroll", this.onNativeScroll, false);
|
|
442
|
+
this.options.wrapper.addEventListener(
|
|
443
|
+
"pointerdown",
|
|
444
|
+
this.onPointerDown,
|
|
445
|
+
false
|
|
446
|
+
);
|
|
447
|
+
this.virtualScroll = new VirtualScroll(eventsTarget, {
|
|
448
|
+
touchMultiplier,
|
|
449
|
+
wheelMultiplier
|
|
450
|
+
});
|
|
451
|
+
this.virtualScroll.on("scroll", this.onVirtualScroll);
|
|
213
452
|
}
|
|
214
|
-
|
|
215
453
|
/**
|
|
216
|
-
*
|
|
217
|
-
* @example
|
|
218
|
-
* const emitter = new Emitter()
|
|
219
|
-
* emitter.on('event', (data) => {
|
|
220
|
-
* console.log(data)
|
|
221
|
-
* })
|
|
222
|
-
* emitter.emit('event', 'data')
|
|
454
|
+
* Destroy the lenis instance, remove all event listeners and clean up the class name
|
|
223
455
|
*/
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Add a callback to the event
|
|
242
|
-
* @param event Event name
|
|
243
|
-
* @param cb Callback function
|
|
244
|
-
* @returns Unsubscribe function
|
|
245
|
-
*/
|
|
246
|
-
on(event, cb) {
|
|
247
|
-
var _a;
|
|
248
|
-
// Add the callback to the event's callback list, or create a new list with the callback
|
|
249
|
-
((_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
|
|
250
|
-
// Return an unsubscribe function
|
|
251
|
-
return () => {
|
|
252
|
-
var _a;
|
|
253
|
-
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => cb !== i);
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Remove a callback from the event
|
|
258
|
-
* @param event Event name
|
|
259
|
-
* @param callback Callback function
|
|
260
|
-
*/
|
|
261
|
-
off(event, callback) {
|
|
262
|
-
var _a;
|
|
263
|
-
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => callback !== i);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Remove all event listeners and clean up
|
|
267
|
-
*/
|
|
268
|
-
destroy() {
|
|
269
|
-
this.events = {};
|
|
270
|
-
}
|
|
456
|
+
destroy() {
|
|
457
|
+
this.emitter.destroy();
|
|
458
|
+
this.options.wrapper.removeEventListener(
|
|
459
|
+
"scroll",
|
|
460
|
+
this.onNativeScroll,
|
|
461
|
+
false
|
|
462
|
+
);
|
|
463
|
+
this.options.wrapper.removeEventListener(
|
|
464
|
+
"pointerdown",
|
|
465
|
+
this.onPointerDown,
|
|
466
|
+
false
|
|
467
|
+
);
|
|
468
|
+
this.virtualScroll.destroy();
|
|
469
|
+
this.dimensions.destroy();
|
|
470
|
+
this.cleanUpClassName();
|
|
271
471
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const listenerOptions = { passive: false };
|
|
275
|
-
class VirtualScroll {
|
|
276
|
-
constructor(element, options = { wheelMultiplier: 1, touchMultiplier: 1 }) {
|
|
277
|
-
this.element = element;
|
|
278
|
-
this.options = options;
|
|
279
|
-
this.touchStart = {
|
|
280
|
-
x: 0,
|
|
281
|
-
y: 0,
|
|
282
|
-
};
|
|
283
|
-
this.lastDelta = {
|
|
284
|
-
x: 0,
|
|
285
|
-
y: 0,
|
|
286
|
-
};
|
|
287
|
-
this.window = {
|
|
288
|
-
width: 0,
|
|
289
|
-
height: 0,
|
|
290
|
-
};
|
|
291
|
-
this.emitter = new Emitter();
|
|
292
|
-
/**
|
|
293
|
-
* Event handler for 'touchstart' event
|
|
294
|
-
*
|
|
295
|
-
* @param event Touch event
|
|
296
|
-
*/
|
|
297
|
-
this.onTouchStart = (event) => {
|
|
298
|
-
// @ts-expect-error - event.targetTouches is not defined
|
|
299
|
-
const { clientX, clientY } = event.targetTouches
|
|
300
|
-
? event.targetTouches[0]
|
|
301
|
-
: event;
|
|
302
|
-
this.touchStart.x = clientX;
|
|
303
|
-
this.touchStart.y = clientY;
|
|
304
|
-
this.lastDelta = {
|
|
305
|
-
x: 0,
|
|
306
|
-
y: 0,
|
|
307
|
-
};
|
|
308
|
-
this.emitter.emit('scroll', {
|
|
309
|
-
deltaX: 0,
|
|
310
|
-
deltaY: 0,
|
|
311
|
-
event,
|
|
312
|
-
});
|
|
313
|
-
};
|
|
314
|
-
/** Event handler for 'touchmove' event */
|
|
315
|
-
this.onTouchMove = (event) => {
|
|
316
|
-
// @ts-expect-error - event.targetTouches is not defined
|
|
317
|
-
const { clientX, clientY } = event.targetTouches
|
|
318
|
-
? event.targetTouches[0]
|
|
319
|
-
: event;
|
|
320
|
-
const deltaX = -(clientX - this.touchStart.x) * this.options.touchMultiplier;
|
|
321
|
-
const deltaY = -(clientY - this.touchStart.y) * this.options.touchMultiplier;
|
|
322
|
-
this.touchStart.x = clientX;
|
|
323
|
-
this.touchStart.y = clientY;
|
|
324
|
-
this.lastDelta = {
|
|
325
|
-
x: deltaX,
|
|
326
|
-
y: deltaY,
|
|
327
|
-
};
|
|
328
|
-
this.emitter.emit('scroll', {
|
|
329
|
-
deltaX,
|
|
330
|
-
deltaY,
|
|
331
|
-
event,
|
|
332
|
-
});
|
|
333
|
-
};
|
|
334
|
-
this.onTouchEnd = (event) => {
|
|
335
|
-
this.emitter.emit('scroll', {
|
|
336
|
-
deltaX: this.lastDelta.x,
|
|
337
|
-
deltaY: this.lastDelta.y,
|
|
338
|
-
event,
|
|
339
|
-
});
|
|
340
|
-
};
|
|
341
|
-
/** Event handler for 'wheel' event */
|
|
342
|
-
this.onWheel = (event) => {
|
|
343
|
-
let { deltaX, deltaY, deltaMode } = event;
|
|
344
|
-
const multiplierX = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.width : 1;
|
|
345
|
-
const multiplierY = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.height : 1;
|
|
346
|
-
deltaX *= multiplierX;
|
|
347
|
-
deltaY *= multiplierY;
|
|
348
|
-
deltaX *= this.options.wheelMultiplier;
|
|
349
|
-
deltaY *= this.options.wheelMultiplier;
|
|
350
|
-
this.emitter.emit('scroll', { deltaX, deltaY, event });
|
|
351
|
-
};
|
|
352
|
-
this.onWindowResize = () => {
|
|
353
|
-
this.window = {
|
|
354
|
-
width: window.innerWidth,
|
|
355
|
-
height: window.innerHeight,
|
|
356
|
-
};
|
|
357
|
-
};
|
|
358
|
-
window.addEventListener('resize', this.onWindowResize, false);
|
|
359
|
-
this.onWindowResize();
|
|
360
|
-
this.element.addEventListener('wheel', this.onWheel, listenerOptions);
|
|
361
|
-
this.element.addEventListener('touchstart', this.onTouchStart, listenerOptions);
|
|
362
|
-
this.element.addEventListener('touchmove', this.onTouchMove, listenerOptions);
|
|
363
|
-
this.element.addEventListener('touchend', this.onTouchEnd, listenerOptions);
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Add an event listener for the given event and callback
|
|
367
|
-
*
|
|
368
|
-
* @param event Event name
|
|
369
|
-
* @param callback Callback function
|
|
370
|
-
*/
|
|
371
|
-
on(event, callback) {
|
|
372
|
-
return this.emitter.on(event, callback);
|
|
373
|
-
}
|
|
374
|
-
/** Remove all event listeners and clean up */
|
|
375
|
-
destroy() {
|
|
376
|
-
this.emitter.destroy();
|
|
377
|
-
window.removeEventListener('resize', this.onWindowResize, false);
|
|
378
|
-
this.element.removeEventListener('wheel', this.onWheel, listenerOptions);
|
|
379
|
-
this.element.removeEventListener('touchstart', this.onTouchStart, listenerOptions);
|
|
380
|
-
this.element.removeEventListener('touchmove', this.onTouchMove, listenerOptions);
|
|
381
|
-
this.element.removeEventListener('touchend', this.onTouchEnd, listenerOptions);
|
|
382
|
-
}
|
|
472
|
+
on(event, callback) {
|
|
473
|
+
return this.emitter.on(event, callback);
|
|
383
474
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
475
|
+
off(event, callback) {
|
|
476
|
+
return this.emitter.off(event, callback);
|
|
477
|
+
}
|
|
478
|
+
setScroll(scroll) {
|
|
479
|
+
if (this.isHorizontal) {
|
|
480
|
+
this.rootElement.scrollLeft = scroll;
|
|
481
|
+
} else {
|
|
482
|
+
this.rootElement.scrollTop = scroll;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
onPointerDown = (event) => {
|
|
486
|
+
if (event.button === 1) {
|
|
487
|
+
this.reset();
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
onVirtualScroll = (data) => {
|
|
491
|
+
if (typeof this.options.virtualScroll === "function" && this.options.virtualScroll(data) === false)
|
|
492
|
+
return;
|
|
493
|
+
const { deltaX, deltaY, event } = data;
|
|
494
|
+
this.emitter.emit("virtual-scroll", { deltaX, deltaY, event });
|
|
495
|
+
if (event.ctrlKey) return;
|
|
496
|
+
const isTouch = event.type.includes("touch");
|
|
497
|
+
const isWheel = event.type.includes("wheel");
|
|
498
|
+
this.isTouching = event.type === "touchstart" || event.type === "touchmove";
|
|
499
|
+
const isTapToStop = this.options.syncTouch && isTouch && event.type === "touchstart" && !this.isStopped && !this.isLocked;
|
|
500
|
+
if (isTapToStop) {
|
|
501
|
+
this.reset();
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const isClick = deltaX === 0 && deltaY === 0;
|
|
505
|
+
const isUnknownGesture = this.options.gestureOrientation === "vertical" && deltaY === 0 || this.options.gestureOrientation === "horizontal" && deltaX === 0;
|
|
506
|
+
if (isClick || isUnknownGesture) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
let composedPath = event.composedPath();
|
|
510
|
+
composedPath = composedPath.slice(0, composedPath.indexOf(this.rootElement));
|
|
511
|
+
const prevent = this.options.prevent;
|
|
512
|
+
if (!!composedPath.find(
|
|
513
|
+
(node) => node instanceof HTMLElement && (typeof prevent === "function" && prevent?.(node) || node.hasAttribute?.("data-lenis-prevent") || isTouch && node.hasAttribute?.("data-lenis-prevent-touch") || isWheel && node.hasAttribute?.("data-lenis-prevent-wheel") || node.classList?.contains("lenis") && !node.classList?.contains("lenis-stopped"))
|
|
514
|
+
// nested lenis instance
|
|
515
|
+
))
|
|
516
|
+
return;
|
|
517
|
+
if (this.isStopped || this.isLocked) {
|
|
518
|
+
event.preventDefault();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const isSmooth = this.options.syncTouch && isTouch || this.options.smoothWheel && isWheel;
|
|
522
|
+
if (!isSmooth) {
|
|
523
|
+
this.isScrolling = "native";
|
|
524
|
+
this.animate.stop();
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
event.preventDefault();
|
|
528
|
+
let delta = deltaY;
|
|
529
|
+
if (this.options.gestureOrientation === "both") {
|
|
530
|
+
delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
|
|
531
|
+
} else if (this.options.gestureOrientation === "horizontal") {
|
|
532
|
+
delta = deltaX;
|
|
533
|
+
}
|
|
534
|
+
const syncTouch = isTouch && this.options.syncTouch;
|
|
535
|
+
const isTouchEnd = isTouch && event.type === "touchend";
|
|
536
|
+
const hasTouchInertia = isTouchEnd && Math.abs(delta) > 5;
|
|
537
|
+
if (hasTouchInertia) {
|
|
538
|
+
delta = this.velocity * this.options.touchInertiaMultiplier;
|
|
539
|
+
}
|
|
540
|
+
this.scrollTo(this.targetScroll + delta, {
|
|
541
|
+
programmatic: false,
|
|
542
|
+
...syncTouch ? {
|
|
543
|
+
lerp: hasTouchInertia ? this.options.syncTouchLerp : 1
|
|
544
|
+
} : {
|
|
545
|
+
lerp: this.options.lerp,
|
|
546
|
+
duration: this.options.duration,
|
|
547
|
+
easing: this.options.easing
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Force lenis to recalculate the dimensions
|
|
553
|
+
*/
|
|
554
|
+
resize() {
|
|
555
|
+
this.dimensions.resize();
|
|
556
|
+
this.animatedScroll = this.targetScroll = this.actualScroll;
|
|
557
|
+
this.emit();
|
|
558
|
+
}
|
|
559
|
+
emit() {
|
|
560
|
+
this.emitter.emit("scroll", this);
|
|
561
|
+
}
|
|
562
|
+
onNativeScroll = () => {
|
|
563
|
+
if (this._resetVelocityTimeout !== null) {
|
|
564
|
+
clearTimeout(this._resetVelocityTimeout);
|
|
565
|
+
this._resetVelocityTimeout = null;
|
|
566
|
+
}
|
|
567
|
+
if (this._preventNextNativeScrollEvent) {
|
|
568
|
+
this._preventNextNativeScrollEvent = false;
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (this.isScrolling === false || this.isScrolling === "native") {
|
|
572
|
+
const lastScroll = this.animatedScroll;
|
|
573
|
+
this.animatedScroll = this.targetScroll = this.actualScroll;
|
|
574
|
+
this.lastVelocity = this.velocity;
|
|
575
|
+
this.velocity = this.animatedScroll - lastScroll;
|
|
576
|
+
this.direction = Math.sign(
|
|
577
|
+
this.animatedScroll - lastScroll
|
|
578
|
+
);
|
|
579
|
+
this.isScrolling = "native";
|
|
580
|
+
this.emit();
|
|
581
|
+
if (this.velocity !== 0) {
|
|
582
|
+
this._resetVelocityTimeout = setTimeout(() => {
|
|
583
|
+
this.lastVelocity = this.velocity;
|
|
417
584
|
this.velocity = 0;
|
|
418
|
-
/**
|
|
419
|
-
* The direction of the scroll
|
|
420
|
-
*/
|
|
421
|
-
this.direction = 0;
|
|
422
|
-
// These are instanciated here as they don't need information from the options
|
|
423
|
-
this.animate = new Animate();
|
|
424
|
-
this.emitter = new Emitter();
|
|
425
|
-
this.onPointerDown = (event) => {
|
|
426
|
-
if (event.button === 1) {
|
|
427
|
-
this.reset();
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
this.onVirtualScroll = (data) => {
|
|
431
|
-
if (typeof this.options.virtualScroll === 'function' &&
|
|
432
|
-
this.options.virtualScroll(data) === false)
|
|
433
|
-
return;
|
|
434
|
-
const { deltaX, deltaY, event } = data;
|
|
435
|
-
this.emitter.emit('virtual-scroll', { deltaX, deltaY, event });
|
|
436
|
-
// keep zoom feature
|
|
437
|
-
if (event.ctrlKey)
|
|
438
|
-
return;
|
|
439
|
-
const isTouch = event.type.includes('touch');
|
|
440
|
-
const isWheel = event.type.includes('wheel');
|
|
441
|
-
this.isTouching = event.type === 'touchstart' || event.type === 'touchmove';
|
|
442
|
-
// if (event.type === 'touchend') {
|
|
443
|
-
// console.log('touchend', this.scroll)
|
|
444
|
-
// // this.lastVelocity = this.velocity
|
|
445
|
-
// // this.velocity = 0
|
|
446
|
-
// // this.isScrolling = false
|
|
447
|
-
// this.emit({ type: 'touchend' })
|
|
448
|
-
// // alert('touchend')
|
|
449
|
-
// return
|
|
450
|
-
// }
|
|
451
|
-
const isTapToStop = this.options.syncTouch &&
|
|
452
|
-
isTouch &&
|
|
453
|
-
event.type === 'touchstart' &&
|
|
454
|
-
!this.isStopped &&
|
|
455
|
-
!this.isLocked;
|
|
456
|
-
if (isTapToStop) {
|
|
457
|
-
this.reset();
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
const isClick = deltaX === 0 && deltaY === 0; // click event
|
|
461
|
-
// const isPullToRefresh =
|
|
462
|
-
// this.options.gestureOrientation === 'vertical' &&
|
|
463
|
-
// this.scroll === 0 &&
|
|
464
|
-
// !this.options.infinite &&
|
|
465
|
-
// deltaY <= 5 // touch pull to refresh, not reliable yet
|
|
466
|
-
const isUnknownGesture = (this.options.gestureOrientation === 'vertical' && deltaY === 0) ||
|
|
467
|
-
(this.options.gestureOrientation === 'horizontal' && deltaX === 0);
|
|
468
|
-
if (isClick || isUnknownGesture) {
|
|
469
|
-
// console.log('prevent')
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
// catch if scrolling on nested scroll elements
|
|
473
|
-
let composedPath = event.composedPath();
|
|
474
|
-
composedPath = composedPath.slice(0, composedPath.indexOf(this.rootElement)); // remove parents elements
|
|
475
|
-
const prevent = this.options.prevent;
|
|
476
|
-
if (!!composedPath.find((node) => {
|
|
477
|
-
var _a, _b, _c, _d, _e;
|
|
478
|
-
return node instanceof HTMLElement &&
|
|
479
|
-
((typeof prevent === 'function' && (prevent === null || prevent === void 0 ? void 0 : prevent(node))) ||
|
|
480
|
-
((_a = node.hasAttribute) === null || _a === void 0 ? void 0 : _a.call(node, 'data-lenis-prevent')) ||
|
|
481
|
-
(isTouch && ((_b = node.hasAttribute) === null || _b === void 0 ? void 0 : _b.call(node, 'data-lenis-prevent-touch'))) ||
|
|
482
|
-
(isWheel && ((_c = node.hasAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'data-lenis-prevent-wheel'))) ||
|
|
483
|
-
(((_d = node.classList) === null || _d === void 0 ? void 0 : _d.contains('lenis')) &&
|
|
484
|
-
!((_e = node.classList) === null || _e === void 0 ? void 0 : _e.contains('lenis-stopped'))));
|
|
485
|
-
} // nested lenis instance
|
|
486
|
-
))
|
|
487
|
-
return;
|
|
488
|
-
if (this.isStopped || this.isLocked) {
|
|
489
|
-
event.preventDefault(); // this will stop forwarding the event to the parent, this is problematic
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
const isSmooth = (this.options.syncTouch && isTouch) ||
|
|
493
|
-
(this.options.smoothWheel && isWheel);
|
|
494
|
-
if (!isSmooth) {
|
|
495
|
-
this.isScrolling = 'native';
|
|
496
|
-
this.animate.stop();
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
event.preventDefault();
|
|
500
|
-
let delta = deltaY;
|
|
501
|
-
if (this.options.gestureOrientation === 'both') {
|
|
502
|
-
delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
|
|
503
|
-
}
|
|
504
|
-
else if (this.options.gestureOrientation === 'horizontal') {
|
|
505
|
-
delta = deltaX;
|
|
506
|
-
}
|
|
507
|
-
const syncTouch = isTouch && this.options.syncTouch;
|
|
508
|
-
const isTouchEnd = isTouch && event.type === 'touchend';
|
|
509
|
-
const hasTouchInertia = isTouchEnd && Math.abs(delta) > 5;
|
|
510
|
-
if (hasTouchInertia) {
|
|
511
|
-
delta = this.velocity * this.options.touchInertiaMultiplier;
|
|
512
|
-
}
|
|
513
|
-
this.scrollTo(this.targetScroll + delta, Object.assign({ programmatic: false }, (syncTouch
|
|
514
|
-
? {
|
|
515
|
-
lerp: hasTouchInertia ? this.options.syncTouchLerp : 1,
|
|
516
|
-
}
|
|
517
|
-
: {
|
|
518
|
-
lerp: this.options.lerp,
|
|
519
|
-
duration: this.options.duration,
|
|
520
|
-
easing: this.options.easing,
|
|
521
|
-
})));
|
|
522
|
-
};
|
|
523
|
-
this.onNativeScroll = () => {
|
|
524
|
-
if (this._resetVelocityTimeout !== null) {
|
|
525
|
-
clearTimeout(this._resetVelocityTimeout);
|
|
526
|
-
this._resetVelocityTimeout = null;
|
|
527
|
-
}
|
|
528
|
-
if (this._preventNextNativeScrollEvent) {
|
|
529
|
-
this._preventNextNativeScrollEvent = false;
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
if (this.isScrolling === false || this.isScrolling === 'native') {
|
|
533
|
-
const lastScroll = this.animatedScroll;
|
|
534
|
-
this.animatedScroll = this.targetScroll = this.actualScroll;
|
|
535
|
-
this.lastVelocity = this.velocity;
|
|
536
|
-
this.velocity = this.animatedScroll - lastScroll;
|
|
537
|
-
this.direction = Math.sign(this.animatedScroll - lastScroll);
|
|
538
|
-
this.isScrolling = 'native';
|
|
539
|
-
this.emit();
|
|
540
|
-
if (this.velocity !== 0) {
|
|
541
|
-
this._resetVelocityTimeout = setTimeout(() => {
|
|
542
|
-
this.lastVelocity = this.velocity;
|
|
543
|
-
this.velocity = 0;
|
|
544
|
-
this.isScrolling = false;
|
|
545
|
-
this.emit();
|
|
546
|
-
}, 400);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
// Set version
|
|
551
|
-
window.lenisVersion = version;
|
|
552
|
-
// Check if wrapper is html or body, fallback to window
|
|
553
|
-
if (!wrapper ||
|
|
554
|
-
wrapper === document.documentElement ||
|
|
555
|
-
wrapper === document.body) {
|
|
556
|
-
wrapper = window;
|
|
557
|
-
}
|
|
558
|
-
// Setup options
|
|
559
|
-
this.options = {
|
|
560
|
-
wrapper,
|
|
561
|
-
content,
|
|
562
|
-
eventsTarget,
|
|
563
|
-
smoothWheel,
|
|
564
|
-
syncTouch,
|
|
565
|
-
syncTouchLerp,
|
|
566
|
-
touchInertiaMultiplier,
|
|
567
|
-
duration,
|
|
568
|
-
easing,
|
|
569
|
-
lerp,
|
|
570
|
-
infinite,
|
|
571
|
-
gestureOrientation,
|
|
572
|
-
orientation,
|
|
573
|
-
touchMultiplier,
|
|
574
|
-
wheelMultiplier,
|
|
575
|
-
autoResize,
|
|
576
|
-
prevent,
|
|
577
|
-
virtualScroll,
|
|
578
|
-
__experimental__naiveDimensions,
|
|
579
|
-
};
|
|
580
|
-
// Setup dimensions instance
|
|
581
|
-
this.dimensions = new Dimensions(wrapper, content, { autoResize });
|
|
582
|
-
// Setup class name
|
|
583
|
-
this.updateClassName();
|
|
584
|
-
// Set the initial scroll value for all scroll information
|
|
585
|
-
this.targetScroll = this.animatedScroll = this.actualScroll;
|
|
586
|
-
// Add event listeners
|
|
587
|
-
this.options.wrapper.addEventListener('scroll', this.onNativeScroll, false);
|
|
588
|
-
this.options.wrapper.addEventListener('pointerdown', this.onPointerDown, false);
|
|
589
|
-
// Setup virtual scroll instance
|
|
590
|
-
this.virtualScroll = new VirtualScroll(eventsTarget, {
|
|
591
|
-
touchMultiplier,
|
|
592
|
-
wheelMultiplier,
|
|
593
|
-
});
|
|
594
|
-
this.virtualScroll.on('scroll', this.onVirtualScroll);
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Destroy the lenis instance, remove all event listeners and clean up the class name
|
|
598
|
-
*/
|
|
599
|
-
destroy() {
|
|
600
|
-
this.emitter.destroy();
|
|
601
|
-
this.options.wrapper.removeEventListener('scroll', this.onNativeScroll, false);
|
|
602
|
-
this.options.wrapper.removeEventListener('pointerdown', this.onPointerDown, false);
|
|
603
|
-
this.virtualScroll.destroy();
|
|
604
|
-
this.dimensions.destroy();
|
|
605
|
-
this.cleanUpClassName();
|
|
606
|
-
}
|
|
607
|
-
on(event, callback) {
|
|
608
|
-
return this.emitter.on(event, callback);
|
|
609
|
-
}
|
|
610
|
-
off(event, callback) {
|
|
611
|
-
return this.emitter.off(event, callback);
|
|
612
|
-
}
|
|
613
|
-
setScroll(scroll) {
|
|
614
|
-
// apply scroll value immediately
|
|
615
|
-
if (this.isHorizontal) {
|
|
616
|
-
this.rootElement.scrollLeft = scroll;
|
|
617
|
-
}
|
|
618
|
-
else {
|
|
619
|
-
this.rootElement.scrollTop = scroll;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Force lenis to recalculate the dimensions
|
|
624
|
-
*/
|
|
625
|
-
resize() {
|
|
626
|
-
this.dimensions.resize();
|
|
627
|
-
this.animatedScroll = this.targetScroll = this.actualScroll;
|
|
628
|
-
this.emit();
|
|
629
|
-
}
|
|
630
|
-
emit() {
|
|
631
|
-
this.emitter.emit('scroll', this);
|
|
632
|
-
}
|
|
633
|
-
reset() {
|
|
634
|
-
this.isLocked = false;
|
|
635
585
|
this.isScrolling = false;
|
|
636
|
-
this.
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
586
|
+
this.emit();
|
|
587
|
+
}, 400);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
reset() {
|
|
592
|
+
this.isLocked = false;
|
|
593
|
+
this.isScrolling = false;
|
|
594
|
+
this.animatedScroll = this.targetScroll = this.actualScroll;
|
|
595
|
+
this.lastVelocity = this.velocity = 0;
|
|
596
|
+
this.animate.stop();
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Start lenis scroll after it has been stopped
|
|
600
|
+
*/
|
|
601
|
+
start() {
|
|
602
|
+
if (!this.isStopped) return;
|
|
603
|
+
this.isStopped = false;
|
|
604
|
+
this.reset();
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Stop lenis scroll
|
|
608
|
+
*/
|
|
609
|
+
stop() {
|
|
610
|
+
if (this.isStopped) return;
|
|
611
|
+
this.isStopped = true;
|
|
612
|
+
this.animate.stop();
|
|
613
|
+
this.reset();
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* RequestAnimationFrame for lenis
|
|
617
|
+
*
|
|
618
|
+
* @param time The time in ms from an external clock like `requestAnimationFrame` or Tempus
|
|
619
|
+
*/
|
|
620
|
+
raf(time) {
|
|
621
|
+
const deltaTime = time - (this.time || time);
|
|
622
|
+
this.time = time;
|
|
623
|
+
this.animate.advance(deltaTime * 1e-3);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Scroll to a target value
|
|
627
|
+
*
|
|
628
|
+
* @param target The target value to scroll to
|
|
629
|
+
* @param options The options for the scroll
|
|
630
|
+
*
|
|
631
|
+
* @example
|
|
632
|
+
* lenis.scrollTo(100, {
|
|
633
|
+
* offset: 100,
|
|
634
|
+
* duration: 1,
|
|
635
|
+
* easing: (t) => 1 - Math.cos((t * Math.PI) / 2),
|
|
636
|
+
* lerp: 0.1,
|
|
637
|
+
* onStart: () => {
|
|
638
|
+
* console.log('onStart')
|
|
639
|
+
* },
|
|
640
|
+
* onComplete: () => {
|
|
641
|
+
* console.log('onComplete')
|
|
642
|
+
* },
|
|
643
|
+
* })
|
|
644
|
+
*/
|
|
645
|
+
scrollTo(target, {
|
|
646
|
+
offset = 0,
|
|
647
|
+
immediate = false,
|
|
648
|
+
lock = false,
|
|
649
|
+
duration = this.options.duration,
|
|
650
|
+
easing = this.options.easing,
|
|
651
|
+
lerp: lerp2 = this.options.lerp,
|
|
652
|
+
onStart,
|
|
653
|
+
onComplete,
|
|
654
|
+
force = false,
|
|
655
|
+
// scroll even if stopped
|
|
656
|
+
programmatic = true,
|
|
657
|
+
// called from outside of the class
|
|
658
|
+
userData
|
|
659
|
+
} = {}) {
|
|
660
|
+
if ((this.isStopped || this.isLocked) && !force) return;
|
|
661
|
+
if (typeof target === "string" && ["top", "left", "start"].includes(target)) {
|
|
662
|
+
target = 0;
|
|
663
|
+
} else if (typeof target === "string" && ["bottom", "right", "end"].includes(target)) {
|
|
664
|
+
target = this.limit;
|
|
665
|
+
} else {
|
|
666
|
+
let node;
|
|
667
|
+
if (typeof target === "string") {
|
|
668
|
+
node = document.querySelector(target);
|
|
669
|
+
} else if (target instanceof HTMLElement && target?.nodeType) {
|
|
670
|
+
node = target;
|
|
671
|
+
}
|
|
672
|
+
if (node) {
|
|
673
|
+
if (this.options.wrapper !== window) {
|
|
674
|
+
const wrapperRect = this.rootElement.getBoundingClientRect();
|
|
675
|
+
offset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
|
|
676
|
+
}
|
|
677
|
+
const rect = node.getBoundingClientRect();
|
|
678
|
+
target = (this.isHorizontal ? rect.left : rect.top) + this.animatedScroll;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (typeof target !== "number") return;
|
|
682
|
+
target += offset;
|
|
683
|
+
target = Math.round(target);
|
|
684
|
+
if (this.options.infinite) {
|
|
685
|
+
if (programmatic) {
|
|
686
|
+
this.targetScroll = this.animatedScroll = this.scroll;
|
|
687
|
+
}
|
|
688
|
+
} else {
|
|
689
|
+
target = clamp(0, target, this.limit);
|
|
690
|
+
}
|
|
691
|
+
if (target === this.targetScroll) {
|
|
692
|
+
onStart?.(this);
|
|
693
|
+
onComplete?.(this);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
this.userData = userData ?? {};
|
|
697
|
+
if (immediate) {
|
|
698
|
+
this.animatedScroll = this.targetScroll = target;
|
|
699
|
+
this.setScroll(this.scroll);
|
|
700
|
+
this.reset();
|
|
701
|
+
this.preventNextNativeScrollEvent();
|
|
702
|
+
this.emit();
|
|
703
|
+
onComplete?.(this);
|
|
704
|
+
this.userData = {};
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (!programmatic) {
|
|
708
|
+
this.targetScroll = target;
|
|
709
|
+
}
|
|
710
|
+
this.animate.fromTo(this.animatedScroll, target, {
|
|
711
|
+
duration,
|
|
712
|
+
easing,
|
|
713
|
+
lerp: lerp2,
|
|
714
|
+
onStart: () => {
|
|
715
|
+
if (lock) this.isLocked = true;
|
|
716
|
+
this.isScrolling = "smooth";
|
|
717
|
+
onStart?.(this);
|
|
718
|
+
},
|
|
719
|
+
onUpdate: (value, completed) => {
|
|
720
|
+
this.isScrolling = "smooth";
|
|
721
|
+
this.lastVelocity = this.velocity;
|
|
722
|
+
this.velocity = value - this.animatedScroll;
|
|
723
|
+
this.direction = Math.sign(this.velocity);
|
|
724
|
+
this.animatedScroll = value;
|
|
725
|
+
this.setScroll(this.scroll);
|
|
726
|
+
if (programmatic) {
|
|
727
|
+
this.targetScroll = value;
|
|
728
|
+
}
|
|
729
|
+
if (!completed) this.emit();
|
|
730
|
+
if (completed) {
|
|
657
731
|
this.reset();
|
|
732
|
+
this.emit();
|
|
733
|
+
onComplete?.(this);
|
|
734
|
+
this.userData = {};
|
|
735
|
+
this.preventNextNativeScrollEvent();
|
|
736
|
+
}
|
|
658
737
|
}
|
|
659
|
-
|
|
660
|
-
* RequestAnimationFrame for lenis
|
|
661
|
-
*
|
|
662
|
-
* @param time The time in ms from an external clock like `requestAnimationFrame` or Tempus
|
|
663
|
-
*/
|
|
664
|
-
raf(time) {
|
|
665
|
-
const deltaTime = time - (this.time || time);
|
|
666
|
-
this.time = time;
|
|
667
|
-
this.animate.advance(deltaTime * 0.001);
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Scroll to a target value
|
|
671
|
-
*
|
|
672
|
-
* @param target The target value to scroll to
|
|
673
|
-
* @param options The options for the scroll
|
|
674
|
-
*
|
|
675
|
-
* @example
|
|
676
|
-
* lenis.scrollTo(100, {
|
|
677
|
-
* offset: 100,
|
|
678
|
-
* duration: 1,
|
|
679
|
-
* easing: (t) => 1 - Math.cos((t * Math.PI) / 2),
|
|
680
|
-
* lerp: 0.1,
|
|
681
|
-
* onStart: () => {
|
|
682
|
-
* console.log('onStart')
|
|
683
|
-
* },
|
|
684
|
-
* onComplete: () => {
|
|
685
|
-
* console.log('onComplete')
|
|
686
|
-
* },
|
|
687
|
-
* })
|
|
688
|
-
*/
|
|
689
|
-
scrollTo(target, { offset = 0, immediate = false, lock = false, duration = this.options.duration, easing = this.options.easing, lerp = this.options.lerp, onStart, onComplete, force = false, // scroll even if stopped
|
|
690
|
-
programmatic = true, // called from outside of the class
|
|
691
|
-
userData, } = {}) {
|
|
692
|
-
if ((this.isStopped || this.isLocked) && !force)
|
|
693
|
-
return;
|
|
694
|
-
// keywords
|
|
695
|
-
if (typeof target === 'string' &&
|
|
696
|
-
['top', 'left', 'start'].includes(target)) {
|
|
697
|
-
target = 0;
|
|
698
|
-
}
|
|
699
|
-
else if (typeof target === 'string' &&
|
|
700
|
-
['bottom', 'right', 'end'].includes(target)) {
|
|
701
|
-
target = this.limit;
|
|
702
|
-
}
|
|
703
|
-
else {
|
|
704
|
-
let node;
|
|
705
|
-
if (typeof target === 'string') {
|
|
706
|
-
// CSS selector
|
|
707
|
-
node = document.querySelector(target);
|
|
708
|
-
}
|
|
709
|
-
else if (target instanceof HTMLElement && (target === null || target === void 0 ? void 0 : target.nodeType)) {
|
|
710
|
-
// Node element
|
|
711
|
-
node = target;
|
|
712
|
-
}
|
|
713
|
-
if (node) {
|
|
714
|
-
if (this.options.wrapper !== window) {
|
|
715
|
-
// nested scroll offset correction
|
|
716
|
-
const wrapperRect = this.rootElement.getBoundingClientRect();
|
|
717
|
-
offset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
|
|
718
|
-
}
|
|
719
|
-
const rect = node.getBoundingClientRect();
|
|
720
|
-
target =
|
|
721
|
-
(this.isHorizontal ? rect.left : rect.top) + this.animatedScroll;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
if (typeof target !== 'number')
|
|
725
|
-
return;
|
|
726
|
-
target += offset;
|
|
727
|
-
target = Math.round(target);
|
|
728
|
-
if (this.options.infinite) {
|
|
729
|
-
if (programmatic) {
|
|
730
|
-
this.targetScroll = this.animatedScroll = this.scroll;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
target = clamp(0, target, this.limit);
|
|
735
|
-
}
|
|
736
|
-
if (target === this.targetScroll) {
|
|
737
|
-
onStart === null || onStart === void 0 ? void 0 : onStart(this);
|
|
738
|
-
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
this.userData = userData !== null && userData !== void 0 ? userData : {};
|
|
742
|
-
if (immediate) {
|
|
743
|
-
this.animatedScroll = this.targetScroll = target;
|
|
744
|
-
this.setScroll(this.scroll);
|
|
745
|
-
this.reset();
|
|
746
|
-
this.preventNextNativeScrollEvent();
|
|
747
|
-
this.emit();
|
|
748
|
-
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
|
|
749
|
-
this.userData = {};
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
if (!programmatic) {
|
|
753
|
-
this.targetScroll = target;
|
|
754
|
-
}
|
|
755
|
-
this.animate.fromTo(this.animatedScroll, target, {
|
|
756
|
-
duration,
|
|
757
|
-
easing,
|
|
758
|
-
lerp,
|
|
759
|
-
onStart: () => {
|
|
760
|
-
// started
|
|
761
|
-
if (lock)
|
|
762
|
-
this.isLocked = true;
|
|
763
|
-
this.isScrolling = 'smooth';
|
|
764
|
-
onStart === null || onStart === void 0 ? void 0 : onStart(this);
|
|
765
|
-
},
|
|
766
|
-
onUpdate: (value, completed) => {
|
|
767
|
-
this.isScrolling = 'smooth';
|
|
768
|
-
// updated
|
|
769
|
-
this.lastVelocity = this.velocity;
|
|
770
|
-
this.velocity = value - this.animatedScroll;
|
|
771
|
-
this.direction = Math.sign(this.velocity);
|
|
772
|
-
this.animatedScroll = value;
|
|
773
|
-
this.setScroll(this.scroll);
|
|
774
|
-
if (programmatic) {
|
|
775
|
-
// wheel during programmatic should stop it
|
|
776
|
-
this.targetScroll = value;
|
|
777
|
-
}
|
|
778
|
-
if (!completed)
|
|
779
|
-
this.emit();
|
|
780
|
-
if (completed) {
|
|
781
|
-
this.reset();
|
|
782
|
-
this.emit();
|
|
783
|
-
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
|
|
784
|
-
this.userData = {};
|
|
785
|
-
// avoid emitting event twice
|
|
786
|
-
this.preventNextNativeScrollEvent();
|
|
787
|
-
}
|
|
788
|
-
},
|
|
789
|
-
});
|
|
790
|
-
}
|
|
791
|
-
preventNextNativeScrollEvent() {
|
|
792
|
-
this._preventNextNativeScrollEvent = true;
|
|
793
|
-
requestAnimationFrame(() => {
|
|
794
|
-
this._preventNextNativeScrollEvent = false;
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
/**
|
|
798
|
-
* The root element on which lenis is instanced
|
|
799
|
-
*/
|
|
800
|
-
get rootElement() {
|
|
801
|
-
return (this.options.wrapper === window
|
|
802
|
-
? document.documentElement
|
|
803
|
-
: this.options.wrapper);
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* The limit which is the maximum scroll value
|
|
807
|
-
*/
|
|
808
|
-
get limit() {
|
|
809
|
-
if (this.options.__experimental__naiveDimensions) {
|
|
810
|
-
if (this.isHorizontal) {
|
|
811
|
-
return this.rootElement.scrollWidth - this.rootElement.clientWidth;
|
|
812
|
-
}
|
|
813
|
-
else {
|
|
814
|
-
return this.rootElement.scrollHeight - this.rootElement.clientHeight;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
else {
|
|
818
|
-
return this.dimensions.limit[this.isHorizontal ? 'x' : 'y'];
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Whether or not the scroll is horizontal
|
|
823
|
-
*/
|
|
824
|
-
get isHorizontal() {
|
|
825
|
-
return this.options.orientation === 'horizontal';
|
|
826
|
-
}
|
|
827
|
-
/**
|
|
828
|
-
* The actual scroll value
|
|
829
|
-
*/
|
|
830
|
-
get actualScroll() {
|
|
831
|
-
// value browser takes into account
|
|
832
|
-
return this.isHorizontal
|
|
833
|
-
? this.rootElement.scrollLeft
|
|
834
|
-
: this.rootElement.scrollTop;
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* The current scroll value
|
|
838
|
-
*/
|
|
839
|
-
get scroll() {
|
|
840
|
-
return this.options.infinite
|
|
841
|
-
? modulo(this.animatedScroll, this.limit)
|
|
842
|
-
: this.animatedScroll;
|
|
843
|
-
}
|
|
844
|
-
/**
|
|
845
|
-
* The progress of the scroll relative to the limit
|
|
846
|
-
*/
|
|
847
|
-
get progress() {
|
|
848
|
-
// avoid progress to be NaN
|
|
849
|
-
return this.limit === 0 ? 1 : this.scroll / this.limit;
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Current scroll state
|
|
853
|
-
*/
|
|
854
|
-
get isScrolling() {
|
|
855
|
-
return this._isScrolling;
|
|
856
|
-
}
|
|
857
|
-
set isScrolling(value) {
|
|
858
|
-
if (this._isScrolling !== value) {
|
|
859
|
-
this._isScrolling = value;
|
|
860
|
-
this.updateClassName();
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Check if lenis is stopped
|
|
865
|
-
*/
|
|
866
|
-
get isStopped() {
|
|
867
|
-
return this._isStopped;
|
|
868
|
-
}
|
|
869
|
-
set isStopped(value) {
|
|
870
|
-
if (this._isStopped !== value) {
|
|
871
|
-
this._isStopped = value;
|
|
872
|
-
this.updateClassName();
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
/**
|
|
876
|
-
* Check if lenis is locked
|
|
877
|
-
*/
|
|
878
|
-
get isLocked() {
|
|
879
|
-
return this._isLocked;
|
|
880
|
-
}
|
|
881
|
-
set isLocked(value) {
|
|
882
|
-
if (this._isLocked !== value) {
|
|
883
|
-
this._isLocked = value;
|
|
884
|
-
this.updateClassName();
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Check if lenis is smooth scrolling
|
|
889
|
-
*/
|
|
890
|
-
get isSmooth() {
|
|
891
|
-
return this.isScrolling === 'smooth';
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* The class name applied to the wrapper element
|
|
895
|
-
*/
|
|
896
|
-
get className() {
|
|
897
|
-
let className = 'lenis';
|
|
898
|
-
if (this.isStopped)
|
|
899
|
-
className += ' lenis-stopped';
|
|
900
|
-
if (this.isLocked)
|
|
901
|
-
className += ' lenis-locked';
|
|
902
|
-
if (this.isScrolling)
|
|
903
|
-
className += ' lenis-scrolling';
|
|
904
|
-
if (this.isScrolling === 'smooth')
|
|
905
|
-
className += ' lenis-smooth';
|
|
906
|
-
return className;
|
|
907
|
-
}
|
|
908
|
-
updateClassName() {
|
|
909
|
-
this.cleanUpClassName();
|
|
910
|
-
this.rootElement.className =
|
|
911
|
-
`${this.rootElement.className} ${this.className}`.trim();
|
|
912
|
-
}
|
|
913
|
-
cleanUpClassName() {
|
|
914
|
-
this.rootElement.className = this.rootElement.className
|
|
915
|
-
.replace(/lenis(-\w+)?/g, '')
|
|
916
|
-
.trim();
|
|
917
|
-
}
|
|
738
|
+
});
|
|
918
739
|
}
|
|
740
|
+
preventNextNativeScrollEvent() {
|
|
741
|
+
this._preventNextNativeScrollEvent = true;
|
|
742
|
+
requestAnimationFrame(() => {
|
|
743
|
+
this._preventNextNativeScrollEvent = false;
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* The root element on which lenis is instanced
|
|
748
|
+
*/
|
|
749
|
+
get rootElement() {
|
|
750
|
+
return this.options.wrapper === window ? document.documentElement : this.options.wrapper;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* The limit which is the maximum scroll value
|
|
754
|
+
*/
|
|
755
|
+
get limit() {
|
|
756
|
+
if (this.options.__experimental__naiveDimensions) {
|
|
757
|
+
if (this.isHorizontal) {
|
|
758
|
+
return this.rootElement.scrollWidth - this.rootElement.clientWidth;
|
|
759
|
+
} else {
|
|
760
|
+
return this.rootElement.scrollHeight - this.rootElement.clientHeight;
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
return this.dimensions.limit[this.isHorizontal ? "x" : "y"];
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Whether or not the scroll is horizontal
|
|
768
|
+
*/
|
|
769
|
+
get isHorizontal() {
|
|
770
|
+
return this.options.orientation === "horizontal";
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* The actual scroll value
|
|
774
|
+
*/
|
|
775
|
+
get actualScroll() {
|
|
776
|
+
return this.isHorizontal ? this.rootElement.scrollLeft : this.rootElement.scrollTop;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* The current scroll value
|
|
780
|
+
*/
|
|
781
|
+
get scroll() {
|
|
782
|
+
return this.options.infinite ? modulo(this.animatedScroll, this.limit) : this.animatedScroll;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* The progress of the scroll relative to the limit
|
|
786
|
+
*/
|
|
787
|
+
get progress() {
|
|
788
|
+
return this.limit === 0 ? 1 : this.scroll / this.limit;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Current scroll state
|
|
792
|
+
*/
|
|
793
|
+
get isScrolling() {
|
|
794
|
+
return this._isScrolling;
|
|
795
|
+
}
|
|
796
|
+
set isScrolling(value) {
|
|
797
|
+
if (this._isScrolling !== value) {
|
|
798
|
+
this._isScrolling = value;
|
|
799
|
+
this.updateClassName();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Check if lenis is stopped
|
|
804
|
+
*/
|
|
805
|
+
get isStopped() {
|
|
806
|
+
return this._isStopped;
|
|
807
|
+
}
|
|
808
|
+
set isStopped(value) {
|
|
809
|
+
if (this._isStopped !== value) {
|
|
810
|
+
this._isStopped = value;
|
|
811
|
+
this.updateClassName();
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Check if lenis is locked
|
|
816
|
+
*/
|
|
817
|
+
get isLocked() {
|
|
818
|
+
return this._isLocked;
|
|
819
|
+
}
|
|
820
|
+
set isLocked(value) {
|
|
821
|
+
if (this._isLocked !== value) {
|
|
822
|
+
this._isLocked = value;
|
|
823
|
+
this.updateClassName();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Check if lenis is smooth scrolling
|
|
828
|
+
*/
|
|
829
|
+
get isSmooth() {
|
|
830
|
+
return this.isScrolling === "smooth";
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* The class name applied to the wrapper element
|
|
834
|
+
*/
|
|
835
|
+
get className() {
|
|
836
|
+
let className = "lenis";
|
|
837
|
+
if (this.isStopped) className += " lenis-stopped";
|
|
838
|
+
if (this.isLocked) className += " lenis-locked";
|
|
839
|
+
if (this.isScrolling) className += " lenis-scrolling";
|
|
840
|
+
if (this.isScrolling === "smooth") className += " lenis-smooth";
|
|
841
|
+
return className;
|
|
842
|
+
}
|
|
843
|
+
updateClassName() {
|
|
844
|
+
this.cleanUpClassName();
|
|
845
|
+
this.rootElement.className = `${this.rootElement.className} ${this.className}`.trim();
|
|
846
|
+
}
|
|
847
|
+
cleanUpClassName() {
|
|
848
|
+
this.rootElement.className = this.rootElement.className.replace(/lenis(-\w+)?/g, "").trim();
|
|
849
|
+
}
|
|
850
|
+
};
|
|
919
851
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
//# sourceMappingURL=lenis.js.map
|
|
852
|
+
// packages/core/browser.ts
|
|
853
|
+
globalThis.Lenis = Lenis;
|
|
854
|
+
//# sourceMappingURL=lenis.js.map
|