"use client";
import { useCallback, useEffect, useRef, useState } from "react";
//#region packages/@mantine/hooks/src/use-floating-window/use-floating-window.ts
function useRefValue(value) {
	const ref = useRef(value);
	ref.current = value;
	return ref;
}
function useFloatingWindow(options = {}) {
	const [element, setElement] = useState(null);
	const ref = useRef(null);
	const pos = useRef({
		x: 0,
		y: 0
	});
	const offset = useRef({
		x: 0,
		y: 0
	});
	const [isDragging, setIsDragging] = useState(false);
	const isDraggingRef = useRef(false);
	const initialized = useRef(false);
	const enabledRef = useRefValue(options.enabled);
	const setDragging = useCallback((value) => {
		setIsDragging(value);
		isDraggingRef.current = value;
	}, []);
	const assignRef = useCallback((node) => {
		if (node) {
			ref.current = node;
			setElement(node);
		} else {
			ref.current = null;
			setElement(null);
		}
	}, []);
	useEffect(() => {
		const el = ref.current;
		if (!initialized.current && el) {
			initialized.current = true;
			pos.current = calculateInitialPosition(el, options);
			el.style.left = `${pos.current.x}px`;
			el.style.top = `${pos.current.y}px`;
			el.style.right = "unset";
			el.style.bottom = "unset";
		}
		return () => {
			initialized.current = false;
		};
	}, [
		element,
		options.constrainOffset,
		options.initialPosition?.top,
		options.initialPosition?.left,
		options.initialPosition?.right,
		options.initialPosition?.bottom,
		options.constrainToViewport
	]);
	useEffect(() => {
		const el = ref.current;
		if (!el) return;
		const controller = new AbortController();
		const signal = controller.signal;
		const onStart = (e) => {
			if (enabledRef.current === false) return;
			const point = "touches" in e ? e.touches[0] : e;
			if ("button" in e && e.button !== 0) return;
			if (!getHandle(el, e.target, options)) return;
			setDragging(true);
			document.body.style.userSelect = "none";
			document.body.style.webkitUserSelect = "none";
			const rect = el.getBoundingClientRect();
			offset.current = {
				x: point.clientX - rect.left,
				y: point.clientY - rect.top
			};
			options.onDragStart?.();
			document.addEventListener("mousemove", onMove, { signal });
			document.addEventListener("mouseup", onEnd, { signal });
			document.addEventListener("touchmove", onMove, {
				signal,
				passive: false
			});
			document.addEventListener("touchend", onEnd, { signal });
		};
		const onMove = (e) => {
			if (!isDraggingRef.current) return;
			const point = "touches" in e ? e.touches[0] : e;
			e.preventDefault();
			let x = point.clientX - offset.current.x;
			let y = point.clientY - offset.current.y;
			const constrained = getConstrainedPosition(el, {
				x,
				y
			}, options);
			if (options.axis === "x") {
				x = constrained.x;
				y = pos.current.y;
			} else if (options.axis === "y") {
				x = pos.current.x;
				y = constrained.y;
			} else {
				x = constrained.x;
				y = constrained.y;
			}
			pos.current = {
				x,
				y
			};
			if (ref.current) {
				ref.current.style.left = `${x}px`;
				ref.current.style.top = `${y}px`;
			}
			options.onPositionChange?.({
				x,
				y
			});
		};
		const onEnd = () => {
			if (isDraggingRef.current) {
				setDragging(false);
				document.body.style.userSelect = "";
				document.body.style.webkitUserSelect = "";
				options.onDragEnd?.();
			}
		};
		el.addEventListener("mousedown", onStart, { signal });
		el.addEventListener("touchstart", onStart, {
			signal,
			passive: false
		});
		return () => {
			controller.abort();
		};
	}, [
		options.constrainToViewport,
		options.constrainOffset,
		options.dragHandleSelector,
		options.axis,
		options.onPositionChange,
		options.onDragStart,
		options.onDragEnd,
		options.initialPosition?.top,
		options.initialPosition?.left,
		options.initialPosition?.right,
		options.initialPosition?.bottom,
		element
	]);
	useEffect(() => {
		const el = ref.current;
		if (!el) return;
		const observer = new ResizeObserver(() => {
			const constrained = getConstrainedPosition(el, pos.current, options);
			pos.current = constrained;
			el.style.left = `${constrained.x}px`;
			el.style.top = `${constrained.y}px`;
		});
		observer.observe(el);
		return () => {
			observer.disconnect();
		};
	}, [options.constrainToViewport, options.constrainOffset]);
	return {
		ref: assignRef,
		setPosition: useCallback((position) => {
			const el = ref.current;
			if (!el) return;
			const offset = options.constrainOffset ?? 0;
			const rect = el.getBoundingClientRect();
			let x;
			let y;
			if (position.left != null) x = position.left;
			else if (position.right != null) x = window.innerWidth - rect.width - position.right;
			if (position.top != null) y = position.top;
			else if (position.bottom != null) y = window.innerHeight - rect.height - position.bottom;
			x = x ?? pos.current.x;
			y = y ?? pos.current.y;
			if (options.constrainToViewport) {
				const clamped = clampToViewport(x, y, el, offset);
				x = clamped.x;
				y = clamped.y;
			}
			pos.current = {
				x,
				y
			};
			el.style.left = `${x}px`;
			el.style.top = `${y}px`;
			options.onPositionChange?.({
				x,
				y
			});
		}, [
			options.constrainToViewport,
			options.constrainOffset,
			options.onPositionChange
		]),
		isDragging
	};
}
function px(v) {
	return v.endsWith("px") ? parseFloat(v) : 0;
}
function calculateInitialPosition(el, options) {
	const rect = el.getBoundingClientRect();
	const offset = options.constrainOffset ?? 0;
	const winW = window.innerWidth;
	const winH = window.innerHeight;
	const style = window.getComputedStyle(el);
	const top = options.initialPosition?.top;
	const left = options.initialPosition?.left;
	const right = options.initialPosition?.right;
	const bottom = options.initialPosition?.bottom;
	let x = offset;
	let y = offset;
	if (left != null) x = left;
	else if (right != null) x = winW - rect.width - right;
	else x = px(style.left) || winW - rect.width - px(style.right) || offset;
	if (top != null) y = top;
	else if (bottom != null) y = winH - rect.height - bottom;
	else y = px(style.top) || winH - rect.height - px(style.bottom) || offset;
	return options.constrainToViewport ? clampToViewport(x, y, el, options.constrainOffset) : {
		x,
		y
	};
}
function getConstrainedPosition(el, pos, options) {
	if (!options.constrainToViewport || !el) return pos;
	const rect = el.getBoundingClientRect();
	const offset = options.constrainOffset ?? 0;
	const maxX = window.innerWidth - rect.width - offset;
	const maxY = window.innerHeight - rect.height - offset;
	return {
		x: Math.min(Math.max(offset, pos.x), maxX),
		y: Math.min(Math.max(offset, pos.y), maxY)
	};
}
function matchesExcludeSelector(target, excludeSelector) {
	if (!excludeSelector) return false;
	if (!(target instanceof Element)) return false;
	return Boolean(target.closest(excludeSelector));
}
function getHandle(el, target, options) {
	if (!(target instanceof Node)) return false;
	if (!options.dragHandleSelector) return !matchesExcludeSelector(target, options.excludeDragHandleSelector);
	return Array.from(el.querySelectorAll(options.dragHandleSelector)).some((handle) => handle.contains(target) && !matchesExcludeSelector(target, options.excludeDragHandleSelector));
}
function clampToViewport(x, y, el, offset = 0) {
	const rect = el.getBoundingClientRect();
	const maxX = window.innerWidth - rect.width - offset;
	const maxY = window.innerHeight - rect.height - offset;
	return {
		x: Math.min(Math.max(offset, x), maxX),
		y: Math.min(Math.max(offset, y), maxY)
	};
}
//#endregion
export { useFloatingWindow };

//# sourceMappingURL=use-floating-window.mjs.map