lenis 1.3.12-dev.0 → 1.3.12-dev.2
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/dist/lenis-snap.d.ts +16 -7
- package/dist/lenis-snap.js +87 -52
- package/dist/lenis-snap.js.map +1 -1
- package/dist/lenis-snap.min.js +1 -1
- package/dist/lenis-snap.min.js.map +1 -1
- package/dist/lenis-snap.mjs +87 -52
- package/dist/lenis-snap.mjs.map +1 -1
- package/dist/lenis.js +1 -1
- package/dist/lenis.js.map +1 -1
- package/dist/lenis.min.js +1 -1
- package/dist/lenis.min.js.map +1 -1
- package/dist/lenis.mjs +1 -1
- package/dist/lenis.mjs.map +1 -1
- package/package.json +1 -1
package/dist/lenis-snap.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Lenis, { EasingFunction } from 'lenis';
|
|
1
|
+
import Lenis, { EasingFunction, VirtualScrollData } from 'lenis';
|
|
2
2
|
|
|
3
3
|
type SnapElementOptions = {
|
|
4
4
|
align?: string | string[];
|
|
@@ -23,6 +23,7 @@ declare class SnapElement {
|
|
|
23
23
|
rect: Rect;
|
|
24
24
|
wrapperResizeObserver: ResizeObserver;
|
|
25
25
|
resizeObserver: ResizeObserver;
|
|
26
|
+
debouncedWrapperResize: () => void;
|
|
26
27
|
constructor(element: HTMLElement, { align, ignoreSticky, ignoreTransform, }?: SnapElementOptions);
|
|
27
28
|
destroy(): void;
|
|
28
29
|
setRect({ top, left, width, height, element, }?: {
|
|
@@ -39,13 +40,15 @@ declare class SnapElement {
|
|
|
39
40
|
type SnapItem = {
|
|
40
41
|
value: number;
|
|
41
42
|
};
|
|
42
|
-
type OnSnapCallback = (item: SnapItem
|
|
43
|
+
type OnSnapCallback = (item: SnapItem & {
|
|
44
|
+
index?: number;
|
|
45
|
+
}) => void;
|
|
43
46
|
type SnapOptions = {
|
|
44
47
|
/**
|
|
45
48
|
* Snap type
|
|
46
49
|
* @default mandatory
|
|
47
50
|
*/
|
|
48
|
-
type?: 'mandatory' | 'proximity' | '
|
|
51
|
+
type?: 'mandatory' | 'proximity' | 'lock';
|
|
49
52
|
/**
|
|
50
53
|
* Linear interpolation (lerp) intensity (between 0 and 1)
|
|
51
54
|
*/
|
|
@@ -112,9 +115,10 @@ declare class Snap {
|
|
|
112
115
|
height: number;
|
|
113
116
|
};
|
|
114
117
|
isStopped: boolean;
|
|
115
|
-
onSnapDebounced
|
|
116
|
-
currentSnapIndex
|
|
117
|
-
constructor(lenis: Lenis, { type, lerp, easing, duration, distanceThreshold,
|
|
118
|
+
onSnapDebounced: (e: VirtualScrollData) => void;
|
|
119
|
+
currentSnapIndex?: number;
|
|
120
|
+
constructor(lenis: Lenis, { type, lerp, easing, duration, distanceThreshold, // useless when type is "mandatory"
|
|
121
|
+
debounce: debounceDelay, onSnapStart, onSnapComplete, }?: SnapOptions);
|
|
118
122
|
/**
|
|
119
123
|
* Destroy the snap instance
|
|
120
124
|
*/
|
|
@@ -143,10 +147,15 @@ declare class Snap {
|
|
|
143
147
|
* @returns Unsubscribe function
|
|
144
148
|
*/
|
|
145
149
|
addElement(element: HTMLElement, options?: SnapElementOptions): () => boolean;
|
|
150
|
+
addElements(elements: HTMLElement[], options?: SnapElementOptions): void;
|
|
146
151
|
private onWindowResize;
|
|
147
152
|
private computeSnaps;
|
|
148
|
-
|
|
153
|
+
previous(): void;
|
|
154
|
+
next(): void;
|
|
155
|
+
goTo(index: number): void;
|
|
156
|
+
get distanceThreshold(): number;
|
|
149
157
|
private onSnap;
|
|
158
|
+
resize(): void;
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
export { type OnSnapCallback, type SnapItem, type SnapOptions, Snap as default };
|
package/dist/lenis-snap.js
CHANGED
|
@@ -68,6 +68,7 @@ var SnapElement = class {
|
|
|
68
68
|
rect = {};
|
|
69
69
|
wrapperResizeObserver;
|
|
70
70
|
resizeObserver;
|
|
71
|
+
debouncedWrapperResize;
|
|
71
72
|
constructor(element, {
|
|
72
73
|
align = ["start"],
|
|
73
74
|
ignoreSticky = true,
|
|
@@ -76,7 +77,8 @@ var SnapElement = class {
|
|
|
76
77
|
this.element = element;
|
|
77
78
|
this.options = { align, ignoreSticky, ignoreTransform };
|
|
78
79
|
this.align = [align].flat();
|
|
79
|
-
this.
|
|
80
|
+
this.debouncedWrapperResize = debounce(this.onWrapperResize, 500);
|
|
81
|
+
this.wrapperResizeObserver = new ResizeObserver(this.debouncedWrapperResize);
|
|
80
82
|
this.wrapperResizeObserver.observe(document.body);
|
|
81
83
|
this.onWrapperResize();
|
|
82
84
|
this.resizeObserver = new ResizeObserver(this.onResize);
|
|
@@ -143,13 +145,13 @@ function uid() {
|
|
|
143
145
|
|
|
144
146
|
// packages/snap/src/snap.ts
|
|
145
147
|
var Snap = class {
|
|
146
|
-
// used for slide type
|
|
147
148
|
constructor(lenis, {
|
|
148
149
|
type = "proximity",
|
|
149
150
|
lerp,
|
|
150
151
|
easing,
|
|
151
152
|
duration,
|
|
152
153
|
distanceThreshold = "50%",
|
|
154
|
+
// useless when type is "mandatory"
|
|
153
155
|
debounce: debounceDelay = 500,
|
|
154
156
|
onSnapStart,
|
|
155
157
|
onSnapComplete
|
|
@@ -167,12 +169,11 @@ var Snap = class {
|
|
|
167
169
|
};
|
|
168
170
|
this.onWindowResize();
|
|
169
171
|
window.addEventListener("resize", this.onWindowResize, false);
|
|
170
|
-
|
|
171
|
-
this.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
172
|
+
this.onSnapDebounced = debounce(
|
|
173
|
+
this.onSnap,
|
|
174
|
+
this.options.type === "lock" ? 0 : this.options.debounce
|
|
175
|
+
);
|
|
176
|
+
this.lenis.on("virtual-scroll", this.onSnapDebounced);
|
|
176
177
|
}
|
|
177
178
|
options;
|
|
178
179
|
elements = /* @__PURE__ */ new Map();
|
|
@@ -183,7 +184,7 @@ var Snap = class {
|
|
|
183
184
|
};
|
|
184
185
|
isStopped = false;
|
|
185
186
|
onSnapDebounced;
|
|
186
|
-
currentSnapIndex
|
|
187
|
+
currentSnapIndex;
|
|
187
188
|
/**
|
|
188
189
|
* Destroy the snap instance
|
|
189
190
|
*/
|
|
@@ -228,6 +229,9 @@ var Snap = class {
|
|
|
228
229
|
this.elements.set(id, new SnapElement(element, options));
|
|
229
230
|
return () => this.elements.delete(id);
|
|
230
231
|
}
|
|
232
|
+
addElements(elements, options = {}) {
|
|
233
|
+
elements.forEach((element) => this.addElement(element, options));
|
|
234
|
+
}
|
|
231
235
|
onWindowResize = () => {
|
|
232
236
|
this.viewport.width = window.innerWidth;
|
|
233
237
|
this.viewport.height = window.innerHeight;
|
|
@@ -253,50 +257,53 @@ var Snap = class {
|
|
|
253
257
|
snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value));
|
|
254
258
|
return snaps;
|
|
255
259
|
};
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
previous() {
|
|
261
|
+
this.goTo((this.currentSnapIndex ?? 0) - 1);
|
|
262
|
+
}
|
|
263
|
+
next() {
|
|
264
|
+
this.goTo((this.currentSnapIndex ?? 0) + 1);
|
|
265
|
+
}
|
|
266
|
+
goTo(index2) {
|
|
259
267
|
const snaps = this.computeSnaps();
|
|
260
268
|
if (snaps.length === 0) return;
|
|
261
|
-
|
|
262
|
-
this.currentSnapIndex += 1;
|
|
263
|
-
} else if (direction === -1) {
|
|
264
|
-
this.currentSnapIndex -= 1;
|
|
265
|
-
}
|
|
266
|
-
this.currentSnapIndex = Math.max(
|
|
267
|
-
0,
|
|
268
|
-
Math.min(this.currentSnapIndex, snaps.length - 1)
|
|
269
|
-
);
|
|
269
|
+
this.currentSnapIndex = Math.max(0, Math.min(index2, snaps.length - 1));
|
|
270
270
|
const currentSnap = snaps[this.currentSnapIndex];
|
|
271
271
|
if (currentSnap === void 0) return;
|
|
272
272
|
this.lenis.scrollTo(currentSnap.value, {
|
|
273
273
|
duration: this.options.duration,
|
|
274
274
|
easing: this.options.easing,
|
|
275
275
|
lerp: this.options.lerp,
|
|
276
|
-
lock:
|
|
276
|
+
lock: this.options.type === "lock",
|
|
277
277
|
userData: { initiator: "snap" },
|
|
278
278
|
onStart: () => {
|
|
279
|
-
this.options.onSnapStart?.(
|
|
279
|
+
this.options.onSnapStart?.({
|
|
280
|
+
index: this.currentSnapIndex,
|
|
281
|
+
...currentSnap
|
|
282
|
+
});
|
|
280
283
|
},
|
|
281
284
|
onComplete: () => {
|
|
282
|
-
this.options.onSnapComplete?.(
|
|
285
|
+
this.options.onSnapComplete?.({
|
|
286
|
+
index: this.currentSnapIndex,
|
|
287
|
+
...currentSnap
|
|
288
|
+
});
|
|
283
289
|
}
|
|
284
290
|
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
291
|
+
}
|
|
292
|
+
// private onSlide = (e: VirtualScrollData) => {
|
|
293
|
+
// if (this.isStopped) return
|
|
294
|
+
// const { userData, isHorizontal } = this.lenis
|
|
295
|
+
// if (userData?.initiator === 'snap') return
|
|
296
|
+
// const delta = isHorizontal ? e.deltaX : e.deltaY
|
|
297
|
+
// if (delta > 0) {
|
|
298
|
+
// this.next()
|
|
299
|
+
// } else if (delta < 0) {
|
|
300
|
+
// this.previous()
|
|
301
|
+
// }
|
|
302
|
+
// }
|
|
303
|
+
get distanceThreshold() {
|
|
304
|
+
let distanceThreshold = Infinity;
|
|
305
|
+
if (this.options.type === "mandatory") return Infinity;
|
|
306
|
+
const { isHorizontal } = this.lenis;
|
|
300
307
|
const axis = isHorizontal ? "width" : "height";
|
|
301
308
|
if (typeof this.options.distanceThreshold === "string" && this.options.distanceThreshold.endsWith("%")) {
|
|
302
309
|
distanceThreshold = Number(this.options.distanceThreshold.replace("%", "")) / 100 * this.viewport[axis];
|
|
@@ -305,21 +312,49 @@ var Snap = class {
|
|
|
305
312
|
} else {
|
|
306
313
|
distanceThreshold = this.viewport[axis];
|
|
307
314
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
315
|
+
return distanceThreshold;
|
|
316
|
+
}
|
|
317
|
+
onSnap = (e) => {
|
|
318
|
+
if (this.isStopped) return;
|
|
319
|
+
if (this.options.type === "lock" && this.lenis.userData?.initiator === "snap")
|
|
320
|
+
return;
|
|
321
|
+
let { scroll, isHorizontal } = this.lenis;
|
|
322
|
+
const delta = isHorizontal ? e.deltaX : e.deltaY;
|
|
323
|
+
scroll = Math.ceil(this.lenis.scroll);
|
|
324
|
+
const snaps = this.computeSnaps();
|
|
325
|
+
if (snaps.length === 0) return;
|
|
326
|
+
let snapIndex;
|
|
327
|
+
if (this.options.type === "lock") {
|
|
328
|
+
if (delta > 0) {
|
|
329
|
+
const currentSnapIndex = snaps.findIndex(({ value }) => value > scroll);
|
|
330
|
+
snapIndex = currentSnapIndex;
|
|
331
|
+
} else if (delta < 0) {
|
|
332
|
+
const currentSnapIndex = snaps.findLastIndex(
|
|
333
|
+
({ value }) => value < scroll
|
|
334
|
+
);
|
|
335
|
+
snapIndex = currentSnapIndex;
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
let prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll);
|
|
339
|
+
const prevSnap = snaps[prevSnapIndex];
|
|
340
|
+
const distanceToPrevSnap = Math.abs(scroll - prevSnap.value);
|
|
341
|
+
let nextSnapIndex = snaps.findIndex(({ value }) => value > scroll);
|
|
342
|
+
const nextSnap = snaps[nextSnapIndex];
|
|
343
|
+
const distanceToNextSnap = Math.abs(scroll - nextSnap.value);
|
|
344
|
+
snapIndex = distanceToPrevSnap < distanceToNextSnap ? prevSnapIndex : nextSnapIndex;
|
|
345
|
+
}
|
|
346
|
+
if (snapIndex === void 0) return;
|
|
347
|
+
if (snapIndex === -1) return;
|
|
348
|
+
snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1));
|
|
349
|
+
const snap = snaps[snapIndex];
|
|
350
|
+
const distance = Math.abs(scroll - snap.value);
|
|
351
|
+
if (distance <= this.distanceThreshold) {
|
|
352
|
+
this.goTo(snapIndex);
|
|
321
353
|
}
|
|
322
354
|
};
|
|
355
|
+
resize() {
|
|
356
|
+
this.elements.forEach((element) => element.onWrapperResize());
|
|
357
|
+
}
|
|
323
358
|
};
|
|
324
359
|
|
|
325
360
|
// packages/snap/browser.ts
|
package/dist/lenis-snap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../packages/snap/src/debounce.ts","../packages/snap/src/element.ts","../packages/snap/src/uid.ts","../packages/snap/src/snap.ts","../packages/snap/browser.ts"],"sourcesContent":["export function debounce<CB extends (...args: any[]) => void>(\r\n callback: CB,\r\n delay: number\r\n) {\r\n let timer: number | undefined\r\n return function <T>(this: T, ...args: Parameters<typeof callback>) {\r\n let context = this\r\n clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n timer = undefined\r\n callback.apply(context, args)\r\n }, delay)\r\n }\r\n}\r\n","function removeParentSticky(element: HTMLElement) {\r\n const position = getComputedStyle(element).position\r\n\r\n const isSticky = position === 'sticky'\r\n\r\n if (isSticky) {\r\n element.style.setProperty('position', 'static')\r\n element.dataset.sticky = 'true'\r\n }\r\n\r\n if (element.offsetParent) {\r\n removeParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction addParentSticky(element: HTMLElement) {\r\n if (element?.dataset?.sticky === 'true') {\r\n element.style.removeProperty('position')\r\n delete element.dataset.sticky\r\n }\r\n\r\n if (element.offsetParent) {\r\n addParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction offsetTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.offsetTop\r\n if (element.offsetParent) {\r\n return offsetTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top\r\n}\r\n\r\nfunction offsetLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.offsetLeft\r\n if (element.offsetParent) {\r\n return offsetLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left\r\n}\r\n\r\nfunction scrollTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.scrollTop\r\n if (element.offsetParent) {\r\n return scrollTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top + window.scrollY\r\n}\r\n\r\nfunction scrollLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.scrollLeft\r\n if (element.offsetParent) {\r\n return scrollLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left + window.scrollX\r\n}\r\n\r\nexport type SnapElementOptions = {\r\n align?: string | string[]\r\n ignoreSticky?: boolean\r\n ignoreTransform?: boolean\r\n}\r\n\r\ntype Rect = {\r\n top: number\r\n left: number\r\n width: number\r\n height: number\r\n x: number\r\n y: number\r\n bottom: number\r\n right: number\r\n element: HTMLElement\r\n}\r\n\r\nexport class SnapElement {\r\n element: HTMLElement\r\n options: SnapElementOptions\r\n align: string[]\r\n // @ts-ignore\r\n rect: Rect = {}\r\n wrapperResizeObserver: ResizeObserver\r\n resizeObserver: ResizeObserver\r\n\r\n constructor(\r\n element: HTMLElement,\r\n {\r\n align = ['start'],\r\n ignoreSticky = true,\r\n ignoreTransform = false,\r\n }: SnapElementOptions = {}\r\n ) {\r\n this.element = element\r\n\r\n this.options = { align, ignoreSticky, ignoreTransform }\r\n\r\n // this.ignoreSticky = ignoreSticky\r\n // this.ignoreTransform = ignoreTransform\r\n\r\n this.align = [align].flat()\r\n\r\n // TODO: assing rect immediately\r\n\r\n this.wrapperResizeObserver = new ResizeObserver(this.onWrapperResize)\r\n this.wrapperResizeObserver.observe(document.body)\r\n this.onWrapperResize()\r\n\r\n this.resizeObserver = new ResizeObserver(this.onResize)\r\n this.resizeObserver.observe(this.element)\r\n this.setRect({\r\n width: this.element.offsetWidth,\r\n height: this.element.offsetHeight,\r\n })\r\n }\r\n\r\n destroy() {\r\n this.wrapperResizeObserver.disconnect()\r\n this.resizeObserver.disconnect()\r\n }\r\n\r\n setRect({\r\n top,\r\n left,\r\n width,\r\n height,\r\n element,\r\n }: {\r\n top?: number\r\n left?: number\r\n width?: number\r\n height?: number\r\n element?: HTMLElement\r\n } = {}) {\r\n top = top ?? this.rect.top\r\n left = left ?? this.rect.left\r\n width = width ?? this.rect.width\r\n height = height ?? this.rect.height\r\n element = element ?? this.rect.element\r\n\r\n if (\r\n top === this.rect.top &&\r\n left === this.rect.left &&\r\n width === this.rect.width &&\r\n height === this.rect.height &&\r\n element === this.rect.element\r\n )\r\n return\r\n\r\n this.rect.top = top\r\n this.rect.y = top\r\n this.rect.width = width\r\n this.rect.height = height\r\n this.rect.left = left\r\n this.rect.x = left\r\n this.rect.bottom = top + height\r\n this.rect.right = left + width\r\n }\r\n\r\n onWrapperResize = () => {\r\n let top, left\r\n\r\n if (this.options.ignoreSticky) removeParentSticky(this.element)\r\n if (this.options.ignoreTransform) {\r\n top = offsetTop(this.element)\r\n left = offsetLeft(this.element)\r\n } else {\r\n const rect = this.element.getBoundingClientRect()\r\n top = rect.top + scrollTop(this.element)\r\n left = rect.left + scrollLeft(this.element)\r\n }\r\n if (this.options.ignoreSticky) addParentSticky(this.element)\r\n\r\n this.setRect({ top, left })\r\n }\r\n\r\n onResize = ([entry]: ResizeObserverEntry[]) => {\r\n if (!entry?.borderBoxSize[0]) return\r\n const width = entry.borderBoxSize[0].inlineSize\r\n const height = entry.borderBoxSize[0].blockSize\r\n\r\n this.setRect({ width, height })\r\n }\r\n}\r\n","let index = 0\r\n\r\nexport type UID = number\r\n\r\nexport function uid(): UID {\r\n return index++\r\n}\r\n","import type Lenis from 'lenis'\r\nimport { debounce } from './debounce'\r\nimport type { SnapElementOptions } from './element'\r\nimport { SnapElement } from './element'\r\nimport type { SnapItem, SnapOptions } from './types'\r\nimport type { UID } from './uid'\r\nimport { uid } from './uid'\r\n\r\n// TODO:\r\n// - horizontal\r\n// - fix trackpad snapping too soon due to velocity (fuck Apple)\r\n// - fix wheel scrolling after limits (see console scroll to)\r\n// - fix touch scroll, do not snap when not released\r\n// - arrow, spacebar\r\n\r\ntype RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>\r\n\r\n/**\r\n * Snap class to handle the snap functionality\r\n *\r\n * @example\r\n * const snap = new Snap(lenis, {\r\n * type: 'mandatory', // 'mandatory', 'proximity'\r\n * lerp: 0.1,\r\n * duration: 1,\r\n * easing: (t) => t,\r\n * onSnapStart: (snap) => {\r\n * console.log('onSnapStart', snap)\r\n * },\r\n * onSnapComplete: (snap) => {\r\n * console.log('onSnapComplete', snap)\r\n * },\r\n * })\r\n *\r\n * snap.add(500) // snap at 500px\r\n *\r\n * const removeSnap = snap.add(500)\r\n *\r\n * if (someCondition) {\r\n * removeSnap()\r\n * }\r\n */\r\nexport class Snap {\r\n options: RequiredPick<SnapOptions, 'type' | 'debounce'>\r\n elements = new Map<UID, SnapElement>()\r\n snaps = new Map<UID, SnapItem>()\r\n viewport: { width: number; height: number } = {\r\n width: window.innerWidth,\r\n height: window.innerHeight,\r\n }\r\n isStopped = false\r\n onSnapDebounced?: () => void\r\n currentSnapIndex = 0 // used for slide type\r\n\r\n constructor(\r\n private lenis: Lenis,\r\n {\r\n type = 'proximity',\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold = '50%',\r\n debounce: debounceDelay = 500,\r\n onSnapStart,\r\n onSnapComplete,\r\n }: SnapOptions = {}\r\n ) {\r\n this.options = {\r\n type,\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold,\r\n debounce: debounceDelay,\r\n onSnapStart,\r\n onSnapComplete,\r\n }\r\n\r\n this.onWindowResize()\r\n window.addEventListener('resize', this.onWindowResize, false)\r\n\r\n if (this.options.type === 'slide') {\r\n this.lenis.on('scroll', this.onSlide)\r\n } else {\r\n this.onSnapDebounced = debounce(this.onSnap, this.options.debounce)\r\n\r\n // this.lenis.on('scroll', this.onScroll)\r\n this.lenis.on('virtual-scroll', this.onSnapDebounced)\r\n }\r\n }\r\n\r\n /**\r\n * Destroy the snap instance\r\n */\r\n destroy() {\r\n // this.lenis.off('scroll', this.onScroll)\r\n this.lenis.off('virtual-scroll', this.onSnapDebounced!)\r\n window.removeEventListener('resize', this.onWindowResize, false)\r\n this.elements.forEach((element) => element.destroy())\r\n }\r\n\r\n /**\r\n * Start the snap after it has been stopped\r\n */\r\n start() {\r\n this.isStopped = false\r\n }\r\n\r\n /**\r\n * Stop the snap\r\n */\r\n stop() {\r\n this.isStopped = true\r\n }\r\n\r\n /**\r\n * Add a snap to the snap instance\r\n *\r\n * @param value The value to snap to\r\n * @param userData User data that will be forwarded through the snap event\r\n * @returns Unsubscribe function\r\n */\r\n add(value: number) {\r\n const id = uid()\r\n\r\n this.snaps.set(id, { value })\r\n\r\n return () => this.snaps.delete(id)\r\n }\r\n\r\n /**\r\n * Add an element to the snap instance\r\n *\r\n * @param element The element to add\r\n * @param options The options for the element\r\n * @returns Unsubscribe function\r\n */\r\n addElement(element: HTMLElement, options: SnapElementOptions = {}) {\r\n const id = uid()\r\n\r\n this.elements.set(id, new SnapElement(element, options))\r\n\r\n return () => this.elements.delete(id)\r\n }\r\n\r\n private onWindowResize = () => {\r\n this.viewport.width = window.innerWidth\r\n this.viewport.height = window.innerHeight\r\n }\r\n\r\n private computeSnaps = () => {\r\n const { isHorizontal } = this.lenis\r\n\r\n let snaps = [...this.snaps.values()] as SnapItem[]\r\n\r\n this.elements.forEach(({ rect, align }) => {\r\n let value: number | undefined\r\n\r\n align.forEach((align) => {\r\n if (align === 'start') {\r\n value = rect.top\r\n } else if (align === 'center') {\r\n value = isHorizontal\r\n ? rect.left + rect.width / 2 - this.viewport.width / 2\r\n : rect.top + rect.height / 2 - this.viewport.height / 2\r\n } else if (align === 'end') {\r\n value = isHorizontal\r\n ? rect.left + rect.width - this.viewport.width\r\n : rect.top + rect.height - this.viewport.height\r\n }\r\n\r\n if (typeof value === 'number') {\r\n snaps.push({ value: Math.ceil(value) })\r\n }\r\n })\r\n })\r\n\r\n snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value))\r\n\r\n return snaps\r\n }\r\n\r\n private onSlide = () => {\r\n const { direction, userData } = this.lenis\r\n\r\n if (userData?.initiator === 'snap') return\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n if (direction === 1) {\r\n this.currentSnapIndex += 1\r\n } else if (direction === -1) {\r\n this.currentSnapIndex -= 1\r\n }\r\n\r\n this.currentSnapIndex = Math.max(\r\n 0,\r\n Math.min(this.currentSnapIndex, snaps.length - 1)\r\n )\r\n\r\n const currentSnap = snaps[this.currentSnapIndex]\r\n\r\n if (currentSnap === undefined) return\r\n\r\n this.lenis.scrollTo(currentSnap.value, {\r\n duration: this.options.duration,\r\n easing: this.options.easing,\r\n lerp: this.options.lerp,\r\n lock: true,\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.(currentSnap)\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.(currentSnap)\r\n },\r\n })\r\n }\r\n\r\n private onSnap = () => {\r\n let { scroll, isHorizontal } = this.lenis\r\n scroll = Math.ceil(this.lenis.scroll)\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n let prevSnap = snaps.findLast(({ value }) => value <= scroll)\r\n if (prevSnap === undefined) prevSnap = snaps[0]!\r\n const distanceToPrevSnap = Math.abs(scroll - prevSnap.value)\r\n\r\n let nextSnap = snaps.find(({ value }) => value >= scroll)\r\n if (nextSnap === undefined) nextSnap = snaps[snaps.length - 1]!\r\n const distanceToNextSnap = Math.abs(scroll - nextSnap.value)\r\n\r\n const snap = distanceToPrevSnap < distanceToNextSnap ? prevSnap : nextSnap\r\n\r\n const distance = Math.abs(scroll - snap.value)\r\n\r\n let distanceThreshold\r\n\r\n const axis = isHorizontal ? 'width' : 'height'\r\n\r\n if (\r\n typeof this.options.distanceThreshold === 'string' &&\r\n this.options.distanceThreshold.endsWith('%')\r\n ) {\r\n distanceThreshold =\r\n (Number(this.options.distanceThreshold.replace('%', '')) / 100) *\r\n this.viewport[axis]\r\n } else if (typeof this.options.distanceThreshold === 'number') {\r\n distanceThreshold = this.options.distanceThreshold\r\n } else {\r\n distanceThreshold = this.viewport[axis]\r\n }\r\n\r\n if (\r\n this.options.type === 'mandatory' ||\r\n (this.options.type === 'proximity' && distance <= distanceThreshold)\r\n ) {\r\n // this.__isScrolling = true\r\n // this.onSnapStart?.(snap)\r\n\r\n // console.log('scroll to')\r\n\r\n this.lenis.scrollTo(snap.value, {\r\n lerp: this.options.lerp,\r\n easing: this.options.easing,\r\n duration: this.options.duration,\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.(snap)\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.(snap)\r\n },\r\n })\r\n }\r\n\r\n // console.timeEnd('scroll')\r\n }\r\n}\r\n","// This file serves as an entry point for the package\r\nimport { Snap } from './src/snap'\r\nglobalThis.Snap = Snap\r\n"],"mappings":"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","names":["align"]}
|
|
1
|
+
{"version":3,"sources":["../packages/snap/src/debounce.ts","../packages/snap/src/element.ts","../packages/snap/src/uid.ts","../packages/snap/src/snap.ts","../packages/snap/browser.ts"],"sourcesContent":["export function debounce<CB extends (...args: any[]) => void>(\r\n callback: CB,\r\n delay: number\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | undefined\r\n return function <T>(this: T, ...args: Parameters<typeof callback>): void {\r\n let context = this\r\n clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n timer = undefined\r\n callback.apply(context, args)\r\n }, delay)\r\n }\r\n}\r\n","import { debounce } from './debounce'\r\n\r\nfunction removeParentSticky(element: HTMLElement) {\r\n const position = getComputedStyle(element).position\r\n\r\n const isSticky = position === 'sticky'\r\n\r\n if (isSticky) {\r\n element.style.setProperty('position', 'static')\r\n element.dataset.sticky = 'true'\r\n }\r\n\r\n if (element.offsetParent) {\r\n removeParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction addParentSticky(element: HTMLElement) {\r\n if (element?.dataset?.sticky === 'true') {\r\n element.style.removeProperty('position')\r\n delete element.dataset.sticky\r\n }\r\n\r\n if (element.offsetParent) {\r\n addParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction offsetTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.offsetTop\r\n if (element.offsetParent) {\r\n return offsetTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top\r\n}\r\n\r\nfunction offsetLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.offsetLeft\r\n if (element.offsetParent) {\r\n return offsetLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left\r\n}\r\n\r\nfunction scrollTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.scrollTop\r\n if (element.offsetParent) {\r\n return scrollTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top + window.scrollY\r\n}\r\n\r\nfunction scrollLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.scrollLeft\r\n if (element.offsetParent) {\r\n return scrollLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left + window.scrollX\r\n}\r\n\r\nexport type SnapElementOptions = {\r\n align?: string | string[]\r\n ignoreSticky?: boolean\r\n ignoreTransform?: boolean\r\n}\r\n\r\ntype Rect = {\r\n top: number\r\n left: number\r\n width: number\r\n height: number\r\n x: number\r\n y: number\r\n bottom: number\r\n right: number\r\n element: HTMLElement\r\n}\r\n\r\nexport class SnapElement {\r\n element: HTMLElement\r\n options: SnapElementOptions\r\n align: string[]\r\n // @ts-ignore\r\n rect: Rect = {}\r\n wrapperResizeObserver: ResizeObserver\r\n resizeObserver: ResizeObserver\r\n debouncedWrapperResize: () => void\r\n\r\n constructor(\r\n element: HTMLElement,\r\n {\r\n align = ['start'],\r\n ignoreSticky = true,\r\n ignoreTransform = false,\r\n }: SnapElementOptions = {}\r\n ) {\r\n this.element = element\r\n\r\n this.options = { align, ignoreSticky, ignoreTransform }\r\n\r\n this.align = [align].flat()\r\n\r\n this.debouncedWrapperResize = debounce(this.onWrapperResize, 500)\r\n\r\n this.wrapperResizeObserver = new ResizeObserver(this.debouncedWrapperResize)\r\n this.wrapperResizeObserver.observe(document.body)\r\n this.onWrapperResize()\r\n\r\n this.resizeObserver = new ResizeObserver(this.onResize)\r\n this.resizeObserver.observe(this.element)\r\n this.setRect({\r\n width: this.element.offsetWidth,\r\n height: this.element.offsetHeight,\r\n })\r\n }\r\n\r\n destroy() {\r\n this.wrapperResizeObserver.disconnect()\r\n this.resizeObserver.disconnect()\r\n }\r\n\r\n setRect({\r\n top,\r\n left,\r\n width,\r\n height,\r\n element,\r\n }: {\r\n top?: number\r\n left?: number\r\n width?: number\r\n height?: number\r\n element?: HTMLElement\r\n } = {}) {\r\n top = top ?? this.rect.top\r\n left = left ?? this.rect.left\r\n width = width ?? this.rect.width\r\n height = height ?? this.rect.height\r\n element = element ?? this.rect.element\r\n\r\n if (\r\n top === this.rect.top &&\r\n left === this.rect.left &&\r\n width === this.rect.width &&\r\n height === this.rect.height &&\r\n element === this.rect.element\r\n )\r\n return\r\n\r\n this.rect.top = top\r\n this.rect.y = top\r\n this.rect.width = width\r\n this.rect.height = height\r\n this.rect.left = left\r\n this.rect.x = left\r\n this.rect.bottom = top + height\r\n this.rect.right = left + width\r\n }\r\n\r\n onWrapperResize = () => {\r\n let top, left\r\n\r\n if (this.options.ignoreSticky) removeParentSticky(this.element)\r\n if (this.options.ignoreTransform) {\r\n top = offsetTop(this.element)\r\n left = offsetLeft(this.element)\r\n } else {\r\n const rect = this.element.getBoundingClientRect()\r\n top = rect.top + scrollTop(this.element)\r\n left = rect.left + scrollLeft(this.element)\r\n }\r\n if (this.options.ignoreSticky) addParentSticky(this.element)\r\n\r\n this.setRect({ top, left })\r\n }\r\n\r\n onResize = ([entry]: ResizeObserverEntry[]) => {\r\n if (!entry?.borderBoxSize[0]) return\r\n const width = entry.borderBoxSize[0].inlineSize\r\n const height = entry.borderBoxSize[0].blockSize\r\n\r\n this.setRect({ width, height })\r\n }\r\n}\r\n","let index = 0\r\n\r\nexport type UID = number\r\n\r\nexport function uid(): UID {\r\n return index++\r\n}\r\n","import type Lenis from 'lenis'\r\nimport type { VirtualScrollData } from 'lenis'\r\nimport { debounce } from './debounce'\r\nimport type { SnapElementOptions } from './element'\r\nimport { SnapElement } from './element'\r\nimport type { SnapItem, SnapOptions } from './types'\r\nimport type { UID } from './uid'\r\nimport { uid } from './uid'\r\n\r\n// TODO:\r\n// - fix wheel scrolling after limits (see console scroll to)\r\n// - fix touch scroll, do not snap when not released\r\n// - arrow, spacebar\r\n\r\ntype RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>\r\n\r\n/**\r\n * Snap class to handle the snap functionality\r\n *\r\n * @example\r\n * const snap = new Snap(lenis, {\r\n * type: 'mandatory', // 'mandatory', 'proximity'\r\n * lerp: 0.1,\r\n * duration: 1,\r\n * easing: (t) => t,\r\n * onSnapStart: (snap) => {\r\n * console.log('onSnapStart', snap)\r\n * },\r\n * onSnapComplete: (snap) => {\r\n * console.log('onSnapComplete', snap)\r\n * },\r\n * })\r\n *\r\n * snap.add(500) // snap at 500px\r\n *\r\n * const removeSnap = snap.add(500)\r\n *\r\n * if (someCondition) {\r\n * removeSnap()\r\n * }\r\n */\r\nexport class Snap {\r\n options: RequiredPick<SnapOptions, 'type' | 'debounce'>\r\n elements = new Map<UID, SnapElement>()\r\n snaps = new Map<UID, SnapItem>()\r\n viewport: { width: number; height: number } = {\r\n width: window.innerWidth,\r\n height: window.innerHeight,\r\n }\r\n isStopped = false\r\n onSnapDebounced: (e: VirtualScrollData) => void\r\n currentSnapIndex?: number\r\n\r\n constructor(\r\n private lenis: Lenis,\r\n {\r\n type = 'proximity',\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold = '50%', // useless when type is \"mandatory\"\r\n debounce: debounceDelay = 500,\r\n onSnapStart,\r\n onSnapComplete,\r\n }: SnapOptions = {}\r\n ) {\r\n this.options = {\r\n type,\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold,\r\n debounce: debounceDelay,\r\n onSnapStart,\r\n onSnapComplete,\r\n }\r\n\r\n this.onWindowResize()\r\n window.addEventListener('resize', this.onWindowResize, false)\r\n\r\n this.onSnapDebounced = debounce(\r\n this.onSnap,\r\n this.options.type === 'lock' ? 0 : this.options.debounce\r\n )\r\n\r\n this.lenis.on('virtual-scroll', this.onSnapDebounced)\r\n }\r\n\r\n /**\r\n * Destroy the snap instance\r\n */\r\n destroy() {\r\n this.lenis.off('virtual-scroll', this.onSnapDebounced)\r\n window.removeEventListener('resize', this.onWindowResize, false)\r\n this.elements.forEach((element) => element.destroy())\r\n }\r\n\r\n /**\r\n * Start the snap after it has been stopped\r\n */\r\n start() {\r\n this.isStopped = false\r\n }\r\n\r\n /**\r\n * Stop the snap\r\n */\r\n stop() {\r\n this.isStopped = true\r\n }\r\n\r\n /**\r\n * Add a snap to the snap instance\r\n *\r\n * @param value The value to snap to\r\n * @param userData User data that will be forwarded through the snap event\r\n * @returns Unsubscribe function\r\n */\r\n add(value: number) {\r\n const id = uid()\r\n\r\n this.snaps.set(id, { value })\r\n\r\n return () => this.snaps.delete(id)\r\n }\r\n\r\n /**\r\n * Add an element to the snap instance\r\n *\r\n * @param element The element to add\r\n * @param options The options for the element\r\n * @returns Unsubscribe function\r\n */\r\n addElement(element: HTMLElement, options: SnapElementOptions = {}) {\r\n const id = uid()\r\n\r\n this.elements.set(id, new SnapElement(element, options))\r\n\r\n return () => this.elements.delete(id)\r\n }\r\n\r\n addElements(elements: HTMLElement[], options: SnapElementOptions = {}) {\r\n elements.forEach((element) => this.addElement(element, options))\r\n }\r\n\r\n private onWindowResize = () => {\r\n this.viewport.width = window.innerWidth\r\n this.viewport.height = window.innerHeight\r\n }\r\n\r\n private computeSnaps = () => {\r\n const { isHorizontal } = this.lenis\r\n\r\n let snaps = [...this.snaps.values()] as SnapItem[]\r\n\r\n this.elements.forEach(({ rect, align }) => {\r\n let value: number | undefined\r\n\r\n align.forEach((align) => {\r\n if (align === 'start') {\r\n value = rect.top\r\n } else if (align === 'center') {\r\n value = isHorizontal\r\n ? rect.left + rect.width / 2 - this.viewport.width / 2\r\n : rect.top + rect.height / 2 - this.viewport.height / 2\r\n } else if (align === 'end') {\r\n value = isHorizontal\r\n ? rect.left + rect.width - this.viewport.width\r\n : rect.top + rect.height - this.viewport.height\r\n }\r\n\r\n if (typeof value === 'number') {\r\n snaps.push({ value: Math.ceil(value) })\r\n }\r\n })\r\n })\r\n\r\n snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value))\r\n\r\n return snaps\r\n }\r\n\r\n previous() {\r\n this.goTo((this.currentSnapIndex ?? 0) - 1)\r\n }\r\n\r\n next() {\r\n this.goTo((this.currentSnapIndex ?? 0) + 1)\r\n }\r\n\r\n goTo(index: number) {\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n this.currentSnapIndex = Math.max(0, Math.min(index, snaps.length - 1))\r\n\r\n const currentSnap = snaps[this.currentSnapIndex]\r\n if (currentSnap === undefined) return\r\n\r\n this.lenis.scrollTo(currentSnap.value, {\r\n duration: this.options.duration,\r\n easing: this.options.easing,\r\n lerp: this.options.lerp,\r\n lock: this.options.type === 'lock',\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.({\r\n index: this.currentSnapIndex,\r\n ...currentSnap,\r\n })\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.({\r\n index: this.currentSnapIndex,\r\n ...currentSnap,\r\n })\r\n },\r\n })\r\n }\r\n\r\n // private onSlide = (e: VirtualScrollData) => {\r\n // if (this.isStopped) return\r\n\r\n // const { userData, isHorizontal } = this.lenis\r\n\r\n // if (userData?.initiator === 'snap') return\r\n\r\n // const delta = isHorizontal ? e.deltaX : e.deltaY\r\n\r\n // if (delta > 0) {\r\n // this.next()\r\n // } else if (delta < 0) {\r\n // this.previous()\r\n // }\r\n // }\r\n\r\n get distanceThreshold() {\r\n let distanceThreshold = Infinity\r\n if (this.options.type === 'mandatory') return Infinity\r\n\r\n const { isHorizontal } = this.lenis\r\n\r\n const axis = isHorizontal ? 'width' : 'height'\r\n\r\n if (\r\n typeof this.options.distanceThreshold === 'string' &&\r\n this.options.distanceThreshold.endsWith('%')\r\n ) {\r\n distanceThreshold =\r\n (Number(this.options.distanceThreshold.replace('%', '')) / 100) *\r\n this.viewport[axis]\r\n } else if (typeof this.options.distanceThreshold === 'number') {\r\n distanceThreshold = this.options.distanceThreshold\r\n } else {\r\n distanceThreshold = this.viewport[axis]\r\n }\r\n\r\n return distanceThreshold\r\n }\r\n\r\n private onSnap = (e: VirtualScrollData) => {\r\n if (this.isStopped) return\r\n\r\n if (\r\n this.options.type === 'lock' &&\r\n this.lenis.userData?.initiator === 'snap'\r\n )\r\n return\r\n\r\n let { scroll, isHorizontal } = this.lenis\r\n const delta = isHorizontal ? e.deltaX : e.deltaY\r\n scroll = Math.ceil(this.lenis.scroll)\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n let snapIndex\r\n\r\n if (this.options.type === 'lock') {\r\n if (delta > 0) {\r\n const currentSnapIndex = snaps.findIndex(({ value }) => value > scroll)\r\n snapIndex = currentSnapIndex\r\n } else if (delta < 0) {\r\n const currentSnapIndex = snaps.findLastIndex(\r\n ({ value }) => value < scroll\r\n )\r\n snapIndex = currentSnapIndex\r\n }\r\n } else {\r\n let prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll)\r\n // if (prevSnapIndex === -1) prevSnapIndex = 0\r\n const prevSnap = snaps[prevSnapIndex]!\r\n const distanceToPrevSnap = Math.abs(scroll - prevSnap.value)\r\n\r\n let nextSnapIndex = snaps.findIndex(({ value }) => value > scroll)\r\n // if (nextSnapIndex === -1) nextSnapIndex = snaps.length - 1\r\n const nextSnap = snaps[nextSnapIndex]!\r\n const distanceToNextSnap = Math.abs(scroll - nextSnap.value)\r\n snapIndex =\r\n distanceToPrevSnap < distanceToNextSnap ? prevSnapIndex : nextSnapIndex\r\n }\r\n\r\n if (snapIndex === undefined) return\r\n if (snapIndex === -1) return\r\n\r\n snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1))\r\n\r\n const snap = snaps[snapIndex]!\r\n\r\n const distance = Math.abs(scroll - snap.value)\r\n\r\n if (distance <= this.distanceThreshold) {\r\n this.goTo(snapIndex)\r\n }\r\n }\r\n\r\n resize() {\r\n this.elements.forEach((element) => element.onWrapperResize())\r\n }\r\n}\r\n","// This file serves as an entry point for the package\r\nimport { Snap } from './src/snap'\r\nglobalThis.Snap = Snap\r\n"],"mappings":"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","names":["align","index"]}
|
package/dist/lenis-snap.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(e){"sticky"===getComputedStyle(e).position&&(e.style.setProperty("position","static"),e.dataset.sticky="true"),e.offsetParent&&t(e.offsetParent)}function e
|
|
1
|
+
function e(e,t){let i;return function(...s){let n=this;clearTimeout(i),i=setTimeout((()=>{i=void 0,e.apply(n,s)}),t)}}function t(e){"sticky"===getComputedStyle(e).position&&(e.style.setProperty("position","static"),e.dataset.sticky="true"),e.offsetParent&&t(e.offsetParent)}function i(e){"true"===e?.dataset?.sticky&&(e.style.removeProperty("position"),delete e.dataset.sticky),e.offsetParent&&i(e.offsetParent)}function s(e,t=0){const i=t+e.offsetTop;return e.offsetParent?s(e.offsetParent,i):i}function n(e,t=0){const i=t+e.offsetLeft;return e.offsetParent?n(e.offsetParent,i):i}function o(e,t=0){const i=t+e.scrollTop;return e.offsetParent?o(e.offsetParent,i):i+window.scrollY}function r(e,t=0){const i=t+e.scrollLeft;return e.offsetParent?r(e.offsetParent,i):i+window.scrollX}var h=class{element;options;align;rect={};wrapperResizeObserver;resizeObserver;debouncedWrapperResize;constructor(t,{align:i=["start"],ignoreSticky:s=!0,ignoreTransform:n=!1}={}){this.element=t,this.options={align:i,ignoreSticky:s,ignoreTransform:n},this.align=[i].flat(),this.debouncedWrapperResize=e(this.onWrapperResize,500),this.wrapperResizeObserver=new ResizeObserver(this.debouncedWrapperResize),this.wrapperResizeObserver.observe(document.body),this.onWrapperResize(),this.resizeObserver=new ResizeObserver(this.onResize),this.resizeObserver.observe(this.element),this.setRect({width:this.element.offsetWidth,height:this.element.offsetHeight})}destroy(){this.wrapperResizeObserver.disconnect(),this.resizeObserver.disconnect()}setRect({top:e,left:t,width:i,height:s,element:n}={}){e=e??this.rect.top,t=t??this.rect.left,i=i??this.rect.width,s=s??this.rect.height,n=n??this.rect.element,e===this.rect.top&&t===this.rect.left&&i===this.rect.width&&s===this.rect.height&&n===this.rect.element||(this.rect.top=e,this.rect.y=e,this.rect.width=i,this.rect.height=s,this.rect.left=t,this.rect.x=t,this.rect.bottom=e+s,this.rect.right=t+i)}onWrapperResize=()=>{let e,h;if(this.options.ignoreSticky&&t(this.element),this.options.ignoreTransform)e=s(this.element),h=n(this.element);else{const t=this.element.getBoundingClientRect();e=t.top+o(this.element),h=t.left+r(this.element)}this.options.ignoreSticky&&i(this.element),this.setRect({top:e,left:h})};onResize=([e])=>{if(!e?.borderBoxSize[0])return;const t=e.borderBoxSize[0].inlineSize,i=e.borderBoxSize[0].blockSize;this.setRect({width:t,height:i})}},a=0;function l(){return a++}globalThis.Snap=class{constructor(t,{type:i="proximity",lerp:s,easing:n,duration:o,distanceThreshold:r="50%",debounce:h=500,onSnapStart:a,onSnapComplete:l}={}){this.lenis=t,this.options={type:i,lerp:s,easing:n,duration:o,distanceThreshold:r,debounce:h,onSnapStart:a,onSnapComplete:l},this.onWindowResize(),window.addEventListener("resize",this.onWindowResize,!1),this.onSnapDebounced=e(this.onSnap,"lock"===this.options.type?0:this.options.debounce),this.lenis.on("virtual-scroll",this.onSnapDebounced)}options;elements=new Map;snaps=new Map;viewport={width:window.innerWidth,height:window.innerHeight};isStopped=!1;onSnapDebounced;currentSnapIndex;destroy(){this.lenis.off("virtual-scroll",this.onSnapDebounced),window.removeEventListener("resize",this.onWindowResize,!1),this.elements.forEach((e=>e.destroy()))}start(){this.isStopped=!1}stop(){this.isStopped=!0}add(e){const t=l();return this.snaps.set(t,{value:e}),()=>this.snaps.delete(t)}addElement(e,t={}){const i=l();return this.elements.set(i,new h(e,t)),()=>this.elements.delete(i)}addElements(e,t={}){e.forEach((e=>this.addElement(e,t)))}onWindowResize=()=>{this.viewport.width=window.innerWidth,this.viewport.height=window.innerHeight};computeSnaps=()=>{const{isHorizontal:e}=this.lenis;let t=[...this.snaps.values()];return this.elements.forEach((({rect:i,align:s})=>{let n;s.forEach((s=>{"start"===s?n=i.top:"center"===s?n=e?i.left+i.width/2-this.viewport.width/2:i.top+i.height/2-this.viewport.height/2:"end"===s&&(n=e?i.left+i.width-this.viewport.width:i.top+i.height-this.viewport.height),"number"==typeof n&&t.push({value:Math.ceil(n)})}))})),t=t.sort(((e,t)=>Math.abs(e.value)-Math.abs(t.value))),t};previous(){this.goTo((this.currentSnapIndex??0)-1)}next(){this.goTo((this.currentSnapIndex??0)+1)}goTo(e){const t=this.computeSnaps();if(0===t.length)return;this.currentSnapIndex=Math.max(0,Math.min(e,t.length-1));const i=t[this.currentSnapIndex];void 0!==i&&this.lenis.scrollTo(i.value,{duration:this.options.duration,easing:this.options.easing,lerp:this.options.lerp,lock:"lock"===this.options.type,userData:{initiator:"snap"},onStart:()=>{this.options.onSnapStart?.({index:this.currentSnapIndex,...i})},onComplete:()=>{this.options.onSnapComplete?.({index:this.currentSnapIndex,...i})}})}get distanceThreshold(){let e=1/0;if("mandatory"===this.options.type)return 1/0;const{isHorizontal:t}=this.lenis,i=t?"width":"height";return e="string"==typeof this.options.distanceThreshold&&this.options.distanceThreshold.endsWith("%")?Number(this.options.distanceThreshold.replace("%",""))/100*this.viewport[i]:"number"==typeof this.options.distanceThreshold?this.options.distanceThreshold:this.viewport[i],e}onSnap=e=>{if(this.isStopped)return;if("lock"===this.options.type&&"snap"===this.lenis.userData?.initiator)return;let{scroll:t,isHorizontal:i}=this.lenis;const s=i?e.deltaX:e.deltaY;t=Math.ceil(this.lenis.scroll);const n=this.computeSnaps();if(0===n.length)return;let o;if("lock"===this.options.type){if(s>0){o=n.findIndex((({value:e})=>e>t))}else if(s<0){o=n.findLastIndex((({value:e})=>e<t))}}else{let e=n.findLastIndex((({value:e})=>e<t));const i=n[e],s=Math.abs(t-i.value);let r=n.findIndex((({value:e})=>e>t));const h=n[r];o=s<Math.abs(t-h.value)?e:r}if(void 0===o)return;if(-1===o)return;o=Math.max(0,Math.min(o,n.length-1));const r=n[o];Math.abs(t-r.value)<=this.distanceThreshold&&this.goTo(o)};resize(){this.elements.forEach((e=>e.onWrapperResize()))}};//# sourceMappingURL=lenis-snap.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../packages/snap/src/debounce.ts","../packages/snap/src/element.ts","../packages/snap/src/uid.ts","../packages/snap/src/snap.ts","../packages/snap/browser.ts"],"sourcesContent":["export function debounce<CB extends (...args: any[]) => void>(\r\n callback: CB,\r\n delay: number\r\n) {\r\n let timer: number | undefined\r\n return function <T>(this: T, ...args: Parameters<typeof callback>) {\r\n let context = this\r\n clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n timer = undefined\r\n callback.apply(context, args)\r\n }, delay)\r\n }\r\n}\r\n","function removeParentSticky(element: HTMLElement) {\r\n const position = getComputedStyle(element).position\r\n\r\n const isSticky = position === 'sticky'\r\n\r\n if (isSticky) {\r\n element.style.setProperty('position', 'static')\r\n element.dataset.sticky = 'true'\r\n }\r\n\r\n if (element.offsetParent) {\r\n removeParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction addParentSticky(element: HTMLElement) {\r\n if (element?.dataset?.sticky === 'true') {\r\n element.style.removeProperty('position')\r\n delete element.dataset.sticky\r\n }\r\n\r\n if (element.offsetParent) {\r\n addParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction offsetTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.offsetTop\r\n if (element.offsetParent) {\r\n return offsetTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top\r\n}\r\n\r\nfunction offsetLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.offsetLeft\r\n if (element.offsetParent) {\r\n return offsetLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left\r\n}\r\n\r\nfunction scrollTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.scrollTop\r\n if (element.offsetParent) {\r\n return scrollTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top + window.scrollY\r\n}\r\n\r\nfunction scrollLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.scrollLeft\r\n if (element.offsetParent) {\r\n return scrollLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left + window.scrollX\r\n}\r\n\r\nexport type SnapElementOptions = {\r\n align?: string | string[]\r\n ignoreSticky?: boolean\r\n ignoreTransform?: boolean\r\n}\r\n\r\ntype Rect = {\r\n top: number\r\n left: number\r\n width: number\r\n height: number\r\n x: number\r\n y: number\r\n bottom: number\r\n right: number\r\n element: HTMLElement\r\n}\r\n\r\nexport class SnapElement {\r\n element: HTMLElement\r\n options: SnapElementOptions\r\n align: string[]\r\n // @ts-ignore\r\n rect: Rect = {}\r\n wrapperResizeObserver: ResizeObserver\r\n resizeObserver: ResizeObserver\r\n\r\n constructor(\r\n element: HTMLElement,\r\n {\r\n align = ['start'],\r\n ignoreSticky = true,\r\n ignoreTransform = false,\r\n }: SnapElementOptions = {}\r\n ) {\r\n this.element = element\r\n\r\n this.options = { align, ignoreSticky, ignoreTransform }\r\n\r\n // this.ignoreSticky = ignoreSticky\r\n // this.ignoreTransform = ignoreTransform\r\n\r\n this.align = [align].flat()\r\n\r\n // TODO: assing rect immediately\r\n\r\n this.wrapperResizeObserver = new ResizeObserver(this.onWrapperResize)\r\n this.wrapperResizeObserver.observe(document.body)\r\n this.onWrapperResize()\r\n\r\n this.resizeObserver = new ResizeObserver(this.onResize)\r\n this.resizeObserver.observe(this.element)\r\n this.setRect({\r\n width: this.element.offsetWidth,\r\n height: this.element.offsetHeight,\r\n })\r\n }\r\n\r\n destroy() {\r\n this.wrapperResizeObserver.disconnect()\r\n this.resizeObserver.disconnect()\r\n }\r\n\r\n setRect({\r\n top,\r\n left,\r\n width,\r\n height,\r\n element,\r\n }: {\r\n top?: number\r\n left?: number\r\n width?: number\r\n height?: number\r\n element?: HTMLElement\r\n } = {}) {\r\n top = top ?? this.rect.top\r\n left = left ?? this.rect.left\r\n width = width ?? this.rect.width\r\n height = height ?? this.rect.height\r\n element = element ?? this.rect.element\r\n\r\n if (\r\n top === this.rect.top &&\r\n left === this.rect.left &&\r\n width === this.rect.width &&\r\n height === this.rect.height &&\r\n element === this.rect.element\r\n )\r\n return\r\n\r\n this.rect.top = top\r\n this.rect.y = top\r\n this.rect.width = width\r\n this.rect.height = height\r\n this.rect.left = left\r\n this.rect.x = left\r\n this.rect.bottom = top + height\r\n this.rect.right = left + width\r\n }\r\n\r\n onWrapperResize = () => {\r\n let top, left\r\n\r\n if (this.options.ignoreSticky) removeParentSticky(this.element)\r\n if (this.options.ignoreTransform) {\r\n top = offsetTop(this.element)\r\n left = offsetLeft(this.element)\r\n } else {\r\n const rect = this.element.getBoundingClientRect()\r\n top = rect.top + scrollTop(this.element)\r\n left = rect.left + scrollLeft(this.element)\r\n }\r\n if (this.options.ignoreSticky) addParentSticky(this.element)\r\n\r\n this.setRect({ top, left })\r\n }\r\n\r\n onResize = ([entry]: ResizeObserverEntry[]) => {\r\n if (!entry?.borderBoxSize[0]) return\r\n const width = entry.borderBoxSize[0].inlineSize\r\n const height = entry.borderBoxSize[0].blockSize\r\n\r\n this.setRect({ width, height })\r\n }\r\n}\r\n","let index = 0\r\n\r\nexport type UID = number\r\n\r\nexport function uid(): UID {\r\n return index++\r\n}\r\n","import type Lenis from 'lenis'\r\nimport { debounce } from './debounce'\r\nimport type { SnapElementOptions } from './element'\r\nimport { SnapElement } from './element'\r\nimport type { SnapItem, SnapOptions } from './types'\r\nimport type { UID } from './uid'\r\nimport { uid } from './uid'\r\n\r\n// TODO:\r\n// - horizontal\r\n// - fix trackpad snapping too soon due to velocity (fuck Apple)\r\n// - fix wheel scrolling after limits (see console scroll to)\r\n// - fix touch scroll, do not snap when not released\r\n// - arrow, spacebar\r\n\r\ntype RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>\r\n\r\n/**\r\n * Snap class to handle the snap functionality\r\n *\r\n * @example\r\n * const snap = new Snap(lenis, {\r\n * type: 'mandatory', // 'mandatory', 'proximity'\r\n * lerp: 0.1,\r\n * duration: 1,\r\n * easing: (t) => t,\r\n * onSnapStart: (snap) => {\r\n * console.log('onSnapStart', snap)\r\n * },\r\n * onSnapComplete: (snap) => {\r\n * console.log('onSnapComplete', snap)\r\n * },\r\n * })\r\n *\r\n * snap.add(500) // snap at 500px\r\n *\r\n * const removeSnap = snap.add(500)\r\n *\r\n * if (someCondition) {\r\n * removeSnap()\r\n * }\r\n */\r\nexport class Snap {\r\n options: RequiredPick<SnapOptions, 'type' | 'debounce'>\r\n elements = new Map<UID, SnapElement>()\r\n snaps = new Map<UID, SnapItem>()\r\n viewport: { width: number; height: number } = {\r\n width: window.innerWidth,\r\n height: window.innerHeight,\r\n }\r\n isStopped = false\r\n onSnapDebounced?: () => void\r\n currentSnapIndex = 0 // used for slide type\r\n\r\n constructor(\r\n private lenis: Lenis,\r\n {\r\n type = 'proximity',\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold = '50%',\r\n debounce: debounceDelay = 500,\r\n onSnapStart,\r\n onSnapComplete,\r\n }: SnapOptions = {}\r\n ) {\r\n this.options = {\r\n type,\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold,\r\n debounce: debounceDelay,\r\n onSnapStart,\r\n onSnapComplete,\r\n }\r\n\r\n this.onWindowResize()\r\n window.addEventListener('resize', this.onWindowResize, false)\r\n\r\n if (this.options.type === 'slide') {\r\n this.lenis.on('scroll', this.onSlide)\r\n } else {\r\n this.onSnapDebounced = debounce(this.onSnap, this.options.debounce)\r\n\r\n // this.lenis.on('scroll', this.onScroll)\r\n this.lenis.on('virtual-scroll', this.onSnapDebounced)\r\n }\r\n }\r\n\r\n /**\r\n * Destroy the snap instance\r\n */\r\n destroy() {\r\n // this.lenis.off('scroll', this.onScroll)\r\n this.lenis.off('virtual-scroll', this.onSnapDebounced!)\r\n window.removeEventListener('resize', this.onWindowResize, false)\r\n this.elements.forEach((element) => element.destroy())\r\n }\r\n\r\n /**\r\n * Start the snap after it has been stopped\r\n */\r\n start() {\r\n this.isStopped = false\r\n }\r\n\r\n /**\r\n * Stop the snap\r\n */\r\n stop() {\r\n this.isStopped = true\r\n }\r\n\r\n /**\r\n * Add a snap to the snap instance\r\n *\r\n * @param value The value to snap to\r\n * @param userData User data that will be forwarded through the snap event\r\n * @returns Unsubscribe function\r\n */\r\n add(value: number) {\r\n const id = uid()\r\n\r\n this.snaps.set(id, { value })\r\n\r\n return () => this.snaps.delete(id)\r\n }\r\n\r\n /**\r\n * Add an element to the snap instance\r\n *\r\n * @param element The element to add\r\n * @param options The options for the element\r\n * @returns Unsubscribe function\r\n */\r\n addElement(element: HTMLElement, options: SnapElementOptions = {}) {\r\n const id = uid()\r\n\r\n this.elements.set(id, new SnapElement(element, options))\r\n\r\n return () => this.elements.delete(id)\r\n }\r\n\r\n private onWindowResize = () => {\r\n this.viewport.width = window.innerWidth\r\n this.viewport.height = window.innerHeight\r\n }\r\n\r\n private computeSnaps = () => {\r\n const { isHorizontal } = this.lenis\r\n\r\n let snaps = [...this.snaps.values()] as SnapItem[]\r\n\r\n this.elements.forEach(({ rect, align }) => {\r\n let value: number | undefined\r\n\r\n align.forEach((align) => {\r\n if (align === 'start') {\r\n value = rect.top\r\n } else if (align === 'center') {\r\n value = isHorizontal\r\n ? rect.left + rect.width / 2 - this.viewport.width / 2\r\n : rect.top + rect.height / 2 - this.viewport.height / 2\r\n } else if (align === 'end') {\r\n value = isHorizontal\r\n ? rect.left + rect.width - this.viewport.width\r\n : rect.top + rect.height - this.viewport.height\r\n }\r\n\r\n if (typeof value === 'number') {\r\n snaps.push({ value: Math.ceil(value) })\r\n }\r\n })\r\n })\r\n\r\n snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value))\r\n\r\n return snaps\r\n }\r\n\r\n private onSlide = () => {\r\n const { direction, userData } = this.lenis\r\n\r\n if (userData?.initiator === 'snap') return\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n if (direction === 1) {\r\n this.currentSnapIndex += 1\r\n } else if (direction === -1) {\r\n this.currentSnapIndex -= 1\r\n }\r\n\r\n this.currentSnapIndex = Math.max(\r\n 0,\r\n Math.min(this.currentSnapIndex, snaps.length - 1)\r\n )\r\n\r\n const currentSnap = snaps[this.currentSnapIndex]\r\n\r\n if (currentSnap === undefined) return\r\n\r\n this.lenis.scrollTo(currentSnap.value, {\r\n duration: this.options.duration,\r\n easing: this.options.easing,\r\n lerp: this.options.lerp,\r\n lock: true,\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.(currentSnap)\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.(currentSnap)\r\n },\r\n })\r\n }\r\n\r\n private onSnap = () => {\r\n let { scroll, isHorizontal } = this.lenis\r\n scroll = Math.ceil(this.lenis.scroll)\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n let prevSnap = snaps.findLast(({ value }) => value <= scroll)\r\n if (prevSnap === undefined) prevSnap = snaps[0]!\r\n const distanceToPrevSnap = Math.abs(scroll - prevSnap.value)\r\n\r\n let nextSnap = snaps.find(({ value }) => value >= scroll)\r\n if (nextSnap === undefined) nextSnap = snaps[snaps.length - 1]!\r\n const distanceToNextSnap = Math.abs(scroll - nextSnap.value)\r\n\r\n const snap = distanceToPrevSnap < distanceToNextSnap ? prevSnap : nextSnap\r\n\r\n const distance = Math.abs(scroll - snap.value)\r\n\r\n let distanceThreshold\r\n\r\n const axis = isHorizontal ? 'width' : 'height'\r\n\r\n if (\r\n typeof this.options.distanceThreshold === 'string' &&\r\n this.options.distanceThreshold.endsWith('%')\r\n ) {\r\n distanceThreshold =\r\n (Number(this.options.distanceThreshold.replace('%', '')) / 100) *\r\n this.viewport[axis]\r\n } else if (typeof this.options.distanceThreshold === 'number') {\r\n distanceThreshold = this.options.distanceThreshold\r\n } else {\r\n distanceThreshold = this.viewport[axis]\r\n }\r\n\r\n if (\r\n this.options.type === 'mandatory' ||\r\n (this.options.type === 'proximity' && distance <= distanceThreshold)\r\n ) {\r\n // this.__isScrolling = true\r\n // this.onSnapStart?.(snap)\r\n\r\n // console.log('scroll to')\r\n\r\n this.lenis.scrollTo(snap.value, {\r\n lerp: this.options.lerp,\r\n easing: this.options.easing,\r\n duration: this.options.duration,\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.(snap)\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.(snap)\r\n },\r\n })\r\n }\r\n\r\n // console.timeEnd('scroll')\r\n }\r\n}\r\n","// This file serves as an entry point for the package\r\nimport { Snap } from './src/snap'\r\nglobalThis.Snap = Snap\r\n"],"mappings":"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","names":["align"]}
|
|
1
|
+
{"version":3,"sources":["../packages/snap/src/debounce.ts","../packages/snap/src/element.ts","../packages/snap/src/uid.ts","../packages/snap/src/snap.ts","../packages/snap/browser.ts"],"sourcesContent":["export function debounce<CB extends (...args: any[]) => void>(\r\n callback: CB,\r\n delay: number\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | undefined\r\n return function <T>(this: T, ...args: Parameters<typeof callback>): void {\r\n let context = this\r\n clearTimeout(timer)\r\n timer = setTimeout(() => {\r\n timer = undefined\r\n callback.apply(context, args)\r\n }, delay)\r\n }\r\n}\r\n","import { debounce } from './debounce'\r\n\r\nfunction removeParentSticky(element: HTMLElement) {\r\n const position = getComputedStyle(element).position\r\n\r\n const isSticky = position === 'sticky'\r\n\r\n if (isSticky) {\r\n element.style.setProperty('position', 'static')\r\n element.dataset.sticky = 'true'\r\n }\r\n\r\n if (element.offsetParent) {\r\n removeParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction addParentSticky(element: HTMLElement) {\r\n if (element?.dataset?.sticky === 'true') {\r\n element.style.removeProperty('position')\r\n delete element.dataset.sticky\r\n }\r\n\r\n if (element.offsetParent) {\r\n addParentSticky(element.offsetParent as HTMLElement)\r\n }\r\n}\r\n\r\nfunction offsetTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.offsetTop\r\n if (element.offsetParent) {\r\n return offsetTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top\r\n}\r\n\r\nfunction offsetLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.offsetLeft\r\n if (element.offsetParent) {\r\n return offsetLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left\r\n}\r\n\r\nfunction scrollTop(element: HTMLElement, accumulator = 0) {\r\n const top = accumulator + element.scrollTop\r\n if (element.offsetParent) {\r\n return scrollTop(element.offsetParent as HTMLElement, top)\r\n }\r\n return top + window.scrollY\r\n}\r\n\r\nfunction scrollLeft(element: HTMLElement, accumulator = 0) {\r\n const left = accumulator + element.scrollLeft\r\n if (element.offsetParent) {\r\n return scrollLeft(element.offsetParent as HTMLElement, left)\r\n }\r\n return left + window.scrollX\r\n}\r\n\r\nexport type SnapElementOptions = {\r\n align?: string | string[]\r\n ignoreSticky?: boolean\r\n ignoreTransform?: boolean\r\n}\r\n\r\ntype Rect = {\r\n top: number\r\n left: number\r\n width: number\r\n height: number\r\n x: number\r\n y: number\r\n bottom: number\r\n right: number\r\n element: HTMLElement\r\n}\r\n\r\nexport class SnapElement {\r\n element: HTMLElement\r\n options: SnapElementOptions\r\n align: string[]\r\n // @ts-ignore\r\n rect: Rect = {}\r\n wrapperResizeObserver: ResizeObserver\r\n resizeObserver: ResizeObserver\r\n debouncedWrapperResize: () => void\r\n\r\n constructor(\r\n element: HTMLElement,\r\n {\r\n align = ['start'],\r\n ignoreSticky = true,\r\n ignoreTransform = false,\r\n }: SnapElementOptions = {}\r\n ) {\r\n this.element = element\r\n\r\n this.options = { align, ignoreSticky, ignoreTransform }\r\n\r\n this.align = [align].flat()\r\n\r\n this.debouncedWrapperResize = debounce(this.onWrapperResize, 500)\r\n\r\n this.wrapperResizeObserver = new ResizeObserver(this.debouncedWrapperResize)\r\n this.wrapperResizeObserver.observe(document.body)\r\n this.onWrapperResize()\r\n\r\n this.resizeObserver = new ResizeObserver(this.onResize)\r\n this.resizeObserver.observe(this.element)\r\n this.setRect({\r\n width: this.element.offsetWidth,\r\n height: this.element.offsetHeight,\r\n })\r\n }\r\n\r\n destroy() {\r\n this.wrapperResizeObserver.disconnect()\r\n this.resizeObserver.disconnect()\r\n }\r\n\r\n setRect({\r\n top,\r\n left,\r\n width,\r\n height,\r\n element,\r\n }: {\r\n top?: number\r\n left?: number\r\n width?: number\r\n height?: number\r\n element?: HTMLElement\r\n } = {}) {\r\n top = top ?? this.rect.top\r\n left = left ?? this.rect.left\r\n width = width ?? this.rect.width\r\n height = height ?? this.rect.height\r\n element = element ?? this.rect.element\r\n\r\n if (\r\n top === this.rect.top &&\r\n left === this.rect.left &&\r\n width === this.rect.width &&\r\n height === this.rect.height &&\r\n element === this.rect.element\r\n )\r\n return\r\n\r\n this.rect.top = top\r\n this.rect.y = top\r\n this.rect.width = width\r\n this.rect.height = height\r\n this.rect.left = left\r\n this.rect.x = left\r\n this.rect.bottom = top + height\r\n this.rect.right = left + width\r\n }\r\n\r\n onWrapperResize = () => {\r\n let top, left\r\n\r\n if (this.options.ignoreSticky) removeParentSticky(this.element)\r\n if (this.options.ignoreTransform) {\r\n top = offsetTop(this.element)\r\n left = offsetLeft(this.element)\r\n } else {\r\n const rect = this.element.getBoundingClientRect()\r\n top = rect.top + scrollTop(this.element)\r\n left = rect.left + scrollLeft(this.element)\r\n }\r\n if (this.options.ignoreSticky) addParentSticky(this.element)\r\n\r\n this.setRect({ top, left })\r\n }\r\n\r\n onResize = ([entry]: ResizeObserverEntry[]) => {\r\n if (!entry?.borderBoxSize[0]) return\r\n const width = entry.borderBoxSize[0].inlineSize\r\n const height = entry.borderBoxSize[0].blockSize\r\n\r\n this.setRect({ width, height })\r\n }\r\n}\r\n","let index = 0\r\n\r\nexport type UID = number\r\n\r\nexport function uid(): UID {\r\n return index++\r\n}\r\n","import type Lenis from 'lenis'\r\nimport type { VirtualScrollData } from 'lenis'\r\nimport { debounce } from './debounce'\r\nimport type { SnapElementOptions } from './element'\r\nimport { SnapElement } from './element'\r\nimport type { SnapItem, SnapOptions } from './types'\r\nimport type { UID } from './uid'\r\nimport { uid } from './uid'\r\n\r\n// TODO:\r\n// - fix wheel scrolling after limits (see console scroll to)\r\n// - fix touch scroll, do not snap when not released\r\n// - arrow, spacebar\r\n\r\ntype RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>\r\n\r\n/**\r\n * Snap class to handle the snap functionality\r\n *\r\n * @example\r\n * const snap = new Snap(lenis, {\r\n * type: 'mandatory', // 'mandatory', 'proximity'\r\n * lerp: 0.1,\r\n * duration: 1,\r\n * easing: (t) => t,\r\n * onSnapStart: (snap) => {\r\n * console.log('onSnapStart', snap)\r\n * },\r\n * onSnapComplete: (snap) => {\r\n * console.log('onSnapComplete', snap)\r\n * },\r\n * })\r\n *\r\n * snap.add(500) // snap at 500px\r\n *\r\n * const removeSnap = snap.add(500)\r\n *\r\n * if (someCondition) {\r\n * removeSnap()\r\n * }\r\n */\r\nexport class Snap {\r\n options: RequiredPick<SnapOptions, 'type' | 'debounce'>\r\n elements = new Map<UID, SnapElement>()\r\n snaps = new Map<UID, SnapItem>()\r\n viewport: { width: number; height: number } = {\r\n width: window.innerWidth,\r\n height: window.innerHeight,\r\n }\r\n isStopped = false\r\n onSnapDebounced: (e: VirtualScrollData) => void\r\n currentSnapIndex?: number\r\n\r\n constructor(\r\n private lenis: Lenis,\r\n {\r\n type = 'proximity',\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold = '50%', // useless when type is \"mandatory\"\r\n debounce: debounceDelay = 500,\r\n onSnapStart,\r\n onSnapComplete,\r\n }: SnapOptions = {}\r\n ) {\r\n this.options = {\r\n type,\r\n lerp,\r\n easing,\r\n duration,\r\n distanceThreshold,\r\n debounce: debounceDelay,\r\n onSnapStart,\r\n onSnapComplete,\r\n }\r\n\r\n this.onWindowResize()\r\n window.addEventListener('resize', this.onWindowResize, false)\r\n\r\n this.onSnapDebounced = debounce(\r\n this.onSnap,\r\n this.options.type === 'lock' ? 0 : this.options.debounce\r\n )\r\n\r\n this.lenis.on('virtual-scroll', this.onSnapDebounced)\r\n }\r\n\r\n /**\r\n * Destroy the snap instance\r\n */\r\n destroy() {\r\n this.lenis.off('virtual-scroll', this.onSnapDebounced)\r\n window.removeEventListener('resize', this.onWindowResize, false)\r\n this.elements.forEach((element) => element.destroy())\r\n }\r\n\r\n /**\r\n * Start the snap after it has been stopped\r\n */\r\n start() {\r\n this.isStopped = false\r\n }\r\n\r\n /**\r\n * Stop the snap\r\n */\r\n stop() {\r\n this.isStopped = true\r\n }\r\n\r\n /**\r\n * Add a snap to the snap instance\r\n *\r\n * @param value The value to snap to\r\n * @param userData User data that will be forwarded through the snap event\r\n * @returns Unsubscribe function\r\n */\r\n add(value: number) {\r\n const id = uid()\r\n\r\n this.snaps.set(id, { value })\r\n\r\n return () => this.snaps.delete(id)\r\n }\r\n\r\n /**\r\n * Add an element to the snap instance\r\n *\r\n * @param element The element to add\r\n * @param options The options for the element\r\n * @returns Unsubscribe function\r\n */\r\n addElement(element: HTMLElement, options: SnapElementOptions = {}) {\r\n const id = uid()\r\n\r\n this.elements.set(id, new SnapElement(element, options))\r\n\r\n return () => this.elements.delete(id)\r\n }\r\n\r\n addElements(elements: HTMLElement[], options: SnapElementOptions = {}) {\r\n elements.forEach((element) => this.addElement(element, options))\r\n }\r\n\r\n private onWindowResize = () => {\r\n this.viewport.width = window.innerWidth\r\n this.viewport.height = window.innerHeight\r\n }\r\n\r\n private computeSnaps = () => {\r\n const { isHorizontal } = this.lenis\r\n\r\n let snaps = [...this.snaps.values()] as SnapItem[]\r\n\r\n this.elements.forEach(({ rect, align }) => {\r\n let value: number | undefined\r\n\r\n align.forEach((align) => {\r\n if (align === 'start') {\r\n value = rect.top\r\n } else if (align === 'center') {\r\n value = isHorizontal\r\n ? rect.left + rect.width / 2 - this.viewport.width / 2\r\n : rect.top + rect.height / 2 - this.viewport.height / 2\r\n } else if (align === 'end') {\r\n value = isHorizontal\r\n ? rect.left + rect.width - this.viewport.width\r\n : rect.top + rect.height - this.viewport.height\r\n }\r\n\r\n if (typeof value === 'number') {\r\n snaps.push({ value: Math.ceil(value) })\r\n }\r\n })\r\n })\r\n\r\n snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value))\r\n\r\n return snaps\r\n }\r\n\r\n previous() {\r\n this.goTo((this.currentSnapIndex ?? 0) - 1)\r\n }\r\n\r\n next() {\r\n this.goTo((this.currentSnapIndex ?? 0) + 1)\r\n }\r\n\r\n goTo(index: number) {\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n this.currentSnapIndex = Math.max(0, Math.min(index, snaps.length - 1))\r\n\r\n const currentSnap = snaps[this.currentSnapIndex]\r\n if (currentSnap === undefined) return\r\n\r\n this.lenis.scrollTo(currentSnap.value, {\r\n duration: this.options.duration,\r\n easing: this.options.easing,\r\n lerp: this.options.lerp,\r\n lock: this.options.type === 'lock',\r\n userData: { initiator: 'snap' },\r\n onStart: () => {\r\n this.options.onSnapStart?.({\r\n index: this.currentSnapIndex,\r\n ...currentSnap,\r\n })\r\n },\r\n onComplete: () => {\r\n this.options.onSnapComplete?.({\r\n index: this.currentSnapIndex,\r\n ...currentSnap,\r\n })\r\n },\r\n })\r\n }\r\n\r\n // private onSlide = (e: VirtualScrollData) => {\r\n // if (this.isStopped) return\r\n\r\n // const { userData, isHorizontal } = this.lenis\r\n\r\n // if (userData?.initiator === 'snap') return\r\n\r\n // const delta = isHorizontal ? e.deltaX : e.deltaY\r\n\r\n // if (delta > 0) {\r\n // this.next()\r\n // } else if (delta < 0) {\r\n // this.previous()\r\n // }\r\n // }\r\n\r\n get distanceThreshold() {\r\n let distanceThreshold = Infinity\r\n if (this.options.type === 'mandatory') return Infinity\r\n\r\n const { isHorizontal } = this.lenis\r\n\r\n const axis = isHorizontal ? 'width' : 'height'\r\n\r\n if (\r\n typeof this.options.distanceThreshold === 'string' &&\r\n this.options.distanceThreshold.endsWith('%')\r\n ) {\r\n distanceThreshold =\r\n (Number(this.options.distanceThreshold.replace('%', '')) / 100) *\r\n this.viewport[axis]\r\n } else if (typeof this.options.distanceThreshold === 'number') {\r\n distanceThreshold = this.options.distanceThreshold\r\n } else {\r\n distanceThreshold = this.viewport[axis]\r\n }\r\n\r\n return distanceThreshold\r\n }\r\n\r\n private onSnap = (e: VirtualScrollData) => {\r\n if (this.isStopped) return\r\n\r\n if (\r\n this.options.type === 'lock' &&\r\n this.lenis.userData?.initiator === 'snap'\r\n )\r\n return\r\n\r\n let { scroll, isHorizontal } = this.lenis\r\n const delta = isHorizontal ? e.deltaX : e.deltaY\r\n scroll = Math.ceil(this.lenis.scroll)\r\n\r\n const snaps = this.computeSnaps()\r\n\r\n if (snaps.length === 0) return\r\n\r\n let snapIndex\r\n\r\n if (this.options.type === 'lock') {\r\n if (delta > 0) {\r\n const currentSnapIndex = snaps.findIndex(({ value }) => value > scroll)\r\n snapIndex = currentSnapIndex\r\n } else if (delta < 0) {\r\n const currentSnapIndex = snaps.findLastIndex(\r\n ({ value }) => value < scroll\r\n )\r\n snapIndex = currentSnapIndex\r\n }\r\n } else {\r\n let prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll)\r\n // if (prevSnapIndex === -1) prevSnapIndex = 0\r\n const prevSnap = snaps[prevSnapIndex]!\r\n const distanceToPrevSnap = Math.abs(scroll - prevSnap.value)\r\n\r\n let nextSnapIndex = snaps.findIndex(({ value }) => value > scroll)\r\n // if (nextSnapIndex === -1) nextSnapIndex = snaps.length - 1\r\n const nextSnap = snaps[nextSnapIndex]!\r\n const distanceToNextSnap = Math.abs(scroll - nextSnap.value)\r\n snapIndex =\r\n distanceToPrevSnap < distanceToNextSnap ? prevSnapIndex : nextSnapIndex\r\n }\r\n\r\n if (snapIndex === undefined) return\r\n if (snapIndex === -1) return\r\n\r\n snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1))\r\n\r\n const snap = snaps[snapIndex]!\r\n\r\n const distance = Math.abs(scroll - snap.value)\r\n\r\n if (distance <= this.distanceThreshold) {\r\n this.goTo(snapIndex)\r\n }\r\n }\r\n\r\n resize() {\r\n this.elements.forEach((element) => element.onWrapperResize())\r\n }\r\n}\r\n","// This file serves as an entry point for the package\r\nimport { Snap } from './src/snap'\r\nglobalThis.Snap = Snap\r\n"],"mappings":"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","names":["align","index"]}
|