// #region Imports
// #endregion
// #region Distance & Direction
/**
 * Calculate Euclidean distance between two points.
 *
 * @param p1 - First point.
 * @param p2 - Second point.
 * @returns Distance between points.
 *
 * @public
 */
export function getDistance(p1, p2) {
    const dx = p2.x - p1.x;
    const dy = p2.y - p1.y;
    return Math.sqrt((dx * dx) + (dy * dy));
}
/**
 * Calculate delta between two points.
 *
 * @param from - Start point.
 * @param to - End point.
 * @returns Delta as point.
 *
 * @public
 */
export function getDelta(from, to) {
    return {
        x: to.x - from.x,
        y: to.y - from.y
    };
}
/**
 * Add two points.
 *
 * @param p1 - First point.
 * @param p2 - Second point.
 * @returns Sum of points.
 *
 * @public
 */
export function addPoints(p1, p2) {
    return {
        x: p1.x + p2.x,
        y: p1.y + p2.y
    };
}
/**
 * Subtract two points.
 *
 * @param p1 - First point.
 * @param p2 - Second point.
 * @returns Difference of points.
 *
 * @public
 */
export function subtractPoints(p1, p2) {
    return {
        x: p1.x - p2.x,
        y: p1.y - p2.y
    };
}
// #endregion
// #region Point in Rect
/**
 * Check if a point is inside a DOMRect.
 *
 * @param point - Point to check.
 * @param rect - Rectangle.
 * @returns True if point is inside rect.
 *
 * @public
 */
export function isPointInsideRect(point, rect) {
    return (point.x >= rect.left &&
        point.x <= rect.right &&
        point.y >= rect.top &&
        point.y <= rect.bottom);
}
/**
 * Check if a point is near the edge of a rect.
 *
 * @param point - Point to check.
 * @param rect - Rectangle.
 * @param threshold - Distance threshold in pixels.
 * @returns Object indicating which edges are near.
 *
 * @public
 */
export function isPointNearEdge(point, rect, threshold) {
    return {
        top: point.y - rect.top < threshold,
        right: rect.right - point.x < threshold,
        bottom: rect.bottom - point.y < threshold,
        left: point.x - rect.left < threshold
    };
}
// #endregion
// #region Element Position
/**
 * Get the center point of a DOMRect.
 *
 * @param rect - Rectangle.
 * @returns Center point.
 *
 * @public
 */
export function getRectCenter(rect) {
    return {
        x: rect.left + (rect.width / 2),
        y: rect.top + (rect.height / 2)
    };
}
/**
 * Get the top-left corner of a DOMRect.
 *
 * @param rect - Rectangle.
 * @returns Top-left point.
 *
 * @public
 */
export function getRectTopLeft(rect) {
    return {
        x: rect.left,
        y: rect.top
    };
}
/**
 * Get element position from PointerEvent.
 *
 * @param event - Pointer event.
 * @returns Point with clientX/clientY.
 *
 * @public
 */
export function getPointerPosition(event) {
    if ('clientX' in event) {
        return { x: event.clientX,
            y: event.clientY };
    }
    else if ('touches' in event && event.touches.length > 0) {
        return { x: event.touches[0].clientX,
            y: event.touches[0].clientY };
    }
    return { x: 0,
        y: 0 };
}
// #endregion
// #region Viewport & Scrolling
/**
 * Get the current viewport dimensions.
 *
 * @returns Viewport size.
 *
 * @public
 */
export function getViewportSize() {
    return {
        width: window.innerWidth,
        height: window.innerHeight
    };
}
/**
 * Adjust rect for scroll offset.
 *
 * @param rect - Original rect.
 * @param scrollTop - Scroll top offset.
 * @param scrollLeft - Scroll left offset.
 * @returns Adjusted rect.
 *
 * @public
 */
export function adjustRectForScroll(rect, scrollTop, scrollLeft) {
    return new DOMRect(rect.x + scrollLeft, rect.y + scrollTop, rect.width, rect.height);
}
// #endregion
// #region Constrain Position
/**
 * Constrain a point within a boundary rect.
 *
 * @param point - Point to constrain.
 * @param boundary - Boundary rect.
 * @param elementSize - Size of the element being positioned.
 * @returns Constrained point.
 *
 * @public
 */
export function constrainPointToBoundary(point, boundary, elementSize) {
    return {
        x: Math.max(boundary.left, Math.min(point.x, boundary.right - elementSize.width)),
        y: Math.max(boundary.top, Math.min(point.y, boundary.bottom - elementSize.height))
    };
}
/**
 * Constrain position to axis.
 *
 * @param point - Point to constrain.
 * @param initialPoint - Initial position (for locked axis).
 * @param lockAxis - Axis to lock ('x', 'y', or null).
 * @returns Constrained point.
 *
 * @public
 */
export function constrainToAxis(point, initialPoint, lockAxis) {
    if (lockAxis === 'x') {
        return { x: point.x,
            y: initialPoint.y };
    }
    else if (lockAxis === 'y') {
        return { x: initialPoint.x,
            y: point.y };
    }
    return point;
}
// #endregion
// #region Transform Utilities
/**
 * Apply transform to an element.
 *
 * @param element - Element to transform.
 * @param position - Position to apply.
 *
 * @public
 */
export function applyTransform(element, position) {
    /* eslint-disable no-restricted-syntax */
    element.style.setProperty('transform', `translate3d(${position.x}px, ${position.y}px, 0)`);
    /* eslint-enable no-restricted-syntax */
}
/**
 * Clear transform from an element.
 *
 * @param element - Element to clear transform from.
 *
 * @public
 */
export function clearTransform(element) {
    /* eslint-disable no-restricted-syntax */
    element.style.removeProperty('transform');
    /* eslint-enable no-restricted-syntax */
}
/**
 * Get current transform position from an element.
 *
 * @param element - Element to read from.
 * @returns Current transform position.
 *
 * @public
 */
export function getTransformPosition(element) {
    const style = window.getComputedStyle(element);
    const transform = style.transform;
    if (transform === 'none' || !transform) {
        return { x: 0,
            y: 0 };
    }
    const match = (/matrix\((.+)\)/).exec(transform);
    if (match) {
        const values = match[1].split(', ');
        return {
            x: parseFloat(values[4]) || 0,
            y: parseFloat(values[5]) || 0
        };
    }
    return { x: 0,
        y: 0 };
}
// #endregion
// #region Element Utilities
/**
 * Create a clone of an element for preview.
 *
 * @param element - Element to clone.
 * @returns Cloned element.
 *
 * @public
 */
export function cloneElement(element) {
    const clone = element.cloneNode(true);
    // Remove IDs to avoid duplicates
    clone.removeAttribute('id');
    clone.querySelectorAll('[id]').forEach((el) => el.removeAttribute('id'));
    return clone;
}
/**
 * Get scrollable parents of an element.
 *
 * @param element - Element to check.
 * @returns Array of scrollable parent elements.
 *
 * @public
 */
export function getScrollableParents(element) {
    const parents = [];
    let current = element.parentElement;
    while (current) {
        const style = window.getComputedStyle(current);
        const overflow = style.overflow + style.overflowX + style.overflowY;
        if ((/(auto|scroll)/).test(overflow)) {
            parents.push(current);
        }
        current = current.parentElement;
    }
    return parents;
}
/**
 * Find closest ancestor matching a selector.
 *
 * @param element - Starting element.
 * @param selector - CSS selector.
 * @returns Matching ancestor or null.
 *
 * @public
 */
export function getClosestMatchingAncestor(element, selector) {
    let current = element.parentElement;
    while (current) {
        if (current.matches(selector)) {
            return current;
        }
        current = current.parentElement;
    }
    return null;
}
// #endregion
//# sourceMappingURL=PositionUtils.js.map