import { getScrollbarWidth } from "../scroll/getScrollbarWidth.js";
import { BELOW_CENTER_ANCHOR } from "./constants.js";
import { createHorizontalPosition } from "./createHorizontalPosition.js";
import { createVerticalPosition } from "./createVerticalPosition.js";
import { findSizingContainer, getElementRect, getTransformOrigin } from "./utils.js";
/**
 * This is used when there is no `container` element so that some styles can
 * still be created. The main use-case for this is context menus and when the
 * `initialX` and `initialY` options have been provided.
 *
 * @internal
 * @since 5.0.0
 */ const FALLBACK_DOM_RECT = {
    x: 0,
    y: 0,
    height: 0,
    width: 0,
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    toJSON () {
    // do nothing
    }
};
/**
 * One of the most complicated functions in this project that will attempt to
 * position an element relative to another container element while still being
 * visible within the viewport. Below is the logical flow for attempting to fix
 * the element to the container:
 *
 * No Container: If there is no container element, return the provided x and y
 * positions and no styles since there's nothing we can use to calculate the
 * position.
 *
 * No Element: If the container was provided but the element to position does
 * not exist, return an style object containing the `left` and `top` values for
 * the container and apply as many of the positioning options as possible so
 * that the styles are "as close as possible" before the fixed element is added
 * to the DOM. This will also return the provided x and y positions since
 * nothing could be swapped around yet.
 *
 * Container and Element: If both the container and fixed element were provided,
 * apply all the positioning options to the `left` and `top` values of the
 * container based on the sizes of both elements.
 *
 * Now that the `left` and `top` values were applied, check to see if the
 * element is fully visible within the viewport with the provided positioning
 * options. If it is fully visible, do nothing else. If it isn't... follow the
 * next flow:
 *
 * First, check the horizontal sizes and make sure that the element is still
 * within the viewport with the provided view width margin. If it isn't, first
 * try to swap only to a `right` style instead of left to see if that fixes it,
 * otherwise keep both the `left` and `right` styles.
 */ export function getFixedPosition(options) {
    const { element, anchor = BELOW_CENTER_ANCHOR, initialX, vwMargin = 16, vhMargin = 16, xMargin = 0, yMargin = 0, width: widthType = "auto", preventOverlap = false, transformOrigin = false, disableSwapping = false, disableVHBounds = false } = options;
    let { initialY } = options;
    const container = findSizingContainer(options.container);
    if (process.env.NODE_ENV !== "production") {
        if (preventOverlap && anchor.y !== "above" && anchor.y !== "below") {
            throw new Error('Unable to prevent overlap when the vertical anchor is not `"above"` or `"below"`');
        }
    }
    if (!element) {
        return {
            actualX: anchor.x,
            actualY: anchor.y,
            style: {
                left: initialX,
                top: initialY,
                position: disableVHBounds ? "absolute" : "fixed",
                transformOrigin: transformOrigin ? getTransformOrigin({
                    x: anchor.x,
                    y: anchor.y
                }) : undefined
            }
        };
    }
    const containerRect = container?.getBoundingClientRect() ?? FALLBACK_DOM_RECT;
    const vh = window.innerHeight;
    const vw = window.innerWidth;
    const { minWidth: elMinWidth } = element.style;
    // Note: This makes it "min-content" or "min-container-width"
    if (widthType === "min") {
        element.style.overflow = "visible";
        element.style.minWidth = "";
    }
    const elementRect = getElementRect(element);
    const { height } = elementRect;
    let elWidth = elementRect.width;
    if (widthType === "min") {
        elWidth += getScrollbarWidth();
        element.style.overflow = "";
        element.style.minWidth = elMinWidth;
    }
    if (disableVHBounds) {
        const dialog = element.closest("[role='dialog']");
        if (!dialog) {
            initialY = (initialY ?? 0) + window.scrollY;
        }
    }
    const { left, right, width, minWidth, actualX } = createHorizontalPosition({
        x: anchor.x,
        vw,
        vwMargin,
        xMargin,
        width: widthType,
        elWidth,
        initialX,
        containerRect,
        disableSwapping
    });
    const { top, bottom, actualY, transformOriginY } = createVerticalPosition({
        y: anchor.y,
        vh,
        vhMargin,
        yMargin,
        initialY,
        elHeight: height,
        containerRect,
        disableSwapping,
        preventOverlap,
        disableVHBounds
    });
    return {
        actualX,
        actualY,
        style: {
            left,
            top,
            right,
            bottom,
            width,
            minWidth,
            position: disableVHBounds ? "absolute" : "fixed",
            transformOrigin: transformOrigin ? getTransformOrigin({
                x: actualX,
                y: actualY,
                transformOriginY
            }) : undefined
        }
    };
}

//# sourceMappingURL=getFixedPosition.js.map