/**
 * Copyright IBM Corp. 2026
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { arrow, autoUpdate, computePosition, flip, hide, offset, size } from "@floating-ui/dom";
//#region src/globals/controllers/floating-controller.ts
/**
* Controller for positioning the menu using Floating UI.
*/
var FloatingController = class {
	/**
	* register with host component
	* @param host host component
	*/
	constructor(host) {
		this.updatePlacement = () => {
			this.computePlacement();
		};
		this.host = host;
		host.addController(this);
	}
	async setPlacement(options = this.options) {
		this.options = options;
		const { trigger, target } = options;
		this.cleanup = autoUpdate(trigger, target, this.updatePlacement);
	}
	async computePlacement() {
		const { arrowElement, alignment, caret, trigger, target, styleElement, matchWidth, open, alignmentAxisOffset, autoAlignBoundary, isTabTip } = this.options;
		const isListBox = target?.role === "listbox";
		const isMenu = target?.localName === "cds-custom-menu";
		const element = styleElement ?? target;
		if (!element) return;
		let shimmedAlign;
		switch (alignment) {
			case "top-left":
				shimmedAlign = "top-start";
				break;
			case "top-right":
				shimmedAlign = "top-end";
				break;
			case "bottom-left":
				shimmedAlign = "bottom-start";
				break;
			case "bottom-right":
				shimmedAlign = "bottom-end";
				break;
			case "left-bottom":
				shimmedAlign = "left-end";
				break;
			case "left-top":
				shimmedAlign = "left-start";
				break;
			case "right-bottom":
				shimmedAlign = "right-end";
				break;
			case "right-top":
				shimmedAlign = "right-start";
				break;
			default:
				shimmedAlign = alignment;
				break;
		}
		const cs = getComputedStyle(element);
		const toPx = (val) => {
			const raw = parseFloat(val);
			return val.trim().endsWith("rem") ? raw * 16 : raw;
		};
		const offsetPx = !isTabTip ? toPx(cs.getPropertyValue("--cds-popover-offset").trim()) ?? 10 : 0;
		const middleware = [
			offset(!isTabTip ? {
				alignmentAxis: alignmentAxisOffset,
				mainAxis: caret ? offsetPx : 4
			} : 0),
			flip({
				fallbackPlacements: isTabTip ? shimmedAlign.includes("bottom") ? [
					"bottom-start",
					"bottom-end",
					"top-start",
					"top-end"
				] : [
					"top-start",
					"top-end",
					"bottom-start",
					"bottom-end"
				] : isListBox || isMenu ? ["top", "bottom"] : shimmedAlign.includes("bottom") ? [
					"bottom",
					"bottom-start",
					"bottom-end",
					"right",
					"right-start",
					"right-end",
					"left",
					"left-start",
					"left-end",
					"top",
					"top-start",
					"top-end"
				] : [
					"top",
					"top-start",
					"top-end",
					"left",
					"left-start",
					"left-end",
					"right",
					"right-start",
					"right-end",
					"bottom",
					"bottom-start",
					"bottom-end"
				],
				fallbackStrategy: "initialPlacement",
				fallbackAxisSideDirection: "start",
				boundary: autoAlignBoundary
			}),
			...matchWidth && (shimmedAlign === "bottom" || shimmedAlign === "top") ? [size({ apply({ rects, elements }) {
				elements.floating.style.width = `${rects.reference.width}px`;
			} })] : [size({ apply({ elements }) {
				elements.floating.style.removeProperty("width");
			} })],
			...caret && arrowElement ? [arrow({
				element: arrowElement,
				padding: 15
			})] : [],
			...[hide()]
		];
		if (open) {
			const { x, y, placement, middlewareData, strategy } = await computePosition(trigger, element, {
				strategy: "fixed",
				middleware,
				placement: shimmedAlign
			});
			element.setAttribute("align", placement);
			element.style.left = `${x}px`;
			element.style.top = `${y}px`;
			element.style.position = `${strategy}`;
			element.style.visibility = middlewareData.hide?.referenceHidden ? "hidden" : "visible";
			if (arrowElement) {
				const { x: arrowX, y: arrowY } = middlewareData.arrow;
				const staticSide = {
					top: "bottom",
					right: "left",
					bottom: "top",
					left: "right"
				}[placement.split("-")[0]];
				arrowElement.style.left = arrowX != null ? `${arrowX}px` : "";
				arrowElement.style.top = arrowY != null ? `${arrowY}px` : "";
				arrowElement.style.right = "";
				arrowElement.style.bottom = "";
				arrowElement.style[staticSide] = `${-arrowElement.offsetWidth / 2}px`;
			}
			if (this.host.tagName === "CDS-AI-LABEL" || this.host.tagName === "CDS-SLUG") this.host?.setAttribute("alignment", placement);
		}
	}
	hostUpdated() {
		if (!this.host.hasAttribute("open")) {
			this.cleanup?.();
			this.cleanup = void 0;
		}
	}
	hostDisconnected() {
		this.cleanup?.();
		this.cleanup = void 0;
	}
};
//#endregion
export { FloatingController as default };

//# sourceMappingURL=floating-controller.js.map