(function() {


//#region packages/snap/src/debounce.ts
	function debounce(callback, delay) {
		let timer;
		return function(...args) {
			clearTimeout(timer);
			timer = setTimeout(() => {
				timer = void 0;
				callback.apply(this, args);
			}, delay);
		};
	}

//#endregion
//#region packages/snap/src/element.ts
	function removeParentSticky(element) {
		if (getComputedStyle(element).position === "sticky") {
			element.style.setProperty("position", "static");
			element.dataset.sticky = "true";
		}
		if (element.offsetParent) removeParentSticky(element.offsetParent);
	}
	function addParentSticky(element) {
		if (element?.dataset?.sticky === "true") {
			element.style.removeProperty("position");
			delete element.dataset.sticky;
		}
		if (element.offsetParent) addParentSticky(element.offsetParent);
	}
	function offsetTop(element, accumulator = 0) {
		const top = accumulator + element.offsetTop;
		if (element.offsetParent) return offsetTop(element.offsetParent, top);
		return top;
	}
	function offsetLeft(element, accumulator = 0) {
		const left = accumulator + element.offsetLeft;
		if (element.offsetParent) return offsetLeft(element.offsetParent, left);
		return left;
	}
	function scrollTop(element, accumulator = 0) {
		const top = accumulator + element.scrollTop;
		if (element.offsetParent) return scrollTop(element.offsetParent, top);
		return top + window.scrollY;
	}
	function scrollLeft(element, accumulator = 0) {
		const left = accumulator + element.scrollLeft;
		if (element.offsetParent) return scrollLeft(element.offsetParent, left);
		return left + window.scrollX;
	}
	var SnapElement = class {
		element;
		options;
		align;
		rect = {};
		wrapperResizeObserver;
		resizeObserver;
		debouncedWrapperResize;
		constructor(element, { align = ["start"], ignoreSticky = true, ignoreTransform = false } = {}) {
			this.element = element;
			this.options = {
				align,
				ignoreSticky,
				ignoreTransform
			};
			this.align = [align].flat();
			this.debouncedWrapperResize = debounce(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, left, width, height, element } = {}) {
			top = top ?? this.rect.top;
			left = left ?? this.rect.left;
			width = width ?? this.rect.width;
			height = height ?? this.rect.height;
			element = element ?? this.rect.element;
			if (top === this.rect.top && left === this.rect.left && width === this.rect.width && height === this.rect.height && element === this.rect.element) return;
			this.rect.top = top;
			this.rect.y = top;
			this.rect.width = width;
			this.rect.height = height;
			this.rect.left = left;
			this.rect.x = left;
			this.rect.bottom = top + height;
			this.rect.right = left + width;
		}
		onWrapperResize = () => {
			let top;
			let left;
			if (this.options.ignoreSticky) removeParentSticky(this.element);
			if (this.options.ignoreTransform) {
				top = offsetTop(this.element);
				left = offsetLeft(this.element);
			} else {
				const rect = this.element.getBoundingClientRect();
				top = rect.top + scrollTop(this.element);
				left = rect.left + scrollLeft(this.element);
			}
			if (this.options.ignoreSticky) addParentSticky(this.element);
			this.setRect({
				top,
				left
			});
		};
		onResize = ([entry]) => {
			if (!entry?.borderBoxSize[0]) return;
			const width = entry.borderBoxSize[0].inlineSize;
			const height = entry.borderBoxSize[0].blockSize;
			this.setRect({
				width,
				height
			});
		};
	};

//#endregion
//#region packages/snap/src/uid.ts
	let index = 0;
	function uid() {
		return index++;
	}

//#endregion
//#region packages/snap/src/snap.ts
/**
	* Snap class to handle the snap functionality
	*
	* @example
	* const snap = new Snap(lenis, {
	*   type: 'mandatory', // 'mandatory', 'proximity' or 'lock'
	*   onSnapStart: (snap) => {
	*     console.log('onSnapStart', snap)
	*   },
	*   onSnapComplete: (snap) => {
	*     console.log('onSnapComplete', snap)
	*   },
	* })
	*
	* snap.add(500) // snap at 500px
	*
	* const removeSnap = snap.add(500)
	*
	* if (someCondition) {
	*   removeSnap()
	* }
	*/
	var Snap = class {
		options;
		elements = /* @__PURE__ */ new Map();
		snaps = /* @__PURE__ */ new Map();
		viewport = {
			width: window.innerWidth,
			height: window.innerHeight
		};
		isStopped = false;
		onSnapDebounced;
		currentSnapIndex;
		constructor(lenis, { type = "proximity", lerp, easing, duration, distanceThreshold = "50%", debounce: debounceDelay = 500, onSnapStart, onSnapComplete } = {}) {
			this.lenis = lenis;
			if (!window.lenis) window.lenis = {};
			window.lenis.snap = true;
			this.options = {
				type,
				lerp,
				easing,
				duration,
				distanceThreshold,
				debounce: debounceDelay,
				onSnapStart,
				onSnapComplete
			};
			this.onWindowResize();
			window.addEventListener("resize", this.onWindowResize);
			this.onSnapDebounced = debounce(this.onSnap, this.options.debounce);
			this.lenis.on("virtual-scroll", this.onSnapDebounced);
		}
		/**
		* Destroy the snap instance
		*/
		destroy() {
			this.lenis.off("virtual-scroll", this.onSnapDebounced);
			window.removeEventListener("resize", this.onWindowResize);
			this.elements.forEach((element) => {
				element.destroy();
			});
		}
		/**
		* Start the snap after it has been stopped
		*/
		start() {
			this.isStopped = false;
		}
		/**
		* Stop the snap
		*/
		stop() {
			this.isStopped = true;
		}
		/**
		* Add a snap to the snap instance
		*
		* @param value The value to snap to
		* @param userData User data that will be forwarded through the snap event
		* @returns Unsubscribe function
		*/
		add(value) {
			const id = uid();
			this.snaps.set(id, { value });
			return () => this.snaps.delete(id);
		}
		/**
		* Add an element to the snap instance
		*
		* @param element The element to add
		* @param options The options for the element
		* @returns Unsubscribe function
		*/
		addElement(element, options = {}) {
			const id = uid();
			this.elements.set(id, new SnapElement(element, options));
			return () => this.elements.delete(id);
		}
		addElements(elements, options = {}) {
			const map = [...elements].map((element) => this.addElement(element, options));
			return () => {
				map.forEach((remove) => {
					remove();
				});
			};
		}
		onWindowResize = () => {
			this.viewport.width = window.innerWidth;
			this.viewport.height = window.innerHeight;
		};
		computeSnaps = () => {
			const { isHorizontal } = this.lenis;
			let snaps = [...this.snaps.values()];
			this.elements.forEach(({ rect, align }) => {
				let value;
				align.forEach((align) => {
					if (align === "start") value = rect.top;
					else if (align === "center") value = isHorizontal ? rect.left + rect.width / 2 - this.viewport.width / 2 : rect.top + rect.height / 2 - this.viewport.height / 2;
					else if (align === "end") value = isHorizontal ? rect.left + rect.width - this.viewport.width : rect.top + rect.height - this.viewport.height;
					if (typeof value === "number") snaps.push({ value: Math.ceil(value) });
				});
			});
			snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value));
			return snaps;
		};
		previous() {
			this.goTo((this.currentSnapIndex ?? 0) - 1);
		}
		next() {
			this.goTo((this.currentSnapIndex ?? 0) + 1);
		}
		goTo(index) {
			const snaps = this.computeSnaps();
			if (snaps.length === 0) return;
			this.currentSnapIndex = Math.max(0, Math.min(index, snaps.length - 1));
			const currentSnap = snaps[this.currentSnapIndex];
			if (currentSnap === void 0) return;
			this.lenis.scrollTo(currentSnap.value, {
				duration: this.options.duration,
				easing: this.options.easing,
				lerp: this.options.lerp,
				lock: this.options.type === "lock",
				userData: { initiator: "snap" },
				onStart: () => {
					this.options.onSnapStart?.({
						index: this.currentSnapIndex,
						...currentSnap
					});
				},
				onComplete: () => {
					this.options.onSnapComplete?.({
						index: this.currentSnapIndex,
						...currentSnap
					});
				}
			});
		}
		get distanceThreshold() {
			let distanceThreshold = Number.POSITIVE_INFINITY;
			if (this.options.type === "mandatory") return Number.POSITIVE_INFINITY;
			const { isHorizontal } = this.lenis;
			const axis = isHorizontal ? "width" : "height";
			if (typeof this.options.distanceThreshold === "string" && this.options.distanceThreshold.endsWith("%")) distanceThreshold = Number(this.options.distanceThreshold.replace("%", "")) / 100 * this.viewport[axis];
			else if (typeof this.options.distanceThreshold === "number") distanceThreshold = this.options.distanceThreshold;
			else distanceThreshold = this.viewport[axis];
			return distanceThreshold;
		}
		onSnap = (e) => {
			if (this.isStopped) return;
			if (e.event.type === "touchmove") return;
			if (this.options.type === "lock" && this.lenis.userData?.initiator === "snap") return;
			let { scroll, isHorizontal } = this.lenis;
			const delta = isHorizontal ? e.deltaX : e.deltaY;
			scroll = Math.ceil(this.lenis.scroll + delta);
			const snaps = this.computeSnaps();
			if (snaps.length === 0) return;
			let snapIndex;
			const prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll);
			const nextSnapIndex = snaps.findIndex(({ value }) => value > scroll);
			if (this.options.type === "lock") {
				if (delta > 0) snapIndex = nextSnapIndex;
				else if (delta < 0) snapIndex = prevSnapIndex;
			} else {
				const prevSnap = snaps[prevSnapIndex];
				const distanceToPrevSnap = prevSnap ? Math.abs(scroll - prevSnap.value) : Number.POSITIVE_INFINITY;
				const nextSnap = snaps[nextSnapIndex];
				snapIndex = distanceToPrevSnap < (nextSnap ? Math.abs(scroll - nextSnap.value) : Number.POSITIVE_INFINITY) ? prevSnapIndex : nextSnapIndex;
			}
			if (snapIndex === void 0) return;
			if (snapIndex === -1) return;
			snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1));
			const snap = snaps[snapIndex];
			if (Math.abs(scroll - snap.value) <= this.distanceThreshold) this.goTo(snapIndex);
		};
		resize() {
			this.elements.forEach((element) => {
				element.onWrapperResize();
			});
		}
	};

//#endregion
//#region packages/snap/browser.ts
	globalThis.Snap = Snap;

//#endregion
})();
//# sourceMappingURL=lenis-snap.js.map