New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

lenis

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lenis - npm Package Compare versions

Comparing version 1.1.12 to 1.1.13

6

dist/lenis.d.ts

@@ -229,3 +229,7 @@ /**

declare class Lenis {
#private;
private _isScrolling;
private _isStopped;
private _isLocked;
private _preventNextNativeScrollEvent;
private _resetVelocityTimeout;
/**

@@ -232,0 +236,0 @@ * Whether or not the user is touching the screen

1859

dist/lenis.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Lenis = factory());
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Lenis = factory());
})(this, (function () { 'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
var version = "1.1.13";
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
/**
* Clamp a value between a minimum and maximum value
*
* @param min Minimum value
* @param input Value to clamp
* @param max Maximum value
* @returns Clamped value
*/
function clamp(min, input, max) {
return Math.max(min, Math.min(input, max));
}
/**
* Linearly interpolate between two values using an amount (0 <= t <= 1)
*
* @param x First value
* @param y Second value
* @param t Amount to interpolate (0 <= t <= 1)
* @returns Interpolated value
*/
function lerp(x, y, t) {
return (1 - t) * x + t * y;
}
/**
* Damp a value over time using a damping factor
* {@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}
*
* @param x Initial value
* @param y Target value
* @param lambda Damping factor
* @param dt Time elapsed since the last update
* @returns Damped value
*/
function damp(x, y, lambda, deltaTime) {
return lerp(x, y, 1 - Math.exp(-lambda * deltaTime));
}
/**
* Calculate the modulo of the dividend and divisor while keeping the result within the same sign as the divisor
* {@link https://anguscroll.com/just/just-modulo}
*
* @param n Dividend
* @param d Divisor
* @returns Modulo
*/
function modulo(n, d) {
return ((n % d) + d) % d;
}
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
/**
* Animate class to handle value animations with lerping or easing
*
* @example
* const animate = new Animate()
* animate.fromTo(0, 100, { duration: 1, easing: (t) => t })
* animate.advance(0.5) // 50
*/
class Animate {
constructor() {
this.isRunning = false;
this.value = 0;
this.from = 0;
this.to = 0;
this.currentTime = 0;
}
/**
* Advance the animation by the given delta time
*
* @param deltaTime - The time in seconds to advance the animation
*/
advance(deltaTime) {
var _a;
if (!this.isRunning)
return;
let completed = false;
if (this.duration && this.easing) {
this.currentTime += deltaTime;
const linearProgress = clamp(0, this.currentTime / this.duration, 1);
completed = linearProgress >= 1;
const easedProgress = completed ? 1 : this.easing(linearProgress);
this.value = this.from + (this.to - this.from) * easedProgress;
}
else if (this.lerp) {
this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
if (Math.round(this.value) === this.to) {
this.value = this.to;
completed = true;
}
}
else {
// If no easing or lerp, just jump to the end value
this.value = this.to;
completed = true;
}
if (completed) {
this.stop();
}
// Call the onUpdate callback with the current value and completed status
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, this.value, completed);
}
/** Stop the animation */
stop() {
this.isRunning = false;
}
/**
* Set up the animation from a starting value to an ending value
* with optional parameters for lerping, duration, easing, and onUpdate callback
*
* @param from - The starting value
* @param to - The ending value
* @param options - Options for the animation
*/
fromTo(from, to, { lerp, duration, easing, onStart, onUpdate }) {
this.from = this.value = from;
this.to = to;
this.lerp = lerp;
this.duration = duration;
this.easing = easing;
this.currentTime = 0;
this.isRunning = true;
onStart === null || onStart === void 0 ? void 0 : onStart();
this.onUpdate = onUpdate;
}
}
function debounce(callback, delay) {
let timer;
return function (...args) {
let context = this;
clearTimeout(timer);
timer = setTimeout(() => {
timer = undefined;
callback.apply(context, args);
}, delay);
};
}
function __classPrivateFieldGet(receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}
/**
* Dimensions class to handle the size of the content and wrapper
*
* @example
* const dimensions = new Dimensions(wrapper, content)
* dimensions.on('resize', (e) => {
* console.log(e.width, e.height)
* })
*/
class Dimensions {
constructor(wrapper, content, { autoResize = true, debounce: debounceValue = 250 } = {}) {
this.wrapper = wrapper;
this.content = content;
this.width = 0;
this.height = 0;
this.scrollHeight = 0;
this.scrollWidth = 0;
this.resize = () => {
this.onWrapperResize();
this.onContentResize();
};
this.onWrapperResize = () => {
if (this.wrapper instanceof Window) {
this.width = window.innerWidth;
this.height = window.innerHeight;
}
else {
this.width = this.wrapper.clientWidth;
this.height = this.wrapper.clientHeight;
}
};
this.onContentResize = () => {
if (this.wrapper instanceof Window) {
this.scrollHeight = this.content.scrollHeight;
this.scrollWidth = this.content.scrollWidth;
}
else {
this.scrollHeight = this.wrapper.scrollHeight;
this.scrollWidth = this.wrapper.scrollWidth;
}
};
if (autoResize) {
this.debouncedResize = debounce(this.resize, debounceValue);
if (this.wrapper instanceof Window) {
window.addEventListener('resize', this.debouncedResize, false);
}
else {
this.wrapperResizeObserver = new ResizeObserver(this.debouncedResize);
this.wrapperResizeObserver.observe(this.wrapper);
}
this.contentResizeObserver = new ResizeObserver(this.debouncedResize);
this.contentResizeObserver.observe(this.content);
}
this.resize();
}
destroy() {
var _a, _b;
(_a = this.wrapperResizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
(_b = this.contentResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
if (this.wrapper === window && this.debouncedResize) {
window.removeEventListener('resize', this.debouncedResize, false);
}
}
get limit() {
return {
x: this.scrollWidth - this.width,
y: this.scrollHeight - this.height,
};
}
}
function __classPrivateFieldSet(receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
}
/**
* Emitter class to handle events
* @example
* const emitter = new Emitter()
* emitter.on('event', (data) => {
* console.log(data)
* })
* emitter.emit('event', 'data')
*/
class Emitter {
constructor() {
this.events = {};
}
/**
* Emit an event with the given data
* @param event Event name
* @param args Data to pass to the event handlers
*/
emit(event, ...args) {
var _a;
let callbacks = this.events[event] || [];
for (let i = 0, length = callbacks.length; i < length; i++) {
(_a = callbacks[i]) === null || _a === void 0 ? void 0 : _a.call(callbacks, ...args);
}
}
/**
* Add a callback to the event
* @param event Event name
* @param cb Callback function
* @returns Unsubscribe function
*/
on(event, cb) {
var _a;
// Add the callback to the event's callback list, or create a new list with the callback
((_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
// Return an unsubscribe function
return () => {
var _a;
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => cb !== i);
};
}
/**
* Remove a callback from the event
* @param event Event name
* @param callback Callback function
*/
off(event, callback) {
var _a;
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => callback !== i);
}
/**
* Remove all event listeners and clean up
*/
destroy() {
this.events = {};
}
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
const LINE_HEIGHT = 100 / 6;
const listenerOptions = { passive: false };
class VirtualScroll {
constructor(element, options = { wheelMultiplier: 1, touchMultiplier: 1 }) {
this.element = element;
this.options = options;
this.touchStart = {
x: 0,
y: 0,
};
this.lastDelta = {
x: 0,
y: 0,
};
this.window = {
width: 0,
height: 0,
};
this.emitter = new Emitter();
/**
* Event handler for 'touchstart' event
*
* @param event Touch event
*/
this.onTouchStart = (event) => {
// @ts-expect-error - event.targetTouches is not defined
const { clientX, clientY } = event.targetTouches
? event.targetTouches[0]
: event;
this.touchStart.x = clientX;
this.touchStart.y = clientY;
this.lastDelta = {
x: 0,
y: 0,
};
this.emitter.emit('scroll', {
deltaX: 0,
deltaY: 0,
event,
});
};
/** Event handler for 'touchmove' event */
this.onTouchMove = (event) => {
// @ts-expect-error - event.targetTouches is not defined
const { clientX, clientY } = event.targetTouches
? event.targetTouches[0]
: event;
const deltaX = -(clientX - this.touchStart.x) * this.options.touchMultiplier;
const deltaY = -(clientY - this.touchStart.y) * this.options.touchMultiplier;
this.touchStart.x = clientX;
this.touchStart.y = clientY;
this.lastDelta = {
x: deltaX,
y: deltaY,
};
this.emitter.emit('scroll', {
deltaX,
deltaY,
event,
});
};
this.onTouchEnd = (event) => {
this.emitter.emit('scroll', {
deltaX: this.lastDelta.x,
deltaY: this.lastDelta.y,
event,
});
};
/** Event handler for 'wheel' event */
this.onWheel = (event) => {
let { deltaX, deltaY, deltaMode } = event;
const multiplierX = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.width : 1;
const multiplierY = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.height : 1;
deltaX *= multiplierX;
deltaY *= multiplierY;
deltaX *= this.options.wheelMultiplier;
deltaY *= this.options.wheelMultiplier;
this.emitter.emit('scroll', { deltaX, deltaY, event });
};
this.onWindowResize = () => {
this.window = {
width: window.innerWidth,
height: window.innerHeight,
};
};
window.addEventListener('resize', this.onWindowResize, false);
this.onWindowResize();
this.element.addEventListener('wheel', this.onWheel, listenerOptions);
this.element.addEventListener('touchstart', this.onTouchStart, listenerOptions);
this.element.addEventListener('touchmove', this.onTouchMove, listenerOptions);
this.element.addEventListener('touchend', this.onTouchEnd, listenerOptions);
}
/**
* Add an event listener for the given event and callback
*
* @param event Event name
* @param callback Callback function
*/
on(event, callback) {
return this.emitter.on(event, callback);
}
/** Remove all event listeners and clean up */
destroy() {
this.emitter.destroy();
window.removeEventListener('resize', this.onWindowResize, false);
this.element.removeEventListener('wheel', this.onWheel, listenerOptions);
this.element.removeEventListener('touchstart', this.onTouchStart, listenerOptions);
this.element.removeEventListener('touchmove', this.onTouchMove, listenerOptions);
this.element.removeEventListener('touchend', this.onTouchEnd, listenerOptions);
}
}
var version = "1.1.12";
class Lenis {
constructor({ wrapper = window, content = document.documentElement, eventsTarget = wrapper, smoothWheel = true, syncTouch = false, syncTouchLerp = 0.075, touchInertiaMultiplier = 35, duration, // in seconds
easing = (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), lerp = 0.1, infinite = false, orientation = 'vertical', // vertical, horizontal
gestureOrientation = 'vertical', // vertical, horizontal, both
touchMultiplier = 1, wheelMultiplier = 1, autoResize = true, prevent, virtualScroll, __experimental__naiveDimensions = false, } = {}) {
this._isScrolling = false; // true when scroll is animating
this._isStopped = false; // true if user should not be able to scroll - enable/disable programmatically
this._isLocked = false; // same as isStopped but enabled/disabled when scroll reaches target
this._preventNextNativeScrollEvent = false;
this._resetVelocityTimeout = null;
/**
* The time in ms since the lenis instance was created
*/
this.time = 0;
/**
* User data that will be forwarded through the scroll event
*
* @example
* lenis.scrollTo(100, {
* userData: {
* foo: 'bar'
* }
* })
*/
this.userData = {};
/**
* The last velocity of the scroll
*/
this.lastVelocity = 0;
/**
* The current velocity of the scroll
*/
this.velocity = 0;
/**
* The direction of the scroll
*/
this.direction = 0;
// These are instanciated here as they don't need information from the options
this.animate = new Animate();
this.emitter = new Emitter();
this.onPointerDown = (event) => {
if (event.button === 1) {
this.reset();
}
};
this.onVirtualScroll = (data) => {
if (typeof this.options.virtualScroll === 'function' &&
this.options.virtualScroll(data) === false)
return;
const { deltaX, deltaY, event } = data;
this.emitter.emit('virtual-scroll', { deltaX, deltaY, event });
// keep zoom feature
if (event.ctrlKey)
return;
const isTouch = event.type.includes('touch');
const isWheel = event.type.includes('wheel');
this.isTouching = event.type === 'touchstart' || event.type === 'touchmove';
// if (event.type === 'touchend') {
// console.log('touchend', this.scroll)
// // this.lastVelocity = this.velocity
// // this.velocity = 0
// // this.isScrolling = false
// this.emit({ type: 'touchend' })
// // alert('touchend')
// return
// }
const isTapToStop = this.options.syncTouch &&
isTouch &&
event.type === 'touchstart' &&
!this.isStopped &&
!this.isLocked;
if (isTapToStop) {
this.reset();
return;
}
const isClick = deltaX === 0 && deltaY === 0; // click event
// const isPullToRefresh =
// this.options.gestureOrientation === 'vertical' &&
// this.scroll === 0 &&
// !this.options.infinite &&
// deltaY <= 5 // touch pull to refresh, not reliable yet
const isUnknownGesture = (this.options.gestureOrientation === 'vertical' && deltaY === 0) ||
(this.options.gestureOrientation === 'horizontal' && deltaX === 0);
if (isClick || isUnknownGesture) {
// console.log('prevent')
return;
}
// catch if scrolling on nested scroll elements
let composedPath = event.composedPath();
composedPath = composedPath.slice(0, composedPath.indexOf(this.rootElement)); // remove parents elements
const prevent = this.options.prevent;
if (!!composedPath.find((node) => {
var _a, _b, _c, _d, _e;
return node instanceof HTMLElement &&
((typeof prevent === 'function' && (prevent === null || prevent === void 0 ? void 0 : prevent(node))) ||
((_a = node.hasAttribute) === null || _a === void 0 ? void 0 : _a.call(node, 'data-lenis-prevent')) ||
(isTouch && ((_b = node.hasAttribute) === null || _b === void 0 ? void 0 : _b.call(node, 'data-lenis-prevent-touch'))) ||
(isWheel && ((_c = node.hasAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'data-lenis-prevent-wheel'))) ||
(((_d = node.classList) === null || _d === void 0 ? void 0 : _d.contains('lenis')) &&
!((_e = node.classList) === null || _e === void 0 ? void 0 : _e.contains('lenis-stopped'))));
} // nested lenis instance
))
return;
if (this.isStopped || this.isLocked) {
event.preventDefault(); // this will stop forwarding the event to the parent, this is problematic
return;
}
const isSmooth = (this.options.syncTouch && isTouch) ||
(this.options.smoothWheel && isWheel);
if (!isSmooth) {
this.isScrolling = 'native';
this.animate.stop();
return;
}
event.preventDefault();
let delta = deltaY;
if (this.options.gestureOrientation === 'both') {
delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
}
else if (this.options.gestureOrientation === 'horizontal') {
delta = deltaX;
}
const syncTouch = isTouch && this.options.syncTouch;
const isTouchEnd = isTouch && event.type === 'touchend';
const hasTouchInertia = isTouchEnd && Math.abs(delta) > 5;
if (hasTouchInertia) {
delta = this.velocity * this.options.touchInertiaMultiplier;
}
this.scrollTo(this.targetScroll + delta, Object.assign({ programmatic: false }, (syncTouch
? {
lerp: hasTouchInertia ? this.options.syncTouchLerp : 1,
}
: {
lerp: this.options.lerp,
duration: this.options.duration,
easing: this.options.easing,
})));
};
this.onNativeScroll = () => {
if (this._resetVelocityTimeout !== null) {
clearTimeout(this._resetVelocityTimeout);
this._resetVelocityTimeout = null;
}
if (this._preventNextNativeScrollEvent) {
this._preventNextNativeScrollEvent = false;
return;
}
if (this.isScrolling === false || this.isScrolling === 'native') {
const lastScroll = this.animatedScroll;
this.animatedScroll = this.targetScroll = this.actualScroll;
this.lastVelocity = this.velocity;
this.velocity = this.animatedScroll - lastScroll;
this.direction = Math.sign(this.animatedScroll - lastScroll);
this.isScrolling = 'native';
this.emit();
if (this.velocity !== 0) {
this._resetVelocityTimeout = setTimeout(() => {
this.lastVelocity = this.velocity;
this.velocity = 0;
this.isScrolling = false;
this.emit();
}, 400);
}
}
};
// Set version
window.lenisVersion = version;
// Check if wrapper is html or body, fallback to window
if (!wrapper ||
wrapper === document.documentElement ||
wrapper === document.body) {
wrapper = window;
}
// Setup options
this.options = {
wrapper,
content,
eventsTarget,
smoothWheel,
syncTouch,
syncTouchLerp,
touchInertiaMultiplier,
duration,
easing,
lerp,
infinite,
gestureOrientation,
orientation,
touchMultiplier,
wheelMultiplier,
autoResize,
prevent,
virtualScroll,
__experimental__naiveDimensions,
};
// Setup dimensions instance
this.dimensions = new Dimensions(wrapper, content, { autoResize });
// Setup class name
this.updateClassName();
// Set the initial scroll value for all scroll information
this.targetScroll = this.animatedScroll = this.actualScroll;
// Add event listeners
this.options.wrapper.addEventListener('scroll', this.onNativeScroll, false);
this.options.wrapper.addEventListener('pointerdown', this.onPointerDown, false);
// Setup virtual scroll instance
this.virtualScroll = new VirtualScroll(eventsTarget, {
touchMultiplier,
wheelMultiplier,
});
this.virtualScroll.on('scroll', this.onVirtualScroll);
}
/**
* Destroy the lenis instance, remove all event listeners and clean up the class name
*/
destroy() {
this.emitter.destroy();
this.options.wrapper.removeEventListener('scroll', this.onNativeScroll, false);
this.options.wrapper.removeEventListener('pointerdown', this.onPointerDown, false);
this.virtualScroll.destroy();
this.dimensions.destroy();
this.cleanUpClassName();
}
on(event, callback) {
return this.emitter.on(event, callback);
}
off(event, callback) {
return this.emitter.off(event, callback);
}
setScroll(scroll) {
// apply scroll value immediately
if (this.isHorizontal) {
this.rootElement.scrollLeft = scroll;
}
else {
this.rootElement.scrollTop = scroll;
}
}
/**
* Force lenis to recalculate the dimensions
*/
resize() {
this.dimensions.resize();
this.animatedScroll = this.targetScroll = this.actualScroll;
this.emit();
}
emit() {
this.emitter.emit('scroll', this);
}
reset() {
this.isLocked = false;
this.isScrolling = false;
this.animatedScroll = this.targetScroll = this.actualScroll;
this.lastVelocity = this.velocity = 0;
this.animate.stop();
}
/**
* Start lenis scroll after it has been stopped
*/
start() {
if (!this.isStopped)
return;
this.isStopped = false;
this.reset();
}
/**
* Stop lenis scroll
*/
stop() {
if (this.isStopped)
return;
this.isStopped = true;
this.animate.stop();
this.reset();
}
/**
* RequestAnimationFrame for lenis
*
* @param time The time in ms from an external clock like `requestAnimationFrame` or Tempus
*/
raf(time) {
const deltaTime = time - (this.time || time);
this.time = time;
this.animate.advance(deltaTime * 0.001);
}
/**
* Scroll to a target value
*
* @param target The target value to scroll to
* @param options The options for the scroll
*
* @example
* lenis.scrollTo(100, {
* offset: 100,
* duration: 1,
* easing: (t) => 1 - Math.cos((t * Math.PI) / 2),
* lerp: 0.1,
* onStart: () => {
* console.log('onStart')
* },
* onComplete: () => {
* console.log('onComplete')
* },
* })
*/
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
programmatic = true, // called from outside of the class
userData, } = {}) {
if ((this.isStopped || this.isLocked) && !force)
return;
// keywords
if (typeof target === 'string' &&
['top', 'left', 'start'].includes(target)) {
target = 0;
}
else if (typeof target === 'string' &&
['bottom', 'right', 'end'].includes(target)) {
target = this.limit;
}
else {
let node;
if (typeof target === 'string') {
// CSS selector
node = document.querySelector(target);
}
else if (target instanceof HTMLElement && (target === null || target === void 0 ? void 0 : target.nodeType)) {
// Node element
node = target;
}
if (node) {
if (this.options.wrapper !== window) {
// nested scroll offset correction
const wrapperRect = this.rootElement.getBoundingClientRect();
offset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
}
const rect = node.getBoundingClientRect();
target =
(this.isHorizontal ? rect.left : rect.top) + this.animatedScroll;
}
}
if (typeof target !== 'number')
return;
target += offset;
target = Math.round(target);
if (this.options.infinite) {
if (programmatic) {
this.targetScroll = this.animatedScroll = this.scroll;
}
}
else {
target = clamp(0, target, this.limit);
}
if (target === this.targetScroll) {
onStart === null || onStart === void 0 ? void 0 : onStart(this);
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
return;
}
this.userData = userData !== null && userData !== void 0 ? userData : {};
if (immediate) {
this.animatedScroll = this.targetScroll = target;
this.setScroll(this.scroll);
this.reset();
this.preventNextNativeScrollEvent();
this.emit();
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
this.userData = {};
return;
}
if (!programmatic) {
this.targetScroll = target;
}
this.animate.fromTo(this.animatedScroll, target, {
duration,
easing,
lerp,
onStart: () => {
// started
if (lock)
this.isLocked = true;
this.isScrolling = 'smooth';
onStart === null || onStart === void 0 ? void 0 : onStart(this);
},
onUpdate: (value, completed) => {
this.isScrolling = 'smooth';
// updated
this.lastVelocity = this.velocity;
this.velocity = value - this.animatedScroll;
this.direction = Math.sign(this.velocity);
this.animatedScroll = value;
this.setScroll(this.scroll);
if (programmatic) {
// wheel during programmatic should stop it
this.targetScroll = value;
}
if (!completed)
this.emit();
if (completed) {
this.reset();
this.emit();
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
this.userData = {};
// avoid emitting event twice
this.preventNextNativeScrollEvent();
}
},
});
}
preventNextNativeScrollEvent() {
this._preventNextNativeScrollEvent = true;
requestAnimationFrame(() => {
this._preventNextNativeScrollEvent = false;
});
}
/**
* The root element on which lenis is instanced
*/
get rootElement() {
return (this.options.wrapper === window
? document.documentElement
: this.options.wrapper);
}
/**
* The limit which is the maximum scroll value
*/
get limit() {
if (this.options.__experimental__naiveDimensions) {
if (this.isHorizontal) {
return this.rootElement.scrollWidth - this.rootElement.clientWidth;
}
else {
return this.rootElement.scrollHeight - this.rootElement.clientHeight;
}
}
else {
return this.dimensions.limit[this.isHorizontal ? 'x' : 'y'];
}
}
/**
* Whether or not the scroll is horizontal
*/
get isHorizontal() {
return this.options.orientation === 'horizontal';
}
/**
* The actual scroll value
*/
get actualScroll() {
// value browser takes into account
return this.isHorizontal
? this.rootElement.scrollLeft
: this.rootElement.scrollTop;
}
/**
* The current scroll value
*/
get scroll() {
return this.options.infinite
? modulo(this.animatedScroll, this.limit)
: this.animatedScroll;
}
/**
* The progress of the scroll relative to the limit
*/
get progress() {
// avoid progress to be NaN
return this.limit === 0 ? 1 : this.scroll / this.limit;
}
/**
* Current scroll state
*/
get isScrolling() {
return this._isScrolling;
}
set isScrolling(value) {
if (this._isScrolling !== value) {
this._isScrolling = value;
this.updateClassName();
}
}
/**
* Check if lenis is stopped
*/
get isStopped() {
return this._isStopped;
}
set isStopped(value) {
if (this._isStopped !== value) {
this._isStopped = value;
this.updateClassName();
}
}
/**
* Check if lenis is locked
*/
get isLocked() {
return this._isLocked;
}
set isLocked(value) {
if (this._isLocked !== value) {
this._isLocked = value;
this.updateClassName();
}
}
/**
* Check if lenis is smooth scrolling
*/
get isSmooth() {
return this.isScrolling === 'smooth';
}
/**
* The class name applied to the wrapper element
*/
get className() {
let className = 'lenis';
if (this.isStopped)
className += ' lenis-stopped';
if (this.isLocked)
className += ' lenis-locked';
if (this.isScrolling)
className += ' lenis-scrolling';
if (this.isScrolling === 'smooth')
className += ' lenis-smooth';
return className;
}
updateClassName() {
this.cleanUpClassName();
this.rootElement.className =
`${this.rootElement.className} ${this.className}`.trim();
}
cleanUpClassName() {
this.rootElement.className = this.rootElement.className
.replace(/lenis(-\w+)?/g, '')
.trim();
}
}
/**
* Clamp a value between a minimum and maximum value
*
* @param min Minimum value
* @param input Value to clamp
* @param max Maximum value
* @returns Clamped value
*/
function clamp(min, input, max) {
return Math.max(min, Math.min(input, max));
}
/**
* Linearly interpolate between two values using an amount (0 <= t <= 1)
*
* @param x First value
* @param y Second value
* @param t Amount to interpolate (0 <= t <= 1)
* @returns Interpolated value
*/
function lerp(x, y, t) {
return (1 - t) * x + t * y;
}
/**
* Damp a value over time using a damping factor
* {@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}
*
* @param x Initial value
* @param y Target value
* @param lambda Damping factor
* @param dt Time elapsed since the last update
* @returns Damped value
*/
function damp(x, y, lambda, deltaTime) {
return lerp(x, y, 1 - Math.exp(-lambda * deltaTime));
}
/**
* Calculate the modulo of the dividend and divisor while keeping the result within the same sign as the divisor
* {@link https://anguscroll.com/just/just-modulo}
*
* @param n Dividend
* @param d Divisor
* @returns Modulo
*/
function modulo(n, d) {
return ((n % d) + d) % d;
}
return Lenis;
/**
* Animate class to handle value animations with lerping or easing
*
* @example
* const animate = new Animate()
* animate.fromTo(0, 100, { duration: 1, easing: (t) => t })
* animate.advance(0.5) // 50
*/
class Animate {
constructor() {
this.isRunning = false;
this.value = 0;
this.from = 0;
this.to = 0;
this.currentTime = 0;
}
/**
* Advance the animation by the given delta time
*
* @param deltaTime - The time in seconds to advance the animation
*/
advance(deltaTime) {
var _a;
if (!this.isRunning)
return;
let completed = false;
if (this.duration && this.easing) {
this.currentTime += deltaTime;
const linearProgress = clamp(0, this.currentTime / this.duration, 1);
completed = linearProgress >= 1;
const easedProgress = completed ? 1 : this.easing(linearProgress);
this.value = this.from + (this.to - this.from) * easedProgress;
}
else if (this.lerp) {
this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
if (Math.round(this.value) === this.to) {
this.value = this.to;
completed = true;
}
}
else {
// If no easing or lerp, just jump to the end value
this.value = this.to;
completed = true;
}
if (completed) {
this.stop();
}
// Call the onUpdate callback with the current value and completed status
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, this.value, completed);
}
/** Stop the animation */
stop() {
this.isRunning = false;
}
/**
* Set up the animation from a starting value to an ending value
* with optional parameters for lerping, duration, easing, and onUpdate callback
*
* @param from - The starting value
* @param to - The ending value
* @param options - Options for the animation
*/
fromTo(from, to, { lerp, duration, easing, onStart, onUpdate }) {
this.from = this.value = from;
this.to = to;
this.lerp = lerp;
this.duration = duration;
this.easing = easing;
this.currentTime = 0;
this.isRunning = true;
onStart === null || onStart === void 0 ? void 0 : onStart();
this.onUpdate = onUpdate;
}
}
function debounce(callback, delay) {
let timer;
return function (...args) {
let context = this;
clearTimeout(timer);
timer = setTimeout(() => {
timer = undefined;
callback.apply(context, args);
}, delay);
};
}
/**
* Dimensions class to handle the size of the content and wrapper
*
* @example
* const dimensions = new Dimensions(wrapper, content)
* dimensions.on('resize', (e) => {
* console.log(e.width, e.height)
* })
*/
class Dimensions {
constructor(wrapper, content, { autoResize = true, debounce: debounceValue = 250 } = {}) {
this.wrapper = wrapper;
this.content = content;
this.width = 0;
this.height = 0;
this.scrollHeight = 0;
this.scrollWidth = 0;
this.resize = () => {
this.onWrapperResize();
this.onContentResize();
};
this.onWrapperResize = () => {
if (this.wrapper instanceof Window) {
this.width = window.innerWidth;
this.height = window.innerHeight;
}
else {
this.width = this.wrapper.clientWidth;
this.height = this.wrapper.clientHeight;
}
};
this.onContentResize = () => {
if (this.wrapper instanceof Window) {
this.scrollHeight = this.content.scrollHeight;
this.scrollWidth = this.content.scrollWidth;
}
else {
this.scrollHeight = this.wrapper.scrollHeight;
this.scrollWidth = this.wrapper.scrollWidth;
}
};
if (autoResize) {
this.debouncedResize = debounce(this.resize, debounceValue);
if (this.wrapper instanceof Window) {
window.addEventListener('resize', this.debouncedResize, false);
}
else {
this.wrapperResizeObserver = new ResizeObserver(this.debouncedResize);
this.wrapperResizeObserver.observe(this.wrapper);
}
this.contentResizeObserver = new ResizeObserver(this.debouncedResize);
this.contentResizeObserver.observe(this.content);
}
this.resize();
}
destroy() {
var _a, _b;
(_a = this.wrapperResizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
(_b = this.contentResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
if (this.wrapper === window && this.debouncedResize) {
window.removeEventListener('resize', this.debouncedResize, false);
}
}
get limit() {
return {
x: this.scrollWidth - this.width,
y: this.scrollHeight - this.height,
};
}
}
/**
* Emitter class to handle events
* @example
* const emitter = new Emitter()
* emitter.on('event', (data) => {
* console.log(data)
* })
* emitter.emit('event', 'data')
*/
class Emitter {
constructor() {
this.events = {};
}
/**
* Emit an event with the given data
* @param event Event name
* @param args Data to pass to the event handlers
*/
emit(event, ...args) {
var _a;
let callbacks = this.events[event] || [];
for (let i = 0, length = callbacks.length; i < length; i++) {
(_a = callbacks[i]) === null || _a === void 0 ? void 0 : _a.call(callbacks, ...args);
}
}
/**
* Add a callback to the event
* @param event Event name
* @param cb Callback function
* @returns Unsubscribe function
*/
on(event, cb) {
var _a;
// Add the callback to the event's callback list, or create a new list with the callback
((_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
// Return an unsubscribe function
return () => {
var _a;
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => cb !== i);
};
}
/**
* Remove a callback from the event
* @param event Event name
* @param callback Callback function
*/
off(event, callback) {
var _a;
this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter((i) => callback !== i);
}
/**
* Remove all event listeners and clean up
*/
destroy() {
this.events = {};
}
}
const LINE_HEIGHT = 100 / 6;
const listenerOptions = { passive: false };
class VirtualScroll {
constructor(element, options = { wheelMultiplier: 1, touchMultiplier: 1 }) {
this.element = element;
this.options = options;
this.touchStart = {
x: 0,
y: 0,
};
this.lastDelta = {
x: 0,
y: 0,
};
this.window = {
width: 0,
height: 0,
};
this.emitter = new Emitter();
/**
* Event handler for 'touchstart' event
*
* @param event Touch event
*/
this.onTouchStart = (event) => {
// @ts-expect-error - event.targetTouches is not defined
const { clientX, clientY } = event.targetTouches
? event.targetTouches[0]
: event;
this.touchStart.x = clientX;
this.touchStart.y = clientY;
this.lastDelta = {
x: 0,
y: 0,
};
this.emitter.emit('scroll', {
deltaX: 0,
deltaY: 0,
event,
});
};
/** Event handler for 'touchmove' event */
this.onTouchMove = (event) => {
// @ts-expect-error - event.targetTouches is not defined
const { clientX, clientY } = event.targetTouches
? event.targetTouches[0]
: event;
const deltaX = -(clientX - this.touchStart.x) * this.options.touchMultiplier;
const deltaY = -(clientY - this.touchStart.y) * this.options.touchMultiplier;
this.touchStart.x = clientX;
this.touchStart.y = clientY;
this.lastDelta = {
x: deltaX,
y: deltaY,
};
this.emitter.emit('scroll', {
deltaX,
deltaY,
event,
});
};
this.onTouchEnd = (event) => {
this.emitter.emit('scroll', {
deltaX: this.lastDelta.x,
deltaY: this.lastDelta.y,
event,
});
};
/** Event handler for 'wheel' event */
this.onWheel = (event) => {
let { deltaX, deltaY, deltaMode } = event;
const multiplierX = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.width : 1;
const multiplierY = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? this.window.height : 1;
deltaX *= multiplierX;
deltaY *= multiplierY;
deltaX *= this.options.wheelMultiplier;
deltaY *= this.options.wheelMultiplier;
this.emitter.emit('scroll', { deltaX, deltaY, event });
};
this.onWindowResize = () => {
this.window = {
width: window.innerWidth,
height: window.innerHeight,
};
};
window.addEventListener('resize', this.onWindowResize, false);
this.onWindowResize();
this.element.addEventListener('wheel', this.onWheel, listenerOptions);
this.element.addEventListener('touchstart', this.onTouchStart, listenerOptions);
this.element.addEventListener('touchmove', this.onTouchMove, listenerOptions);
this.element.addEventListener('touchend', this.onTouchEnd, listenerOptions);
}
/**
* Add an event listener for the given event and callback
*
* @param event Event name
* @param callback Callback function
*/
on(event, callback) {
return this.emitter.on(event, callback);
}
/** Remove all event listeners and clean up */
destroy() {
this.emitter.destroy();
window.removeEventListener('resize', this.onWindowResize, false);
this.element.removeEventListener('wheel', this.onWheel, listenerOptions);
this.element.removeEventListener('touchstart', this.onTouchStart, listenerOptions);
this.element.removeEventListener('touchmove', this.onTouchMove, listenerOptions);
this.element.removeEventListener('touchend', this.onTouchEnd, listenerOptions);
}
}
var _Lenis_isScrolling, _Lenis_isStopped, _Lenis_isLocked, _Lenis_preventNextNativeScrollEvent, _Lenis_resetVelocityTimeout;
class Lenis {
constructor({ wrapper = window, content = document.documentElement, eventsTarget = wrapper, smoothWheel = true, syncTouch = false, syncTouchLerp = 0.075, touchInertiaMultiplier = 35, duration, // in seconds
easing = (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), lerp = 0.1, infinite = false, orientation = 'vertical', // vertical, horizontal
gestureOrientation = 'vertical', // vertical, horizontal, both
touchMultiplier = 1, wheelMultiplier = 1, autoResize = true, prevent, virtualScroll, __experimental__naiveDimensions = false, } = {}) {
_Lenis_isScrolling.set(this, false); // true when scroll is animating
_Lenis_isStopped.set(this, false); // true if user should not be able to scroll - enable/disable programmatically
_Lenis_isLocked.set(this, false); // same as isStopped but enabled/disabled when scroll reaches target
_Lenis_preventNextNativeScrollEvent.set(this, false);
_Lenis_resetVelocityTimeout.set(this, null
/**
* Whether or not the user is touching the screen
*/
);
/**
* The time in ms since the lenis instance was created
*/
this.time = 0;
/**
* User data that will be forwarded through the scroll event
*
* @example
* lenis.scrollTo(100, {
* userData: {
* foo: 'bar'
* }
* })
*/
this.userData = {};
/**
* The last velocity of the scroll
*/
this.lastVelocity = 0;
/**
* The current velocity of the scroll
*/
this.velocity = 0;
/**
* The direction of the scroll
*/
this.direction = 0;
// These are instanciated here as they don't need information from the options
this.animate = new Animate();
this.emitter = new Emitter();
this.onPointerDown = (event) => {
if (event.button === 1) {
this.reset();
}
};
this.onVirtualScroll = (data) => {
if (typeof this.options.virtualScroll === 'function' &&
this.options.virtualScroll(data) === false)
return;
const { deltaX, deltaY, event } = data;
this.emitter.emit('virtual-scroll', { deltaX, deltaY, event });
// keep zoom feature
if (event.ctrlKey)
return;
const isTouch = event.type.includes('touch');
const isWheel = event.type.includes('wheel');
this.isTouching = event.type === 'touchstart' || event.type === 'touchmove';
// if (event.type === 'touchend') {
// console.log('touchend', this.scroll)
// // this.lastVelocity = this.velocity
// // this.velocity = 0
// // this.isScrolling = false
// this.emit({ type: 'touchend' })
// // alert('touchend')
// return
// }
const isTapToStop = this.options.syncTouch &&
isTouch &&
event.type === 'touchstart' &&
!this.isStopped &&
!this.isLocked;
if (isTapToStop) {
this.reset();
return;
}
const isClick = deltaX === 0 && deltaY === 0; // click event
// const isPullToRefresh =
// this.options.gestureOrientation === 'vertical' &&
// this.scroll === 0 &&
// !this.options.infinite &&
// deltaY <= 5 // touch pull to refresh, not reliable yet
const isUnknownGesture = (this.options.gestureOrientation === 'vertical' && deltaY === 0) ||
(this.options.gestureOrientation === 'horizontal' && deltaX === 0);
if (isClick || isUnknownGesture) {
// console.log('prevent')
return;
}
// catch if scrolling on nested scroll elements
let composedPath = event.composedPath();
composedPath = composedPath.slice(0, composedPath.indexOf(this.rootElement)); // remove parents elements
const prevent = this.options.prevent;
if (!!composedPath.find((node) => {
var _a, _b, _c, _d, _e;
return node instanceof HTMLElement &&
((typeof prevent === 'function' && (prevent === null || prevent === void 0 ? void 0 : prevent(node))) ||
((_a = node.hasAttribute) === null || _a === void 0 ? void 0 : _a.call(node, 'data-lenis-prevent')) ||
(isTouch && ((_b = node.hasAttribute) === null || _b === void 0 ? void 0 : _b.call(node, 'data-lenis-prevent-touch'))) ||
(isWheel && ((_c = node.hasAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'data-lenis-prevent-wheel'))) ||
(((_d = node.classList) === null || _d === void 0 ? void 0 : _d.contains('lenis')) &&
!((_e = node.classList) === null || _e === void 0 ? void 0 : _e.contains('lenis-stopped'))));
} // nested lenis instance
))
return;
if (this.isStopped || this.isLocked) {
event.preventDefault(); // this will stop forwarding the event to the parent, this is problematic
return;
}
const isSmooth = (this.options.syncTouch && isTouch) ||
(this.options.smoothWheel && isWheel);
if (!isSmooth) {
this.isScrolling = 'native';
this.animate.stop();
return;
}
event.preventDefault();
let delta = deltaY;
if (this.options.gestureOrientation === 'both') {
delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
}
else if (this.options.gestureOrientation === 'horizontal') {
delta = deltaX;
}
const syncTouch = isTouch && this.options.syncTouch;
const isTouchEnd = isTouch && event.type === 'touchend';
const hasTouchInertia = isTouchEnd && Math.abs(delta) > 5;
if (hasTouchInertia) {
delta = this.velocity * this.options.touchInertiaMultiplier;
}
this.scrollTo(this.targetScroll + delta, Object.assign({ programmatic: false }, (syncTouch
? {
lerp: hasTouchInertia ? this.options.syncTouchLerp : 1,
}
: {
lerp: this.options.lerp,
duration: this.options.duration,
easing: this.options.easing,
})));
};
this.onNativeScroll = () => {
if (__classPrivateFieldGet(this, _Lenis_resetVelocityTimeout, "f") !== null) {
clearTimeout(__classPrivateFieldGet(this, _Lenis_resetVelocityTimeout, "f"));
__classPrivateFieldSet(this, _Lenis_resetVelocityTimeout, null, "f");
}
if (__classPrivateFieldGet(this, _Lenis_preventNextNativeScrollEvent, "f")) {
__classPrivateFieldSet(this, _Lenis_preventNextNativeScrollEvent, false, "f");
return;
}
if (this.isScrolling === false || this.isScrolling === 'native') {
const lastScroll = this.animatedScroll;
this.animatedScroll = this.targetScroll = this.actualScroll;
this.lastVelocity = this.velocity;
this.velocity = this.animatedScroll - lastScroll;
this.direction = Math.sign(this.animatedScroll - lastScroll);
this.isScrolling = 'native';
this.emit();
if (this.velocity !== 0) {
__classPrivateFieldSet(this, _Lenis_resetVelocityTimeout, setTimeout(() => {
this.lastVelocity = this.velocity;
this.velocity = 0;
this.isScrolling = false;
this.emit();
}, 400), "f");
}
}
};
// Set version
window.lenisVersion = version;
// Check if wrapper is html or body, fallback to window
if (!wrapper ||
wrapper === document.documentElement ||
wrapper === document.body) {
wrapper = window;
}
// Setup options
this.options = {
wrapper,
content,
eventsTarget,
smoothWheel,
syncTouch,
syncTouchLerp,
touchInertiaMultiplier,
duration,
easing,
lerp,
infinite,
gestureOrientation,
orientation,
touchMultiplier,
wheelMultiplier,
autoResize,
prevent,
virtualScroll,
__experimental__naiveDimensions,
};
// Setup dimensions instance
this.dimensions = new Dimensions(wrapper, content, { autoResize });
// Setup class name
this.updateClassName();
// Set the initial scroll value for all scroll information
this.targetScroll = this.animatedScroll = this.actualScroll;
// Add event listeners
this.options.wrapper.addEventListener('scroll', this.onNativeScroll, false);
this.options.wrapper.addEventListener('pointerdown', this.onPointerDown, false);
// Setup virtual scroll instance
this.virtualScroll = new VirtualScroll(eventsTarget, {
touchMultiplier,
wheelMultiplier,
});
this.virtualScroll.on('scroll', this.onVirtualScroll);
}
/**
* Destroy the lenis instance, remove all event listeners and clean up the class name
*/
destroy() {
this.emitter.destroy();
this.options.wrapper.removeEventListener('scroll', this.onNativeScroll, false);
this.options.wrapper.removeEventListener('pointerdown', this.onPointerDown, false);
this.virtualScroll.destroy();
this.dimensions.destroy();
this.cleanUpClassName();
}
on(event, callback) {
return this.emitter.on(event, callback);
}
off(event, callback) {
return this.emitter.off(event, callback);
}
setScroll(scroll) {
// apply scroll value immediately
if (this.isHorizontal) {
this.rootElement.scrollLeft = scroll;
}
else {
this.rootElement.scrollTop = scroll;
}
}
/**
* Force lenis to recalculate the dimensions
*/
resize() {
this.dimensions.resize();
this.animatedScroll = this.targetScroll = this.actualScroll;
this.emit();
}
emit() {
this.emitter.emit('scroll', this);
}
reset() {
this.isLocked = false;
this.isScrolling = false;
this.animatedScroll = this.targetScroll = this.actualScroll;
this.lastVelocity = this.velocity = 0;
this.animate.stop();
}
/**
* Start lenis scroll after it has been stopped
*/
start() {
if (!this.isStopped)
return;
this.isStopped = false;
this.reset();
}
/**
* Stop lenis scroll
*/
stop() {
if (this.isStopped)
return;
this.isStopped = true;
this.animate.stop();
this.reset();
}
/**
* RequestAnimationFrame for lenis
*
* @param time The time in ms from an external clock like `requestAnimationFrame` or Tempus
*/
raf(time) {
const deltaTime = time - (this.time || time);
this.time = time;
this.animate.advance(deltaTime * 0.001);
}
/**
* Scroll to a target value
*
* @param target The target value to scroll to
* @param options The options for the scroll
*
* @example
* lenis.scrollTo(100, {
* offset: 100,
* duration: 1,
* easing: (t) => 1 - Math.cos((t * Math.PI) / 2),
* lerp: 0.1,
* onStart: () => {
* console.log('onStart')
* },
* onComplete: () => {
* console.log('onComplete')
* },
* })
*/
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
programmatic = true, // called from outside of the class
userData, } = {}) {
if ((this.isStopped || this.isLocked) && !force)
return;
// keywords
if (typeof target === 'string' &&
['top', 'left', 'start'].includes(target)) {
target = 0;
}
else if (typeof target === 'string' &&
['bottom', 'right', 'end'].includes(target)) {
target = this.limit;
}
else {
let node;
if (typeof target === 'string') {
// CSS selector
node = document.querySelector(target);
}
else if (target instanceof HTMLElement && (target === null || target === void 0 ? void 0 : target.nodeType)) {
// Node element
node = target;
}
if (node) {
if (this.options.wrapper !== window) {
// nested scroll offset correction
const wrapperRect = this.rootElement.getBoundingClientRect();
offset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
}
const rect = node.getBoundingClientRect();
target =
(this.isHorizontal ? rect.left : rect.top) + this.animatedScroll;
}
}
if (typeof target !== 'number')
return;
target += offset;
target = Math.round(target);
if (this.options.infinite) {
if (programmatic) {
this.targetScroll = this.animatedScroll = this.scroll;
}
}
else {
target = clamp(0, target, this.limit);
}
if (target === this.targetScroll) {
onStart === null || onStart === void 0 ? void 0 : onStart(this);
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
return;
}
this.userData = userData !== null && userData !== void 0 ? userData : {};
if (immediate) {
this.animatedScroll = this.targetScroll = target;
this.setScroll(this.scroll);
this.reset();
this.preventNextNativeScrollEvent();
this.emit();
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
this.userData = {};
return;
}
if (!programmatic) {
this.targetScroll = target;
}
this.animate.fromTo(this.animatedScroll, target, {
duration,
easing,
lerp,
onStart: () => {
// started
if (lock)
this.isLocked = true;
this.isScrolling = 'smooth';
onStart === null || onStart === void 0 ? void 0 : onStart(this);
},
onUpdate: (value, completed) => {
this.isScrolling = 'smooth';
// updated
this.lastVelocity = this.velocity;
this.velocity = value - this.animatedScroll;
this.direction = Math.sign(this.velocity);
this.animatedScroll = value;
this.setScroll(this.scroll);
if (programmatic) {
// wheel during programmatic should stop it
this.targetScroll = value;
}
if (!completed)
this.emit();
if (completed) {
this.reset();
this.emit();
onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
this.userData = {};
// avoid emitting event twice
this.preventNextNativeScrollEvent();
}
},
});
}
preventNextNativeScrollEvent() {
__classPrivateFieldSet(this, _Lenis_preventNextNativeScrollEvent, true, "f");
requestAnimationFrame(() => {
__classPrivateFieldSet(this, _Lenis_preventNextNativeScrollEvent, false, "f");
});
}
/**
* The root element on which lenis is instanced
*/
get rootElement() {
return (this.options.wrapper === window
? document.documentElement
: this.options.wrapper);
}
/**
* The limit which is the maximum scroll value
*/
get limit() {
if (this.options.__experimental__naiveDimensions) {
if (this.isHorizontal) {
return this.rootElement.scrollWidth - this.rootElement.clientWidth;
}
else {
return this.rootElement.scrollHeight - this.rootElement.clientHeight;
}
}
else {
return this.dimensions.limit[this.isHorizontal ? 'x' : 'y'];
}
}
/**
* Whether or not the scroll is horizontal
*/
get isHorizontal() {
return this.options.orientation === 'horizontal';
}
/**
* The actual scroll value
*/
get actualScroll() {
// value browser takes into account
return this.isHorizontal
? this.rootElement.scrollLeft
: this.rootElement.scrollTop;
}
/**
* The current scroll value
*/
get scroll() {
return this.options.infinite
? modulo(this.animatedScroll, this.limit)
: this.animatedScroll;
}
/**
* The progress of the scroll relative to the limit
*/
get progress() {
// avoid progress to be NaN
return this.limit === 0 ? 1 : this.scroll / this.limit;
}
/**
* Current scroll state
*/
get isScrolling() {
return __classPrivateFieldGet(this, _Lenis_isScrolling, "f");
}
set isScrolling(value) {
if (__classPrivateFieldGet(this, _Lenis_isScrolling, "f") !== value) {
__classPrivateFieldSet(this, _Lenis_isScrolling, value, "f");
this.updateClassName();
}
}
/**
* Check if lenis is stopped
*/
get isStopped() {
return __classPrivateFieldGet(this, _Lenis_isStopped, "f");
}
set isStopped(value) {
if (__classPrivateFieldGet(this, _Lenis_isStopped, "f") !== value) {
__classPrivateFieldSet(this, _Lenis_isStopped, value, "f");
this.updateClassName();
}
}
/**
* Check if lenis is locked
*/
get isLocked() {
return __classPrivateFieldGet(this, _Lenis_isLocked, "f");
}
set isLocked(value) {
if (__classPrivateFieldGet(this, _Lenis_isLocked, "f") !== value) {
__classPrivateFieldSet(this, _Lenis_isLocked, value, "f");
this.updateClassName();
}
}
/**
* Check if lenis is smooth scrolling
*/
get isSmooth() {
return this.isScrolling === 'smooth';
}
/**
* The class name applied to the wrapper element
*/
get className() {
let className = 'lenis';
if (this.isStopped)
className += ' lenis-stopped';
if (this.isLocked)
className += ' lenis-locked';
if (this.isScrolling)
className += ' lenis-scrolling';
if (this.isScrolling === 'smooth')
className += ' lenis-smooth';
return className;
}
updateClassName() {
this.cleanUpClassName();
this.rootElement.className =
`${this.rootElement.className} ${this.className}`.trim();
}
cleanUpClassName() {
this.rootElement.className = this.rootElement.className
.replace(/lenis(-\w+)?/g, '')
.trim();
}
}
_Lenis_isScrolling = new WeakMap(), _Lenis_isStopped = new WeakMap(), _Lenis_isLocked = new WeakMap(), _Lenis_preventNextNativeScrollEvent = new WeakMap(), _Lenis_resetVelocityTimeout = new WeakMap();
return Lenis;
}));
//# sourceMappingURL=lenis.js.map

@@ -1,2 +0,2 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Lenis=e()}(this,(function(){"use strict";function __classPrivateFieldGet(t,e,i,s){if("a"===i&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===i?s:"a"===i?s.call(t):s?s.value:e.get(t)}function __classPrivateFieldSet(t,e,i,s,o){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!o)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!o:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===s?o.call(t,i):o?o.value=i:e.set(t,i),i}"function"==typeof SuppressedError&&SuppressedError;function clamp(t,e,i){return Math.max(t,Math.min(e,i))}class Animate{constructor(){this.isRunning=!1,this.value=0,this.from=0,this.to=0,this.currentTime=0}advance(t){var e;if(!this.isRunning)return;let i=!1;if(this.duration&&this.easing){this.currentTime+=t;const e=clamp(0,this.currentTime/this.duration,1);i=e>=1;const s=i?1:this.easing(e);this.value=this.from+(this.to-this.from)*s}else this.lerp?(this.value=function damp(t,e,i,s){return function lerp(t,e,i){return(1-i)*t+i*e}(t,e,1-Math.exp(-i*s))}(this.value,this.to,60*this.lerp,t),Math.round(this.value)===this.to&&(this.value=this.to,i=!0)):(this.value=this.to,i=!0);i&&this.stop(),null===(e=this.onUpdate)||void 0===e||e.call(this,this.value,i)}stop(){this.isRunning=!1}fromTo(t,e,{lerp:i,duration:s,easing:o,onStart:n,onUpdate:r}){this.from=this.value=t,this.to=e,this.lerp=i,this.duration=s,this.easing=o,this.currentTime=0,this.isRunning=!0,null==n||n(),this.onUpdate=r}}class Dimensions{constructor(t,e,{autoResize:i=!0,debounce:s=250}={}){this.wrapper=t,this.content=e,this.width=0,this.height=0,this.scrollHeight=0,this.scrollWidth=0,this.resize=()=>{this.onWrapperResize(),this.onContentResize()},this.onWrapperResize=()=>{this.wrapper instanceof Window?(this.width=window.innerWidth,this.height=window.innerHeight):(this.width=this.wrapper.clientWidth,this.height=this.wrapper.clientHeight)},this.onContentResize=()=>{this.wrapper instanceof Window?(this.scrollHeight=this.content.scrollHeight,this.scrollWidth=this.content.scrollWidth):(this.scrollHeight=this.wrapper.scrollHeight,this.scrollWidth=this.wrapper.scrollWidth)},i&&(this.debouncedResize=function debounce(t,e){let i;return function(...s){let o=this;clearTimeout(i),i=setTimeout((()=>{i=void 0,t.apply(o,s)}),e)}}(this.resize,s),this.wrapper instanceof Window?window.addEventListener("resize",this.debouncedResize,!1):(this.wrapperResizeObserver=new ResizeObserver(this.debouncedResize),this.wrapperResizeObserver.observe(this.wrapper)),this.contentResizeObserver=new ResizeObserver(this.debouncedResize),this.contentResizeObserver.observe(this.content)),this.resize()}destroy(){var t,e;null===(t=this.wrapperResizeObserver)||void 0===t||t.disconnect(),null===(e=this.contentResizeObserver)||void 0===e||e.disconnect(),this.wrapper===window&&this.debouncedResize&&window.removeEventListener("resize",this.debouncedResize,!1)}get limit(){return{x:this.scrollWidth-this.width,y:this.scrollHeight-this.height}}}class Emitter{constructor(){this.events={}}emit(t,...e){var i;let s=this.events[t]||[];for(let t=0,o=s.length;t<o;t++)null===(i=s[t])||void 0===i||i.call(s,...e)}on(t,e){var i;return(null===(i=this.events[t])||void 0===i?void 0:i.push(e))||(this.events[t]=[e]),()=>{var i;this.events[t]=null===(i=this.events[t])||void 0===i?void 0:i.filter((t=>e!==t))}}off(t,e){var i;this.events[t]=null===(i=this.events[t])||void 0===i?void 0:i.filter((t=>e!==t))}destroy(){this.events={}}}const t=100/6,e={passive:!1};class VirtualScroll{constructor(i,s={wheelMultiplier:1,touchMultiplier:1}){this.element=i,this.options=s,this.touchStart={x:0,y:0},this.lastDelta={x:0,y:0},this.window={width:0,height:0},this.emitter=new Emitter,this.onTouchStart=t=>{const{clientX:e,clientY:i}=t.targetTouches?t.targetTouches[0]:t;this.touchStart.x=e,this.touchStart.y=i,this.lastDelta={x:0,y:0},this.emitter.emit("scroll",{deltaX:0,deltaY:0,event:t})},this.onTouchMove=t=>{const{clientX:e,clientY:i}=t.targetTouches?t.targetTouches[0]:t,s=-(e-this.touchStart.x)*this.options.touchMultiplier,o=-(i-this.touchStart.y)*this.options.touchMultiplier;this.touchStart.x=e,this.touchStart.y=i,this.lastDelta={x:s,y:o},this.emitter.emit("scroll",{deltaX:s,deltaY:o,event:t})},this.onTouchEnd=t=>{this.emitter.emit("scroll",{deltaX:this.lastDelta.x,deltaY:this.lastDelta.y,event:t})},this.onWheel=e=>{let{deltaX:i,deltaY:s,deltaMode:o}=e;i*=1===o?t:2===o?this.window.width:1,s*=1===o?t:2===o?this.window.height:1,i*=this.options.wheelMultiplier,s*=this.options.wheelMultiplier,this.emitter.emit("scroll",{deltaX:i,deltaY:s,event:e})},this.onWindowResize=()=>{this.window={width:window.innerWidth,height:window.innerHeight}},window.addEventListener("resize",this.onWindowResize,!1),this.onWindowResize(),this.element.addEventListener("wheel",this.onWheel,e),this.element.addEventListener("touchstart",this.onTouchStart,e),this.element.addEventListener("touchmove",this.onTouchMove,e),this.element.addEventListener("touchend",this.onTouchEnd,e)}on(t,e){return this.emitter.on(t,e)}destroy(){this.emitter.destroy(),window.removeEventListener("resize",this.onWindowResize,!1),this.element.removeEventListener("wheel",this.onWheel,e),this.element.removeEventListener("touchstart",this.onTouchStart,e),this.element.removeEventListener("touchmove",this.onTouchMove,e),this.element.removeEventListener("touchend",this.onTouchEnd,e)}}var i,s,o,n,r;return i=new WeakMap,s=new WeakMap,o=new WeakMap,n=new WeakMap,r=new WeakMap,class Lenis{constructor({wrapper:t=window,content:e=document.documentElement,eventsTarget:l=t,smoothWheel:h=!0,syncTouch:a=!1,syncTouchLerp:c=.075,touchInertiaMultiplier:d=35,duration:u,easing:p=(t=>Math.min(1,1.001-Math.pow(2,-10*t))),lerp:m=.1,infinite:v=!1,orientation:w="vertical",gestureOrientation:f="vertical",touchMultiplier:g=1,wheelMultiplier:S=1,autoResize:y=!0,prevent:E,virtualScroll:_,__experimental__naiveDimensions:T=!1}={}){i.set(this,!1),s.set(this,!1),o.set(this,!1),n.set(this,!1),r.set(this,null),this.time=0,this.userData={},this.lastVelocity=0,this.velocity=0,this.direction=0,this.animate=new Animate,this.emitter=new Emitter,this.onPointerDown=t=>{1===t.button&&this.reset()},this.onVirtualScroll=t=>{if("function"==typeof this.options.virtualScroll&&!1===this.options.virtualScroll(t))return;const{deltaX:e,deltaY:i,event:s}=t;if(this.emitter.emit("virtual-scroll",{deltaX:e,deltaY:i,event:s}),s.ctrlKey)return;const o=s.type.includes("touch"),n=s.type.includes("wheel");this.isTouching="touchstart"===s.type||"touchmove"===s.type;if(this.options.syncTouch&&o&&"touchstart"===s.type&&!this.isStopped&&!this.isLocked)return void this.reset();const r=0===e&&0===i,l="vertical"===this.options.gestureOrientation&&0===i||"horizontal"===this.options.gestureOrientation&&0===e;if(r||l)return;let h=s.composedPath();h=h.slice(0,h.indexOf(this.rootElement));const a=this.options.prevent;if(h.find((t=>{var e,i,s,r,l;return t instanceof HTMLElement&&("function"==typeof a&&(null==a?void 0:a(t))||(null===(e=t.hasAttribute)||void 0===e?void 0:e.call(t,"data-lenis-prevent"))||o&&(null===(i=t.hasAttribute)||void 0===i?void 0:i.call(t,"data-lenis-prevent-touch"))||n&&(null===(s=t.hasAttribute)||void 0===s?void 0:s.call(t,"data-lenis-prevent-wheel"))||(null===(r=t.classList)||void 0===r?void 0:r.contains("lenis"))&&!(null===(l=t.classList)||void 0===l?void 0:l.contains("lenis-stopped")))})))return;if(this.isStopped||this.isLocked)return void s.preventDefault();if(!(this.options.syncTouch&&o||this.options.smoothWheel&&n))return this.isScrolling="native",void this.animate.stop();s.preventDefault();let c=i;"both"===this.options.gestureOrientation?c=Math.abs(i)>Math.abs(e)?i:e:"horizontal"===this.options.gestureOrientation&&(c=e);const d=o&&this.options.syncTouch,u=o&&"touchend"===s.type&&Math.abs(c)>5;u&&(c=this.velocity*this.options.touchInertiaMultiplier),this.scrollTo(this.targetScroll+c,Object.assign({programmatic:!1},d?{lerp:u?this.options.syncTouchLerp:1}:{lerp:this.options.lerp,duration:this.options.duration,easing:this.options.easing}))},this.onNativeScroll=()=>{if(null!==__classPrivateFieldGet(this,r,"f")&&(clearTimeout(__classPrivateFieldGet(this,r,"f")),__classPrivateFieldSet(this,r,null,"f")),__classPrivateFieldGet(this,n,"f"))__classPrivateFieldSet(this,n,!1,"f");else if(!1===this.isScrolling||"native"===this.isScrolling){const t=this.animatedScroll;this.animatedScroll=this.targetScroll=this.actualScroll,this.lastVelocity=this.velocity,this.velocity=this.animatedScroll-t,this.direction=Math.sign(this.animatedScroll-t),this.isScrolling="native",this.emit(),0!==this.velocity&&__classPrivateFieldSet(this,r,setTimeout((()=>{this.lastVelocity=this.velocity,this.velocity=0,this.isScrolling=!1,this.emit()}),400),"f")}},window.lenisVersion="1.1.12",t&&t!==document.documentElement&&t!==document.body||(t=window),this.options={wrapper:t,content:e,eventsTarget:l,smoothWheel:h,syncTouch:a,syncTouchLerp:c,touchInertiaMultiplier:d,duration:u,easing:p,lerp:m,infinite:v,gestureOrientation:f,orientation:w,touchMultiplier:g,wheelMultiplier:S,autoResize:y,prevent:E,virtualScroll:_,__experimental__naiveDimensions:T},this.dimensions=new Dimensions(t,e,{autoResize:y}),this.updateClassName(),this.targetScroll=this.animatedScroll=this.actualScroll,this.options.wrapper.addEventListener("scroll",this.onNativeScroll,!1),this.options.wrapper.addEventListener("pointerdown",this.onPointerDown,!1),this.virtualScroll=new VirtualScroll(l,{touchMultiplier:g,wheelMultiplier:S}),this.virtualScroll.on("scroll",this.onVirtualScroll)}destroy(){this.emitter.destroy(),this.options.wrapper.removeEventListener("scroll",this.onNativeScroll,!1),this.options.wrapper.removeEventListener("pointerdown",this.onPointerDown,!1),this.virtualScroll.destroy(),this.dimensions.destroy(),this.cleanUpClassName()}on(t,e){return this.emitter.on(t,e)}off(t,e){return this.emitter.off(t,e)}setScroll(t){this.isHorizontal?this.rootElement.scrollLeft=t:this.rootElement.scrollTop=t}resize(){this.dimensions.resize(),this.animatedScroll=this.targetScroll=this.actualScroll,this.emit()}emit(){this.emitter.emit("scroll",this)}reset(){this.isLocked=!1,this.isScrolling=!1,this.animatedScroll=this.targetScroll=this.actualScroll,this.lastVelocity=this.velocity=0,this.animate.stop()}start(){this.isStopped&&(this.isStopped=!1,this.reset())}stop(){this.isStopped||(this.isStopped=!0,this.animate.stop(),this.reset())}raf(t){const e=t-(this.time||t);this.time=t,this.animate.advance(.001*e)}scrollTo(t,{offset:e=0,immediate:i=!1,lock:s=!1,duration:o=this.options.duration,easing:n=this.options.easing,lerp:r=this.options.lerp,onStart:l,onComplete:h,force:a=!1,programmatic:c=!0,userData:d}={}){if(!this.isStopped&&!this.isLocked||a){if("string"==typeof t&&["top","left","start"].includes(t))t=0;else if("string"==typeof t&&["bottom","right","end"].includes(t))t=this.limit;else{let i;if("string"==typeof t?i=document.querySelector(t):t instanceof HTMLElement&&(null==t?void 0:t.nodeType)&&(i=t),i){if(this.options.wrapper!==window){const t=this.rootElement.getBoundingClientRect();e-=this.isHorizontal?t.left:t.top}const s=i.getBoundingClientRect();t=(this.isHorizontal?s.left:s.top)+this.animatedScroll}}if("number"==typeof t){if(t+=e,t=Math.round(t),this.options.infinite?c&&(this.targetScroll=this.animatedScroll=this.scroll):t=clamp(0,t,this.limit),t===this.targetScroll)return null==l||l(this),void(null==h||h(this));if(this.userData=null!=d?d:{},i)return this.animatedScroll=this.targetScroll=t,this.setScroll(this.scroll),this.reset(),this.preventNextNativeScrollEvent(),this.emit(),null==h||h(this),void(this.userData={});c||(this.targetScroll=t),this.animate.fromTo(this.animatedScroll,t,{duration:o,easing:n,lerp:r,onStart:()=>{s&&(this.isLocked=!0),this.isScrolling="smooth",null==l||l(this)},onUpdate:(t,e)=>{this.isScrolling="smooth",this.lastVelocity=this.velocity,this.velocity=t-this.animatedScroll,this.direction=Math.sign(this.velocity),this.animatedScroll=t,this.setScroll(this.scroll),c&&(this.targetScroll=t),e||this.emit(),e&&(this.reset(),this.emit(),null==h||h(this),this.userData={},this.preventNextNativeScrollEvent())}})}}}preventNextNativeScrollEvent(){__classPrivateFieldSet(this,n,!0,"f"),requestAnimationFrame((()=>{__classPrivateFieldSet(this,n,!1,"f")}))}get rootElement(){return this.options.wrapper===window?document.documentElement:this.options.wrapper}get limit(){return this.options.__experimental__naiveDimensions?this.isHorizontal?this.rootElement.scrollWidth-this.rootElement.clientWidth:this.rootElement.scrollHeight-this.rootElement.clientHeight:this.dimensions.limit[this.isHorizontal?"x":"y"]}get isHorizontal(){return"horizontal"===this.options.orientation}get actualScroll(){return this.isHorizontal?this.rootElement.scrollLeft:this.rootElement.scrollTop}get scroll(){return this.options.infinite?function modulo(t,e){return(t%e+e)%e}(this.animatedScroll,this.limit):this.animatedScroll}get progress(){return 0===this.limit?1:this.scroll/this.limit}get isScrolling(){return __classPrivateFieldGet(this,i,"f")}set isScrolling(t){__classPrivateFieldGet(this,i,"f")!==t&&(__classPrivateFieldSet(this,i,t,"f"),this.updateClassName())}get isStopped(){return __classPrivateFieldGet(this,s,"f")}set isStopped(t){__classPrivateFieldGet(this,s,"f")!==t&&(__classPrivateFieldSet(this,s,t,"f"),this.updateClassName())}get isLocked(){return __classPrivateFieldGet(this,o,"f")}set isLocked(t){__classPrivateFieldGet(this,o,"f")!==t&&(__classPrivateFieldSet(this,o,t,"f"),this.updateClassName())}get isSmooth(){return"smooth"===this.isScrolling}get className(){let t="lenis";return this.isStopped&&(t+=" lenis-stopped"),this.isLocked&&(t+=" lenis-locked"),this.isScrolling&&(t+=" lenis-scrolling"),"smooth"===this.isScrolling&&(t+=" lenis-smooth"),t}updateClassName(){this.cleanUpClassName(),this.rootElement.className=`${this.rootElement.className} ${this.className}`.trim()}cleanUpClassName(){this.rootElement.className=this.rootElement.className.replace(/lenis(-\w+)?/g,"").trim()}}}));
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).Lenis=i()}(this,(function(){"use strict";function clamp(t,i,e){return Math.max(t,Math.min(i,e))}class Animate{constructor(){this.isRunning=!1,this.value=0,this.from=0,this.to=0,this.currentTime=0}advance(t){var i;if(!this.isRunning)return;let e=!1;if(this.duration&&this.easing){this.currentTime+=t;const i=clamp(0,this.currentTime/this.duration,1);e=i>=1;const s=e?1:this.easing(i);this.value=this.from+(this.to-this.from)*s}else this.lerp?(this.value=function damp(t,i,e,s){return function lerp(t,i,e){return(1-e)*t+e*i}(t,i,1-Math.exp(-e*s))}(this.value,this.to,60*this.lerp,t),Math.round(this.value)===this.to&&(this.value=this.to,e=!0)):(this.value=this.to,e=!0);e&&this.stop(),null===(i=this.onUpdate)||void 0===i||i.call(this,this.value,e)}stop(){this.isRunning=!1}fromTo(t,i,{lerp:e,duration:s,easing:o,onStart:n,onUpdate:l}){this.from=this.value=t,this.to=i,this.lerp=e,this.duration=s,this.easing=o,this.currentTime=0,this.isRunning=!0,null==n||n(),this.onUpdate=l}}class Dimensions{constructor(t,i,{autoResize:e=!0,debounce:s=250}={}){this.wrapper=t,this.content=i,this.width=0,this.height=0,this.scrollHeight=0,this.scrollWidth=0,this.resize=()=>{this.onWrapperResize(),this.onContentResize()},this.onWrapperResize=()=>{this.wrapper instanceof Window?(this.width=window.innerWidth,this.height=window.innerHeight):(this.width=this.wrapper.clientWidth,this.height=this.wrapper.clientHeight)},this.onContentResize=()=>{this.wrapper instanceof Window?(this.scrollHeight=this.content.scrollHeight,this.scrollWidth=this.content.scrollWidth):(this.scrollHeight=this.wrapper.scrollHeight,this.scrollWidth=this.wrapper.scrollWidth)},e&&(this.debouncedResize=function debounce(t,i){let e;return function(...s){let o=this;clearTimeout(e),e=setTimeout((()=>{e=void 0,t.apply(o,s)}),i)}}(this.resize,s),this.wrapper instanceof Window?window.addEventListener("resize",this.debouncedResize,!1):(this.wrapperResizeObserver=new ResizeObserver(this.debouncedResize),this.wrapperResizeObserver.observe(this.wrapper)),this.contentResizeObserver=new ResizeObserver(this.debouncedResize),this.contentResizeObserver.observe(this.content)),this.resize()}destroy(){var t,i;null===(t=this.wrapperResizeObserver)||void 0===t||t.disconnect(),null===(i=this.contentResizeObserver)||void 0===i||i.disconnect(),this.wrapper===window&&this.debouncedResize&&window.removeEventListener("resize",this.debouncedResize,!1)}get limit(){return{x:this.scrollWidth-this.width,y:this.scrollHeight-this.height}}}class Emitter{constructor(){this.events={}}emit(t,...i){var e;let s=this.events[t]||[];for(let t=0,o=s.length;t<o;t++)null===(e=s[t])||void 0===e||e.call(s,...i)}on(t,i){var e;return(null===(e=this.events[t])||void 0===e?void 0:e.push(i))||(this.events[t]=[i]),()=>{var e;this.events[t]=null===(e=this.events[t])||void 0===e?void 0:e.filter((t=>i!==t))}}off(t,i){var e;this.events[t]=null===(e=this.events[t])||void 0===e?void 0:e.filter((t=>i!==t))}destroy(){this.events={}}}const t=100/6,i={passive:!1};class VirtualScroll{constructor(e,s={wheelMultiplier:1,touchMultiplier:1}){this.element=e,this.options=s,this.touchStart={x:0,y:0},this.lastDelta={x:0,y:0},this.window={width:0,height:0},this.emitter=new Emitter,this.onTouchStart=t=>{const{clientX:i,clientY:e}=t.targetTouches?t.targetTouches[0]:t;this.touchStart.x=i,this.touchStart.y=e,this.lastDelta={x:0,y:0},this.emitter.emit("scroll",{deltaX:0,deltaY:0,event:t})},this.onTouchMove=t=>{const{clientX:i,clientY:e}=t.targetTouches?t.targetTouches[0]:t,s=-(i-this.touchStart.x)*this.options.touchMultiplier,o=-(e-this.touchStart.y)*this.options.touchMultiplier;this.touchStart.x=i,this.touchStart.y=e,this.lastDelta={x:s,y:o},this.emitter.emit("scroll",{deltaX:s,deltaY:o,event:t})},this.onTouchEnd=t=>{this.emitter.emit("scroll",{deltaX:this.lastDelta.x,deltaY:this.lastDelta.y,event:t})},this.onWheel=i=>{let{deltaX:e,deltaY:s,deltaMode:o}=i;e*=1===o?t:2===o?this.window.width:1,s*=1===o?t:2===o?this.window.height:1,e*=this.options.wheelMultiplier,s*=this.options.wheelMultiplier,this.emitter.emit("scroll",{deltaX:e,deltaY:s,event:i})},this.onWindowResize=()=>{this.window={width:window.innerWidth,height:window.innerHeight}},window.addEventListener("resize",this.onWindowResize,!1),this.onWindowResize(),this.element.addEventListener("wheel",this.onWheel,i),this.element.addEventListener("touchstart",this.onTouchStart,i),this.element.addEventListener("touchmove",this.onTouchMove,i),this.element.addEventListener("touchend",this.onTouchEnd,i)}on(t,i){return this.emitter.on(t,i)}destroy(){this.emitter.destroy(),window.removeEventListener("resize",this.onWindowResize,!1),this.element.removeEventListener("wheel",this.onWheel,i),this.element.removeEventListener("touchstart",this.onTouchStart,i),this.element.removeEventListener("touchmove",this.onTouchMove,i),this.element.removeEventListener("touchend",this.onTouchEnd,i)}}return class Lenis{constructor({wrapper:t=window,content:i=document.documentElement,eventsTarget:e=t,smoothWheel:s=!0,syncTouch:o=!1,syncTouchLerp:n=.075,touchInertiaMultiplier:l=35,duration:r,easing:h=(t=>Math.min(1,1.001-Math.pow(2,-10*t))),lerp:a=.1,infinite:c=!1,orientation:u="vertical",gestureOrientation:d="vertical",touchMultiplier:p=1,wheelMultiplier:m=1,autoResize:v=!0,prevent:g,virtualScroll:S,__experimental__naiveDimensions:w=!1}={}){this._isScrolling=!1,this._isStopped=!1,this._isLocked=!1,this._preventNextNativeScrollEvent=!1,this._resetVelocityTimeout=null,this.time=0,this.userData={},this.lastVelocity=0,this.velocity=0,this.direction=0,this.animate=new Animate,this.emitter=new Emitter,this.onPointerDown=t=>{1===t.button&&this.reset()},this.onVirtualScroll=t=>{if("function"==typeof this.options.virtualScroll&&!1===this.options.virtualScroll(t))return;const{deltaX:i,deltaY:e,event:s}=t;if(this.emitter.emit("virtual-scroll",{deltaX:i,deltaY:e,event:s}),s.ctrlKey)return;const o=s.type.includes("touch"),n=s.type.includes("wheel");this.isTouching="touchstart"===s.type||"touchmove"===s.type;if(this.options.syncTouch&&o&&"touchstart"===s.type&&!this.isStopped&&!this.isLocked)return void this.reset();const l=0===i&&0===e,r="vertical"===this.options.gestureOrientation&&0===e||"horizontal"===this.options.gestureOrientation&&0===i;if(l||r)return;let h=s.composedPath();h=h.slice(0,h.indexOf(this.rootElement));const a=this.options.prevent;if(h.find((t=>{var i,e,s,l,r;return t instanceof HTMLElement&&("function"==typeof a&&(null==a?void 0:a(t))||(null===(i=t.hasAttribute)||void 0===i?void 0:i.call(t,"data-lenis-prevent"))||o&&(null===(e=t.hasAttribute)||void 0===e?void 0:e.call(t,"data-lenis-prevent-touch"))||n&&(null===(s=t.hasAttribute)||void 0===s?void 0:s.call(t,"data-lenis-prevent-wheel"))||(null===(l=t.classList)||void 0===l?void 0:l.contains("lenis"))&&!(null===(r=t.classList)||void 0===r?void 0:r.contains("lenis-stopped")))})))return;if(this.isStopped||this.isLocked)return void s.preventDefault();if(!(this.options.syncTouch&&o||this.options.smoothWheel&&n))return this.isScrolling="native",void this.animate.stop();s.preventDefault();let c=e;"both"===this.options.gestureOrientation?c=Math.abs(e)>Math.abs(i)?e:i:"horizontal"===this.options.gestureOrientation&&(c=i);const u=o&&this.options.syncTouch,d=o&&"touchend"===s.type&&Math.abs(c)>5;d&&(c=this.velocity*this.options.touchInertiaMultiplier),this.scrollTo(this.targetScroll+c,Object.assign({programmatic:!1},u?{lerp:d?this.options.syncTouchLerp:1}:{lerp:this.options.lerp,duration:this.options.duration,easing:this.options.easing}))},this.onNativeScroll=()=>{if(null!==this._resetVelocityTimeout&&(clearTimeout(this._resetVelocityTimeout),this._resetVelocityTimeout=null),this._preventNextNativeScrollEvent)this._preventNextNativeScrollEvent=!1;else if(!1===this.isScrolling||"native"===this.isScrolling){const t=this.animatedScroll;this.animatedScroll=this.targetScroll=this.actualScroll,this.lastVelocity=this.velocity,this.velocity=this.animatedScroll-t,this.direction=Math.sign(this.animatedScroll-t),this.isScrolling="native",this.emit(),0!==this.velocity&&(this._resetVelocityTimeout=setTimeout((()=>{this.lastVelocity=this.velocity,this.velocity=0,this.isScrolling=!1,this.emit()}),400))}},window.lenisVersion="1.1.13",t&&t!==document.documentElement&&t!==document.body||(t=window),this.options={wrapper:t,content:i,eventsTarget:e,smoothWheel:s,syncTouch:o,syncTouchLerp:n,touchInertiaMultiplier:l,duration:r,easing:h,lerp:a,infinite:c,gestureOrientation:d,orientation:u,touchMultiplier:p,wheelMultiplier:m,autoResize:v,prevent:g,virtualScroll:S,__experimental__naiveDimensions:w},this.dimensions=new Dimensions(t,i,{autoResize:v}),this.updateClassName(),this.targetScroll=this.animatedScroll=this.actualScroll,this.options.wrapper.addEventListener("scroll",this.onNativeScroll,!1),this.options.wrapper.addEventListener("pointerdown",this.onPointerDown,!1),this.virtualScroll=new VirtualScroll(e,{touchMultiplier:p,wheelMultiplier:m}),this.virtualScroll.on("scroll",this.onVirtualScroll)}destroy(){this.emitter.destroy(),this.options.wrapper.removeEventListener("scroll",this.onNativeScroll,!1),this.options.wrapper.removeEventListener("pointerdown",this.onPointerDown,!1),this.virtualScroll.destroy(),this.dimensions.destroy(),this.cleanUpClassName()}on(t,i){return this.emitter.on(t,i)}off(t,i){return this.emitter.off(t,i)}setScroll(t){this.isHorizontal?this.rootElement.scrollLeft=t:this.rootElement.scrollTop=t}resize(){this.dimensions.resize(),this.animatedScroll=this.targetScroll=this.actualScroll,this.emit()}emit(){this.emitter.emit("scroll",this)}reset(){this.isLocked=!1,this.isScrolling=!1,this.animatedScroll=this.targetScroll=this.actualScroll,this.lastVelocity=this.velocity=0,this.animate.stop()}start(){this.isStopped&&(this.isStopped=!1,this.reset())}stop(){this.isStopped||(this.isStopped=!0,this.animate.stop(),this.reset())}raf(t){const i=t-(this.time||t);this.time=t,this.animate.advance(.001*i)}scrollTo(t,{offset:i=0,immediate:e=!1,lock:s=!1,duration:o=this.options.duration,easing:n=this.options.easing,lerp:l=this.options.lerp,onStart:r,onComplete:h,force:a=!1,programmatic:c=!0,userData:u}={}){if(!this.isStopped&&!this.isLocked||a){if("string"==typeof t&&["top","left","start"].includes(t))t=0;else if("string"==typeof t&&["bottom","right","end"].includes(t))t=this.limit;else{let e;if("string"==typeof t?e=document.querySelector(t):t instanceof HTMLElement&&(null==t?void 0:t.nodeType)&&(e=t),e){if(this.options.wrapper!==window){const t=this.rootElement.getBoundingClientRect();i-=this.isHorizontal?t.left:t.top}const s=e.getBoundingClientRect();t=(this.isHorizontal?s.left:s.top)+this.animatedScroll}}if("number"==typeof t){if(t+=i,t=Math.round(t),this.options.infinite?c&&(this.targetScroll=this.animatedScroll=this.scroll):t=clamp(0,t,this.limit),t===this.targetScroll)return null==r||r(this),void(null==h||h(this));if(this.userData=null!=u?u:{},e)return this.animatedScroll=this.targetScroll=t,this.setScroll(this.scroll),this.reset(),this.preventNextNativeScrollEvent(),this.emit(),null==h||h(this),void(this.userData={});c||(this.targetScroll=t),this.animate.fromTo(this.animatedScroll,t,{duration:o,easing:n,lerp:l,onStart:()=>{s&&(this.isLocked=!0),this.isScrolling="smooth",null==r||r(this)},onUpdate:(t,i)=>{this.isScrolling="smooth",this.lastVelocity=this.velocity,this.velocity=t-this.animatedScroll,this.direction=Math.sign(this.velocity),this.animatedScroll=t,this.setScroll(this.scroll),c&&(this.targetScroll=t),i||this.emit(),i&&(this.reset(),this.emit(),null==h||h(this),this.userData={},this.preventNextNativeScrollEvent())}})}}}preventNextNativeScrollEvent(){this._preventNextNativeScrollEvent=!0,requestAnimationFrame((()=>{this._preventNextNativeScrollEvent=!1}))}get rootElement(){return this.options.wrapper===window?document.documentElement:this.options.wrapper}get limit(){return this.options.__experimental__naiveDimensions?this.isHorizontal?this.rootElement.scrollWidth-this.rootElement.clientWidth:this.rootElement.scrollHeight-this.rootElement.clientHeight:this.dimensions.limit[this.isHorizontal?"x":"y"]}get isHorizontal(){return"horizontal"===this.options.orientation}get actualScroll(){return this.isHorizontal?this.rootElement.scrollLeft:this.rootElement.scrollTop}get scroll(){return this.options.infinite?function modulo(t,i){return(t%i+i)%i}(this.animatedScroll,this.limit):this.animatedScroll}get progress(){return 0===this.limit?1:this.scroll/this.limit}get isScrolling(){return this._isScrolling}set isScrolling(t){this._isScrolling!==t&&(this._isScrolling=t,this.updateClassName())}get isStopped(){return this._isStopped}set isStopped(t){this._isStopped!==t&&(this._isStopped=t,this.updateClassName())}get isLocked(){return this._isLocked}set isLocked(t){this._isLocked!==t&&(this._isLocked=t,this.updateClassName())}get isSmooth(){return"smooth"===this.isScrolling}get className(){let t="lenis";return this.isStopped&&(t+=" lenis-stopped"),this.isLocked&&(t+=" lenis-locked"),this.isScrolling&&(t+=" lenis-scrolling"),"smooth"===this.isScrolling&&(t+=" lenis-smooth"),t}updateClassName(){this.cleanUpClassName(),this.rootElement.className=`${this.rootElement.className} ${this.className}`.trim()}cleanUpClassName(){this.rootElement.className=this.rootElement.className.replace(/lenis(-\w+)?/g,"").trim()}}}));
//# sourceMappingURL=lenis.min.js.map
{
"name": "lenis",
"version": "1.1.12",
"version": "1.1.13",
"author": "darkroom.engineering",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -48,3 +48,3 @@ [![LENIS](https://assets.darkroom.engineering/lenis/header.png)](https://github.com/darkroomengineering/lenis)

```html
<script src="https://unpkg.com/lenis@1.1.12/dist/lenis.min.js"></script>
<script src="https://unpkg.com/lenis@1.1.13/dist/lenis.min.js"></script>
```

@@ -101,3 +101,3 @@

```html
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.12/dist/lenis.css">
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.13/dist/lenis.css">
```

@@ -104,0 +104,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc