UNPKG

lenis

Version:
1 lines 20 kB
{"version":3,"file":"lenis-snap.mjs","names":[],"sources":["../packages/snap/src/debounce.ts","../packages/snap/src/element.ts","../packages/snap/src/uid.ts","../packages/snap/src/snap.ts"],"sourcesContent":["export function debounce<CB extends (...args: unknown[]) => void>(\n callback: CB,\n delay: number\n) {\n let timer: ReturnType<typeof setTimeout> | undefined\n return function <T>(this: T, ...args: Parameters<typeof callback>): void {\n clearTimeout(timer)\n timer = setTimeout(() => {\n timer = undefined\n callback.apply(this, args)\n }, delay)\n }\n}\n","import { debounce } from './debounce'\n\nfunction removeParentSticky(element: HTMLElement) {\n const position = getComputedStyle(element).position\n\n const isSticky = position === 'sticky'\n\n if (isSticky) {\n element.style.setProperty('position', 'static')\n element.dataset.sticky = 'true'\n }\n\n if (element.offsetParent) {\n removeParentSticky(element.offsetParent as HTMLElement)\n }\n}\n\nfunction addParentSticky(element: HTMLElement) {\n if (element?.dataset?.sticky === 'true') {\n element.style.removeProperty('position')\n delete element.dataset.sticky\n }\n\n if (element.offsetParent) {\n addParentSticky(element.offsetParent as HTMLElement)\n }\n}\n\nfunction offsetTop(element: HTMLElement, accumulator = 0) {\n const top = accumulator + element.offsetTop\n if (element.offsetParent) {\n return offsetTop(element.offsetParent as HTMLElement, top)\n }\n return top\n}\n\nfunction offsetLeft(element: HTMLElement, accumulator = 0) {\n const left = accumulator + element.offsetLeft\n if (element.offsetParent) {\n return offsetLeft(element.offsetParent as HTMLElement, left)\n }\n return left\n}\n\nfunction scrollTop(element: HTMLElement, accumulator = 0) {\n const top = accumulator + element.scrollTop\n if (element.offsetParent) {\n return scrollTop(element.offsetParent as HTMLElement, top)\n }\n return top + window.scrollY\n}\n\nfunction scrollLeft(element: HTMLElement, accumulator = 0) {\n const left = accumulator + element.scrollLeft\n if (element.offsetParent) {\n return scrollLeft(element.offsetParent as HTMLElement, left)\n }\n return left + window.scrollX\n}\n\nexport type SnapElementOptions = {\n align?: string | string[]\n ignoreSticky?: boolean\n ignoreTransform?: boolean\n}\n\ntype Rect = {\n top: number\n left: number\n width: number\n height: number\n x: number\n y: number\n bottom: number\n right: number\n element: HTMLElement\n}\n\nexport class SnapElement {\n element: HTMLElement\n options: SnapElementOptions\n align: string[]\n // @ts-expect-error\n rect: Rect = {}\n wrapperResizeObserver: ResizeObserver\n resizeObserver: ResizeObserver\n debouncedWrapperResize: () => void\n\n constructor(\n element: HTMLElement,\n {\n align = ['start'],\n ignoreSticky = true,\n ignoreTransform = false,\n }: SnapElementOptions = {}\n ) {\n this.element = element\n\n this.options = { align, ignoreSticky, ignoreTransform }\n\n this.align = [align].flat()\n\n this.debouncedWrapperResize = debounce(this.onWrapperResize, 500)\n\n this.wrapperResizeObserver = new ResizeObserver(this.debouncedWrapperResize)\n this.wrapperResizeObserver.observe(document.body)\n this.onWrapperResize()\n\n this.resizeObserver = new ResizeObserver(this.onResize)\n this.resizeObserver.observe(this.element)\n this.setRect({\n width: this.element.offsetWidth,\n height: this.element.offsetHeight,\n })\n }\n\n destroy() {\n this.wrapperResizeObserver.disconnect()\n this.resizeObserver.disconnect()\n }\n\n setRect({\n top,\n left,\n width,\n height,\n element,\n }: {\n top?: number\n left?: number\n width?: number\n height?: number\n element?: HTMLElement\n } = {}) {\n top = top ?? this.rect.top\n left = left ?? this.rect.left\n width = width ?? this.rect.width\n height = height ?? this.rect.height\n element = element ?? this.rect.element\n\n if (\n top === this.rect.top &&\n left === this.rect.left &&\n width === this.rect.width &&\n height === this.rect.height &&\n element === this.rect.element\n )\n return\n\n this.rect.top = top\n this.rect.y = top\n this.rect.width = width\n this.rect.height = height\n this.rect.left = left\n this.rect.x = left\n this.rect.bottom = top + height\n this.rect.right = left + width\n }\n\n onWrapperResize = () => {\n let top: number | undefined\n let left: number | undefined\n\n if (this.options.ignoreSticky) removeParentSticky(this.element)\n if (this.options.ignoreTransform) {\n top = offsetTop(this.element)\n left = offsetLeft(this.element)\n } else {\n const rect = this.element.getBoundingClientRect()\n top = rect.top + scrollTop(this.element)\n left = rect.left + scrollLeft(this.element)\n }\n if (this.options.ignoreSticky) addParentSticky(this.element)\n\n this.setRect({ top, left })\n }\n\n onResize = ([entry]: ResizeObserverEntry[]) => {\n if (!entry?.borderBoxSize[0]) return\n const width = entry.borderBoxSize[0].inlineSize\n const height = entry.borderBoxSize[0].blockSize\n\n this.setRect({ width, height })\n }\n}\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'\nimport type { VirtualScrollData } from 'lenis'\nimport { debounce } from './debounce'\nimport type { SnapElementOptions } from './element'\nimport { SnapElement } from './element'\nimport type { SnapItem, SnapOptions } from './types'\nimport type { UID } from './uid'\nimport { uid } from './uid'\n\n// TODO:\n// - fix wheel scrolling after limits (see console scroll to)\n// - arrow, spacebar\n\ntype RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>\n\n/**\n * Snap class to handle the snap functionality\n *\n * @example\n * const snap = new Snap(lenis, {\n * type: 'mandatory', // 'mandatory', 'proximity' or 'lock'\n * onSnapStart: (snap) => {\n * console.log('onSnapStart', snap)\n * },\n * onSnapComplete: (snap) => {\n * console.log('onSnapComplete', snap)\n * },\n * })\n *\n * snap.add(500) // snap at 500px\n *\n * const removeSnap = snap.add(500)\n *\n * if (someCondition) {\n * removeSnap()\n * }\n */\nexport class Snap {\n options: RequiredPick<SnapOptions, 'type' | 'debounce'>\n elements = new Map<UID, SnapElement>()\n snaps = new Map<UID, SnapItem>()\n viewport: { width: number; height: number } = {\n width: window.innerWidth,\n height: window.innerHeight,\n }\n isStopped = false\n onSnapDebounced: (e: VirtualScrollData) => void\n currentSnapIndex?: number\n\n constructor(\n private lenis: Lenis,\n {\n type = 'proximity',\n lerp,\n easing,\n duration,\n distanceThreshold = '50%', // useless when type is \"mandatory\"\n debounce: debounceDelay = 500,\n onSnapStart,\n onSnapComplete,\n }: SnapOptions = {}\n ) {\n if (!window.lenis) {\n window.lenis = {}\n }\n\n window.lenis.snap = true\n\n this.options = {\n type,\n lerp,\n easing,\n duration,\n distanceThreshold,\n debounce: debounceDelay,\n onSnapStart,\n onSnapComplete,\n }\n\n this.onWindowResize()\n window.addEventListener('resize', this.onWindowResize)\n\n this.onSnapDebounced = debounce(\n this.onSnap as (...args: unknown[]) => void,\n this.options.debounce\n )\n\n this.lenis.on('virtual-scroll', this.onSnapDebounced)\n }\n\n /**\n * Destroy the snap instance\n */\n destroy() {\n this.lenis.off('virtual-scroll', this.onSnapDebounced)\n window.removeEventListener('resize', this.onWindowResize)\n this.elements.forEach((element) => {\n element.destroy()\n })\n }\n\n /**\n * Start the snap after it has been stopped\n */\n start() {\n this.isStopped = false\n }\n\n /**\n * Stop the snap\n */\n stop() {\n this.isStopped = true\n }\n\n /**\n * Add a snap to the snap instance\n *\n * @param value The value to snap to\n * @param userData User data that will be forwarded through the snap event\n * @returns Unsubscribe function\n */\n add(value: number): () => void {\n const id = uid()\n\n this.snaps.set(id, { value })\n\n return () => this.snaps.delete(id)\n }\n\n /**\n * Add an element to the snap instance\n *\n * @param element The element to add\n * @param options The options for the element\n * @returns Unsubscribe function\n */\n addElement(\n element: HTMLElement,\n options: SnapElementOptions = {}\n ): () => void {\n const id = uid()\n\n this.elements.set(id, new SnapElement(element, options))\n\n return () => this.elements.delete(id)\n }\n\n addElements(\n elements: HTMLElement[],\n options: SnapElementOptions = {}\n ): () => void {\n const map = [...elements].map((element) =>\n this.addElement(element, options)\n )\n return () => {\n map.forEach((remove) => {\n remove()\n })\n }\n }\n\n private onWindowResize = () => {\n this.viewport.width = window.innerWidth\n this.viewport.height = window.innerHeight\n }\n\n private computeSnaps = () => {\n const { isHorizontal } = this.lenis\n\n let snaps = [...this.snaps.values()] as SnapItem[]\n\n this.elements.forEach(({ rect, align }) => {\n let value: number | undefined\n\n align.forEach((align) => {\n if (align === 'start') {\n value = rect.top\n } else if (align === 'center') {\n value = isHorizontal\n ? rect.left + rect.width / 2 - this.viewport.width / 2\n : rect.top + rect.height / 2 - this.viewport.height / 2\n } else if (align === 'end') {\n value = isHorizontal\n ? rect.left + rect.width - this.viewport.width\n : rect.top + rect.height - this.viewport.height\n }\n\n if (typeof value === 'number') {\n snaps.push({ value: Math.ceil(value) })\n }\n })\n })\n\n snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value))\n\n return snaps\n }\n\n previous() {\n this.goTo((this.currentSnapIndex ?? 0) - 1)\n }\n\n next() {\n this.goTo((this.currentSnapIndex ?? 0) + 1)\n }\n\n goTo(index: number) {\n const snaps = this.computeSnaps()\n\n if (snaps.length === 0) return\n\n this.currentSnapIndex = Math.max(0, Math.min(index, snaps.length - 1))\n\n const currentSnap = snaps[this.currentSnapIndex]\n if (currentSnap === undefined) return\n\n this.lenis.scrollTo(currentSnap.value, {\n duration: this.options.duration,\n easing: this.options.easing,\n lerp: this.options.lerp,\n lock: this.options.type === 'lock',\n userData: { initiator: 'snap' },\n onStart: () => {\n this.options.onSnapStart?.({\n index: this.currentSnapIndex,\n ...currentSnap,\n })\n },\n onComplete: () => {\n this.options.onSnapComplete?.({\n index: this.currentSnapIndex,\n ...currentSnap,\n })\n },\n })\n }\n\n get distanceThreshold() {\n let distanceThreshold = Number.POSITIVE_INFINITY\n if (this.options.type === 'mandatory') return Number.POSITIVE_INFINITY\n\n const { isHorizontal } = this.lenis\n\n const axis = isHorizontal ? 'width' : 'height'\n\n if (\n typeof this.options.distanceThreshold === 'string' &&\n this.options.distanceThreshold.endsWith('%')\n ) {\n distanceThreshold =\n (Number(this.options.distanceThreshold.replace('%', '')) / 100) *\n this.viewport[axis]\n } else if (typeof this.options.distanceThreshold === 'number') {\n distanceThreshold = this.options.distanceThreshold\n } else {\n distanceThreshold = this.viewport[axis]\n }\n\n return distanceThreshold\n }\n\n private onSnap = (e: VirtualScrollData) => {\n if (this.isStopped) return\n\n if (e.event.type === 'touchmove') return\n\n if (\n this.options.type === 'lock' &&\n this.lenis.userData?.initiator === 'snap'\n )\n return\n\n let { scroll, isHorizontal } = this.lenis\n const delta = isHorizontal ? e.deltaX : e.deltaY\n scroll = Math.ceil(this.lenis.scroll + delta)\n\n const snaps = this.computeSnaps()\n\n if (snaps.length === 0) return\n\n let snapIndex: number | undefined\n\n const prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll)\n const nextSnapIndex = snaps.findIndex(({ value }) => value > scroll)\n\n if (this.options.type === 'lock') {\n if (delta > 0) {\n snapIndex = nextSnapIndex\n } else if (delta < 0) {\n snapIndex = prevSnapIndex\n }\n } else {\n const prevSnap = snaps[prevSnapIndex]!\n const distanceToPrevSnap = prevSnap\n ? Math.abs(scroll - prevSnap.value)\n : Number.POSITIVE_INFINITY\n\n const nextSnap = snaps[nextSnapIndex]!\n const distanceToNextSnap = nextSnap\n ? Math.abs(scroll - nextSnap.value)\n : Number.POSITIVE_INFINITY\n snapIndex =\n distanceToPrevSnap < distanceToNextSnap ? prevSnapIndex : nextSnapIndex\n }\n\n if (snapIndex === undefined) return\n if (snapIndex === -1) return\n\n snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1))\n\n const snap = snaps[snapIndex]!\n\n const distance = Math.abs(scroll - snap.value)\n\n if (distance <= this.distanceThreshold) {\n this.goTo(snapIndex)\n }\n }\n\n resize() {\n this.elements.forEach((element) => {\n element.onWrapperResize()\n })\n }\n}\n"],"mappings":"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"}