"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.POPOVER_COLLISION_AVOIDANCE = exports.MENU_COLLISION_AVOIDANCE = exports.Floating = exports.useFloatingContext = exports.FloatingProvider = void 0;
const react_dom_1 = require("@floating-ui/react-dom");
const react_1 = __importStar(require("react"));
const Modal_context_1 = require("../../../modal/Modal.context");
const utils_external_1 = require("../../../utils-external");
const helpers_1 = require("../../helpers");
const hooks_1 = require("../../hooks");
const Slot_1 = require("../slot/Slot");
const Floating_utils_1 = require("./Floating.utils");
/**
 * Used for menus that prefer top/bottom placements and
 * use height-var to limit their height.
 */
const MENU_COLLISION_AVOIDANCE = {
    fallbackAxisSide: "none",
};
exports.MENU_COLLISION_AVOIDANCE = MENU_COLLISION_AVOIDANCE;
/**
 * Used by regular popovers that usually aren't scrollable and are allowed to
 * freely flip to any axis of placement.
 */
const POPOVER_COLLISION_AVOIDANCE = {
    fallbackAxisSide: "end",
};
exports.POPOVER_COLLISION_AVOIDANCE = POPOVER_COLLISION_AVOIDANCE;
_a = (0, helpers_1.createStrictContext)({
    name: "FloatingContext",
}), exports.FloatingProvider = _a.Provider, exports.useFloatingContext = _a.useContext;
const Floating = ({ children }) => {
    const [anchor, setAnchor] = (0, react_1.useState)(null);
    return (react_1.default.createElement(exports.FloatingProvider, { anchor: anchor, onAnchorChange: setAnchor }, children));
};
exports.Floating = Floating;
/**
 * `FloatingAnchor` provides an anchor for a Floating instance.
 * Allows anchoring to non-DOM nodes like a cursor position when used with `virtualRef`.
 */
const FloatingAnchor = (0, react_1.forwardRef)((_a, forwardedRef) => {
    var { virtualRef, asChild } = _a, rest = __rest(_a, ["virtualRef", "asChild"]);
    const context = (0, exports.useFloatingContext)();
    const ref = (0, react_1.useRef)(null);
    const mergedRef = (0, hooks_1.useMergeRefs)(forwardedRef, ref);
    (0, react_1.useEffect)(() => {
        // Allows anchoring the floating to non-DOM nodes like a cursor position.
        // We replace `anchorRef` with a virtual ref in such cases.
        context.onAnchorChange(virtualRef || ref.current);
    });
    const Comp = asChild ? Slot_1.Slot : "div";
    return virtualRef ? null : react_1.default.createElement(Comp, Object.assign({ ref: mergedRef }, rest));
});
/**
 * Floating Arrow
 */
const OPPOSITE_SIDE = {
    top: "bottom",
    right: "left",
    bottom: "top",
    left: "right",
};
const FloatingArrow = ({ width, height, className }) => {
    const context = useFloatingContentContext();
    const side = OPPOSITE_SIDE[context.placedSide];
    return (react_1.default.createElement("span", { ref: context.onArrowChange, style: {
            position: "absolute",
            left: context.arrowX,
            top: context.arrowY,
            [side]: 0,
            transformOrigin: {
                top: "",
                right: "0 0",
                bottom: "center 0",
                left: "100% 0",
            }[context.placedSide],
            transform: {
                top: "translateY(100%)",
                right: "translateY(50%) rotate(90deg) translateX(-50%)",
                bottom: `rotate(180deg)`,
                left: "translateY(50%) rotate(-90deg) translateX(50%)",
            }[context.placedSide],
            visibility: context.hideArrow ? "hidden" : undefined,
        }, "aria-hidden": true },
        react_1.default.createElement("svg", { className: className, width: width, height: height, viewBox: "0 0 30 10", preserveAspectRatio: "none", style: { display: "block" } },
            react_1.default.createElement("polygon", { points: "0,0 30,0 15,10" }))));
};
const { Provider: FloatingContentProvider, useContext: useFloatingContentContext, } = (0, helpers_1.createStrictContext)({
    name: "FloatingContentContext",
});
const FloatingContent = (0, react_1.forwardRef)((_a, forwardedRef) => {
    var _b, _c, _d, _e, _f, _g;
    var { children, side = "bottom", sideOffset = 0, align = "center", alignOffset = 0, avoidCollisions = true, collisionBoundary = [], collisionPadding: collisionPaddingProp = 0, hideWhenDetached = false, updatePositionStrategy = "optimized", onPlaced, arrow: _arrow, fallbackPlacements, enabled = true, autoUpdateWhileMounted = true, fallbackAxisSideDirection = POPOVER_COLLISION_AVOIDANCE.fallbackAxisSide } = _a, contentProps = __rest(_a, ["children", "side", "sideOffset", "align", "alignOffset", "avoidCollisions", "collisionBoundary", "collisionPadding", "hideWhenDetached", "updatePositionStrategy", "onPlaced", "arrow", "fallbackPlacements", "enabled", "autoUpdateWhileMounted", "fallbackAxisSideDirection"]);
    const context = (0, exports.useFloatingContext)();
    const modalContext = (0, Modal_context_1.useModalContext)(false);
    const arrowDefaults = Object.assign({ padding: 5, width: 0, height: 0 }, _arrow);
    const [arrow, setArrow] = (0, react_1.useState)(null);
    const arrowWidth = arrowDefaults.width;
    const arrowHeight = arrowDefaults.height;
    const desiredPlacement = (side +
        (align !== "center" ? "-" + align : ""));
    /**
     * Create a bias to the preferred side.
     * On iOS, when the mobile software keyboard opens, the input is exactly centered
     * in the viewport, but this can cause it to flip to the top undesirably.
     */
    const bias = 1;
    const biasTop = side === "bottom" ? bias : 0;
    const biasBottom = side === "top" ? bias : 0;
    const biasLeft = side === "right" ? bias : 0;
    const biasRight = side === "left" ? bias : 0;
    const collisionPadding = typeof collisionPaddingProp === "number"
        ? {
            top: collisionPaddingProp + biasTop,
            right: collisionPaddingProp + biasRight,
            bottom: collisionPaddingProp + biasBottom,
            left: collisionPaddingProp + biasLeft,
        }
        : {
            top: (collisionPaddingProp.top || 0) + biasTop,
            right: (collisionPaddingProp.right || 0) + biasRight,
            bottom: (collisionPaddingProp.bottom || 0) + biasBottom,
            left: (collisionPaddingProp.left || 0) + biasLeft,
        };
    const boundary = Array.isArray(collisionBoundary)
        ? collisionBoundary
        : [collisionBoundary];
    const hasExplicitBoundaries = boundary.length > 0;
    /* https://floating-ui.com/docs/detectOverflow#boundary */
    const detectOverflowOptions = {
        padding: collisionPadding,
        boundary: boundary.filter(isNotNull),
        // with `strategy: 'fixed'`, this is the only way to get it to respect boundaries
        altBoundary: hasExplicitBoundaries,
        fallbackAxisSideDirection,
        fallbackPlacements,
    };
    const { refs, floatingStyles, placement, isPositioned, middlewareData, elements: floatingElements, update, } = (0, react_dom_1.useFloating)({
        open: enabled,
        // default to `fixed` strategy so users don't have to pick and we also avoid focus scroll issues
        strategy: "fixed",
        placement: desiredPlacement,
        whileElementsMounted: autoUpdateWhileMounted
            ? (...args) => {
                const cleanup = (0, react_dom_1.autoUpdate)(...args, {
                    animationFrame: updatePositionStrategy === "always",
                });
                return cleanup;
            }
            : undefined,
        elements: {
            reference: context.anchor,
        },
        middleware: [
            (0, react_dom_1.offset)({
                mainAxis: sideOffset + arrowHeight,
                alignmentAxis: alignOffset,
            }),
            avoidCollisions &&
                (0, react_dom_1.shift)({
                    mainAxis: true,
                    crossAxis: false,
                    limiter: (0, react_dom_1.limitShift)(),
                }),
            avoidCollisions &&
                (0, react_dom_1.flip)(Object.assign(Object.assign({}, detectOverflowOptions), { padding: collisionPadding })),
            (0, react_dom_1.size)(Object.assign(Object.assign({}, detectOverflowOptions), { apply: ({ elements, rects, availableWidth, availableHeight }) => {
                    const { width: anchorWidth, height: anchorHeight } = rects.reference;
                    const contentStyle = elements.floating.style;
                    /**
                     * Allows styling and animations based on the available space.
                     */
                    contentStyle.setProperty("--__axc-floating-available-width", `${availableWidth}px`);
                    contentStyle.setProperty("--__axc-floating-available-height", `${availableHeight}px`);
                    contentStyle.setProperty("--__axc-floating-anchor-width", `${anchorWidth}px`);
                    contentStyle.setProperty("--__axc-floating-anchor-height", `${anchorHeight}px`);
                } })),
            arrow &&
                (0, react_dom_1.arrow)({ element: arrow, padding: arrowDefaults.padding }),
            (0, Floating_utils_1.transformOrigin)({ arrowWidth, arrowHeight }),
            hideWhenDetached &&
                (0, react_dom_1.hide)(Object.assign({ strategy: "referenceHidden" }, detectOverflowOptions)),
        ],
    });
    (0, react_1.useEffect)(() => {
        if (autoUpdateWhileMounted || !enabled) {
            return;
        }
        if (floatingElements.reference && floatingElements.floating) {
            const cleanup = (0, react_dom_1.autoUpdate)(floatingElements.reference, floatingElements.floating, update);
            return () => {
                cleanup();
            };
        }
    }, [autoUpdateWhileMounted, enabled, floatingElements, update]);
    (0, hooks_1.useOpenChangeAnimationComplete)({
        enabled: !!(modalContext === null || modalContext === void 0 ? void 0 : modalContext.modalRef),
        open: enabled,
        ref: modalContext === null || modalContext === void 0 ? void 0 : modalContext.modalRef,
        onComplete: update,
    });
    const [placedSide, placedAlign] = (0, Floating_utils_1.getSideAndAlignFromPlacement)(placement);
    const handlePlaced = (0, hooks_1.useEventCallback)(onPlaced);
    (0, utils_external_1.useClientLayoutEffect)(() => {
        isPositioned && (handlePlaced === null || handlePlaced === void 0 ? void 0 : handlePlaced());
    }, [isPositioned, handlePlaced]);
    const arrowX = (_b = middlewareData.arrow) === null || _b === void 0 ? void 0 : _b.x;
    const arrowY = (_c = middlewareData.arrow) === null || _c === void 0 ? void 0 : _c.y;
    const cannotCenterArrow = ((_d = middlewareData.arrow) === null || _d === void 0 ? void 0 : _d.centerOffset) !== 0;
    return (react_1.default.createElement("div", { ref: refs.setFloating, "data-aksel-floating-content-wrapper": "", style: Object.assign(Object.assign({}, floatingStyles), { transform: isPositioned
                ? floatingStyles.transform
                : "translate(0, -200%)", minWidth: "max-content", zIndex: "9999999", ["--__axc-floating-transform-origin"]: [
                (_e = middlewareData.transformOrigin) === null || _e === void 0 ? void 0 : _e.x,
                (_f = middlewareData.transformOrigin) === null || _f === void 0 ? void 0 : _f.y,
            ].join(" ") }), 
        // Floating UI uses the `dir` attribute on the reference/floating node for logical alignment.
        // This attribute is necessary for both portalled and inline calculations.
        dir: "ltr" },
        react_1.default.createElement(FloatingContentProvider, { placedSide: placedSide, onArrowChange: setArrow, arrowX: arrowX, arrowY: arrowY, hideArrow: cannotCenterArrow },
            react_1.default.createElement("div", Object.assign({ ref: forwardedRef, "data-side": placedSide, "data-align": placedAlign }, contentProps, { style: Object.assign(Object.assign({}, contentProps.style), { 
                    // if the FloatingContent hasn't been placed yet (not all measurements done)
                    // we prevent animations so that users's animation don't kick in too early referring wrong sides
                    animation: !isPositioned ? "none" : undefined, 
                    // hide the content if using the hide middleware and should be hidden
                    opacity: ((_g = middlewareData.hide) === null || _g === void 0 ? void 0 : _g.referenceHidden) ? 0 : undefined }) }),
                children,
                (_arrow === null || _arrow === void 0 ? void 0 : _arrow.height) && (_arrow === null || _arrow === void 0 ? void 0 : _arrow.width) && (react_1.default.createElement(FloatingArrow, { width: _arrow.width, height: _arrow.height, className: _arrow.className }))))));
});
/**
 * .filter(x => x !== null) does not narrow the type of the array enough.
 */
function isNotNull(value) {
    return value !== null;
}
Floating.Anchor = FloatingAnchor;
Floating.Content = FloatingContent;
//# sourceMappingURL=Floating.js.map