"use client";
import { useCallback, useRef, useState } from "react";
//#region packages/@mantine/hooks/src/use-drag/use-drag.ts
const VELOCITY_DECAY_MS = 100;
function sign(n) {
	if (n > 0) return 1;
	if (n < 0) return -1;
	return 0;
}
function getThresholdVector(threshold) {
	const t = threshold ?? 0;
	if (typeof t === "number") return [t, t];
	return t;
}
function createInitialState() {
	return {
		isActive: false,
		pointerId: -1,
		startXY: [0, 0],
		prevXY: [0, 0],
		startTimestamp: 0,
		prevTimestamp: 0,
		thresholdMet: false,
		firstFired: false,
		lockedAxis: null,
		canceled: false,
		lastVelocity: [0, 0]
	};
}
function useDrag(handler, options = {}) {
	const [active, setActive] = useState(false);
	const handlerRef = useRef(handler);
	handlerRef.current = handler;
	const optionsRef = useRef(options);
	optionsRef.current = options;
	const stateRef = useRef(createInitialState());
	const documentControllerRef = useRef(null);
	return {
		ref: useCallback((node) => {
			if (!node) return;
			const elementController = new AbortController();
			const applyAxisConstraint = (v) => {
				const opts = optionsRef.current;
				const s = stateRef.current;
				if (opts.axis === "x") return [v[0], 0];
				if (opts.axis === "y") return [0, v[1]];
				if (opts.axis === "lock") {
					if (s.lockedAxis === null) {
						const t = opts.axisThreshold ?? 1;
						if (Math.abs(v[0]) > t || Math.abs(v[1]) > t) s.lockedAxis = Math.abs(v[0]) >= Math.abs(v[1]) ? "x" : "y";
					}
					if (s.lockedAxis === "x") return [v[0], 0];
					if (s.lockedAxis === "y") return [0, v[1]];
				}
				return v;
			};
			const resetDrag = () => {
				const s = stateRef.current;
				s.isActive = false;
				s.pointerId = -1;
				s.thresholdMet = false;
				s.firstFired = false;
				s.lockedAxis = null;
				s.canceled = false;
				setActive(false);
				document.body.style.userSelect = "";
				document.body.style.webkitUserSelect = "";
				documentControllerRef.current?.abort();
				documentControllerRef.current = null;
			};
			const cancel = () => {
				if (stateRef.current.isActive) {
					stateRef.current.canceled = true;
					resetDrag();
				}
			};
			const activateDrag = () => {
				setActive(true);
				document.body.style.userSelect = "none";
				document.body.style.webkitUserSelect = "none";
			};
			const onPointerDown = (event) => {
				if (optionsRef.current.enabled === false) return;
				if (event.button !== 0) return;
				if (stateRef.current.isActive) return;
				const s = stateRef.current;
				s.isActive = true;
				s.pointerId = event.pointerId;
				s.startXY = [event.clientX, event.clientY];
				s.prevXY = [event.clientX, event.clientY];
				s.startTimestamp = event.timeStamp;
				s.prevTimestamp = event.timeStamp;
				s.thresholdMet = false;
				s.firstFired = false;
				s.lockedAxis = null;
				s.canceled = false;
				s.lastVelocity = [0, 0];
				const [tx, ty] = getThresholdVector(optionsRef.current.threshold);
				if (tx === 0 && ty === 0) {
					s.thresholdMet = true;
					s.firstFired = true;
					activateDrag();
					handlerRef.current({
						xy: [event.clientX, event.clientY],
						initial: [event.clientX, event.clientY],
						movement: [0, 0],
						delta: [0, 0],
						distance: [0, 0],
						direction: [0, 0],
						velocity: [0, 0],
						elapsedTime: 0,
						first: true,
						last: false,
						active: true,
						tap: false,
						canceled: false,
						cancel,
						event
					});
				}
				documentControllerRef.current?.abort();
				documentControllerRef.current = new AbortController();
				const sig = documentControllerRef.current.signal;
				document.addEventListener("pointermove", onPointerMove, { signal: sig });
				document.addEventListener("pointerup", onPointerUp, { signal: sig });
				document.addEventListener("pointercancel", onPointerCancel, { signal: sig });
			};
			const onPointerMove = (event) => {
				const s = stateRef.current;
				if (!s.isActive || event.pointerId !== s.pointerId) return;
				const rawMovement = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];
				if (!s.thresholdMet) {
					const [tx, ty] = getThresholdVector(optionsRef.current.threshold);
					if (Math.abs(rawMovement[0]) < tx && Math.abs(rawMovement[1]) < ty) {
						s.prevXY = [event.clientX, event.clientY];
						s.prevTimestamp = event.timeStamp;
						return;
					}
					s.thresholdMet = true;
					activateDrag();
				}
				const movement = applyAxisConstraint(rawMovement);
				const delta = applyAxisConstraint([event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]]);
				const timeDelta = event.timeStamp - s.prevTimestamp;
				const velocity = timeDelta > 0 ? [Math.abs(delta[0]) / timeDelta, Math.abs(delta[1]) / timeDelta] : s.lastVelocity;
				s.lastVelocity = velocity;
				const isFirst = !s.firstFired;
				s.firstFired = true;
				s.prevXY = [event.clientX, event.clientY];
				s.prevTimestamp = event.timeStamp;
				handlerRef.current({
					xy: [event.clientX, event.clientY],
					initial: [...s.startXY],
					movement,
					delta,
					distance: [Math.abs(movement[0]), Math.abs(movement[1])],
					direction: [sign(delta[0]), sign(delta[1])],
					velocity,
					elapsedTime: event.timeStamp - s.startTimestamp,
					first: isFirst,
					last: false,
					active: true,
					tap: false,
					canceled: false,
					cancel,
					event
				});
			};
			const onPointerUp = (event) => {
				const s = stateRef.current;
				if (!s.isActive || event.pointerId !== s.pointerId) return;
				const opts = optionsRef.current;
				if (!s.thresholdMet) {
					if (opts.filterTaps) {
						const mov = applyAxisConstraint([event.clientX - s.startXY[0], event.clientY - s.startXY[1]]);
						const dist = [Math.abs(mov[0]), Math.abs(mov[1])];
						const isTap = Math.max(dist[0], dist[1]) < (opts.tapThreshold ?? 3);
						handlerRef.current({
							xy: [event.clientX, event.clientY],
							initial: [...s.startXY],
							movement: mov,
							delta: mov,
							distance: dist,
							direction: [sign(mov[0]), sign(mov[1])],
							velocity: [0, 0],
							elapsedTime: event.timeStamp - s.startTimestamp,
							first: true,
							last: true,
							active: false,
							tap: isTap,
							canceled: false,
							cancel,
							event
						});
					}
					resetDrag();
					return;
				}
				const movement = applyAxisConstraint([event.clientX - s.startXY[0], event.clientY - s.startXY[1]]);
				const distance = [Math.abs(movement[0]), Math.abs(movement[1])];
				const delta = applyAxisConstraint([event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]]);
				const velocity = event.timeStamp - s.prevTimestamp > VELOCITY_DECAY_MS ? [0, 0] : s.lastVelocity;
				const maxDistance = Math.max(distance[0], distance[1]);
				const tap = opts.filterTaps === true && maxDistance < (opts.tapThreshold ?? 3);
				handlerRef.current({
					xy: [event.clientX, event.clientY],
					initial: [...s.startXY],
					movement,
					delta,
					distance,
					direction: [sign(delta[0]), sign(delta[1])],
					velocity,
					elapsedTime: event.timeStamp - s.startTimestamp,
					first: !s.firstFired,
					last: true,
					active: false,
					tap,
					canceled: false,
					cancel,
					event
				});
				resetDrag();
			};
			const onPointerCancel = (event) => {
				const s = stateRef.current;
				if (!s.isActive || event.pointerId !== s.pointerId) return;
				const movement = applyAxisConstraint([event.clientX - s.startXY[0], event.clientY - s.startXY[1]]);
				handlerRef.current({
					xy: [event.clientX, event.clientY],
					initial: [...s.startXY],
					movement,
					delta: [0, 0],
					distance: [Math.abs(movement[0]), Math.abs(movement[1])],
					direction: [0, 0],
					velocity: [0, 0],
					elapsedTime: event.timeStamp - s.startTimestamp,
					first: !s.firstFired,
					last: true,
					active: false,
					tap: false,
					canceled: true,
					cancel,
					event
				});
				resetDrag();
			};
			node.addEventListener("pointerdown", onPointerDown, { signal: elementController.signal });
			return () => {
				elementController.abort();
				documentControllerRef.current?.abort();
				documentControllerRef.current = null;
				if (stateRef.current.isActive) {
					stateRef.current.isActive = false;
					setActive(false);
					document.body.style.userSelect = "";
					document.body.style.webkitUserSelect = "";
				}
			};
		}, []),
		active
	};
}
//#endregion
export { useDrag };

//# sourceMappingURL=use-drag.mjs.map