/**
 * 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 "../../globals/settings.js";
import { carbonElement } from "../../globals/decorators/carbon-element.js";
import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.126.0/helpers/decorate.js";
import HostListener from "../../globals/decorators/host-listener.js";
import HostListenerMixin from "../../globals/mixins/host-listener.js";
import "./defs.js";
import FloatingController from "../../globals/controllers/floating-controller.js";
import popover_default$1 from "./popover.scss.js";
import { deepShadowContains } from "../../globals/internal/deep-shadow-contains.js";
import { LitElement, html } from "lit";
import { property, query } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
//#region src/components/popover/popover.ts
/**
* Copyright IBM Corp. 2019, 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.
*/
var _CDSPopover;
/**
* Popover.
*
* @element cds-custom-popover
* @fires cds-custom-popover-beingclosed before the popover closes via focusout/outsideclick.
* @fires cds-custom-popover-closed when the popover closes via focusout/outsideclick
*/
let CDSPopover = class CDSPopover extends HostListenerMixin(LitElement) {
	static {
		_CDSPopover = this;
	}
	/**
	* Handles `slotchange` event.
	*/
	_handleSlotChange({ target }) {
		if (this.tabTip) target.assignedNodes().filter((node) => node.nodeType === Node.ELEMENT_NODE && node.tagName === "BUTTON")[0]?.classList.add(`cds-custom--popover--tab-tip__button`);
		this.requestUpdate();
	}
	_handleKeyDown(event) {
		if (!this.open) return;
		if (event.key === "Tab") this._tabKeyPressed = true;
		else this._tabKeyPressed = false;
	}
	_handleFocusOut(event) {
		if (!this._tabKeyPressed || !this.open) return;
		if (this.contains(event.relatedTarget) || deepShadowContains(this, event.relatedTarget)) {
			this._tabKeyPressed = false;
			return;
		}
		this._tabKeyPressed = false;
		if (this.dispatchEvent(new CustomEvent(this.constructor.eventBeforeClose, {
			bubbles: true,
			cancelable: true,
			composed: true,
			detail: { triggeredBy: event.target }
		}))) {
			this.open = false;
			this.dispatchEvent(new CustomEvent(this.constructor.eventOnClose, {
				bubbles: true,
				composed: true
			}));
		}
	}
	_handleOutsideClick(event) {
		const path = event.composedPath();
		if (path.includes(this._triggerSlotNode.assignedElements()[0])) return;
		const popoverContent = this.querySelector(this.constructor.selectorPopoverContent)?.shadowRoot?.querySelector(this.constructor.selectorPopoverContentClass);
		if (path.includes(popoverContent)) return;
		const target = event.target;
		const composedTarget = event.composedPath?.()[0];
		if (this.open && target && !this.contains(target) && !this.contains(composedTarget)) {
			if (this.dispatchEvent(new CustomEvent(this.constructor.eventBeforeClose, {
				bubbles: true,
				cancelable: true,
				composed: true,
				detail: { triggeredBy: event.target }
			}))) {
				this.open = false;
				this.dispatchEvent(new CustomEvent(this.constructor.eventOnClose, {
					bubbles: true,
					composed: true
				}));
			}
		}
	}
	constructor() {
		super();
		this.popoverController = new FloatingController(this);
		this._tabKeyPressed = false;
		this.align = "";
		this.autoalign = false;
		this.caret = true;
		this.dropShadow = true;
		this.border = false;
		this.highContrast = false;
		this.open = false;
		this.tabTip = false;
		this.backgroundToken = "layer";
		this._handleOutsideClick = this._handleOutsideClick.bind(this);
	}
	connectedCallback() {
		super.connectedCallback();
		document.addEventListener("click", this._handleOutsideClick);
	}
	disconnectedCallback() {
		document.removeEventListener("click", this._handleOutsideClick);
	}
	/**
	* This function resolves the string passed in for `autoAlignBoundary` to either:
	* "clippingAncestors"
	* An element (found via #id)
	* An array of elements (found via #id1, #id2, #id3, separated by ",")
	* A rect, input format should be 'rect(x,y,width,height)'
	*/
	_resolveAutoAlignBoundary() {
		const raw = (this.autoAlignBoundary ?? "").trim();
		if (!raw) return "clippingAncestors";
		if (raw === "clippingAncestors") return "clippingAncestors";
		const rectMatch = /^rect\(\s*([-\d.]+)\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)$/i.exec(raw);
		if (rectMatch) {
			const [, x, y, w, h] = rectMatch;
			return {
				x: +x,
				y: +y,
				width: +w,
				height: +h
			};
		}
		const ids = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 1 && s.startsWith("#")).map((s) => s.slice(1).trim()).filter(Boolean);
		if (ids.length > 0) {
			const elements = [];
			const inputted_ids = /* @__PURE__ */ new Set();
			for (const id of ids) {
				if (inputted_ids.has(id)) continue;
				inputted_ids.add(id);
				const el = document.getElementById(id);
				if (el) elements.push(el);
			}
			return elements.length === 1 ? elements[0] : elements;
		}
		return "clippingAncestors";
	}
	updated(changedProperties) {
		const { selectorPopoverContent } = this.constructor;
		[
			"open",
			"align",
			"autoalign",
			"caret",
			"dropShadow",
			"border",
			"tabTip",
			"highContrast",
			"backgroundToken"
		].forEach((name) => {
			if (changedProperties.has(name)) {
				const { [name]: value } = this;
				if (this.querySelector(selectorPopoverContent)) this.querySelector(selectorPopoverContent)[name] = value;
			}
		});
		if (this.autoalign && this.open) {
			const button = this._triggerSlotNode.assignedElements()[0];
			const content = this._contentSlotNode.assignedElements()[0];
			const tooltip = content?.shadowRoot?.querySelector(_CDSPopover.selectorPopoverContentClass);
			const arrowElement = content?.shadowRoot?.querySelector(_CDSPopover.selectorPopoverCaret);
			if (button && tooltip) this.popoverController?.setPlacement({
				trigger: button,
				target: tooltip,
				arrowElement: this.caret && arrowElement ? arrowElement : void 0,
				caret: this.caret,
				flipArguments: { fallbackAxisSideDirection: "start" },
				alignment: this.align,
				open: this.open,
				alignmentAxisOffset: this.alignmentAxisOffset,
				autoAlignBoundary: this._resolveAutoAlignBoundary(),
				isTabTip: this.tabTip
			});
		}
	}
	render() {
		const { dropShadow, border, highContrast, open, tabTip, _handleSlotChange: handleSlotChange } = this;
		if (tabTip) this.caret = !tabTip;
		if (!this.autoalign) this.align = this.align ? this.align : tabTip ? "bottom-start" : "bottom";
		if (tabTip) {
			if (![
				"bottom-start",
				"bottom-end",
				"bottom-left",
				"bottom-right"
			].includes(this.align)) this.align = "bottom-start";
		}
		return html`
      <span class="${classMap({
			[`cds-custom--popover-container`]: true,
			[`cds-custom--popover--caret`]: this.caret,
			[`cds-custom--popover--drop-shadow`]: dropShadow,
			[`cds-custom--popover--border`]: border,
			[`cds-custom--popover--high-contrast`]: highContrast,
			[`cds-custom--popover--open`]: open,
			[`cds-custom--popover--${this.align}`]: true,
			[`cds-custom--popover--tab-tip`]: tabTip,
			[`cds-custom--popover--background-token__background`]: this.backgroundToken === "background" && !highContrast
		})}" part="popover-container">
        <slot @slotchange="${handleSlotChange}"></slot>
        <slot name="content"></slot>
      </span>
    `;
	}
	/**
	* A selector that will return popover content element within
	* CDSPopoverContent's shadowRoot.
	*/
	static get selectorPopoverContentClass() {
		return `.cds-custom--popover-content`;
	}
	/**
	* A selector that will return popover caret element within
	* CDSPopoverContent's shadowRoot.
	*/
	static get selectorPopoverCaret() {
		return `.cds-custom--popover-caret`;
	}
	/**
	* A selector that will return the CDSPopoverContent.
	*/
	static get selectorPopoverContent() {
		return `cds-custom-popover-content`;
	}
	/**
	* The name of the custom event fired before the popover closes via focusout/outsideclick.
	* This event is cancellable.
	*/
	static get eventBeforeClose() {
		return `cds-custom-popover-beingclosed`;
	}
	/**
	* The name of the custom event fired when the popover closes via focusout/outsideclick
	*/
	static get eventOnClose() {
		return `cds-custom-popover-closed`;
	}
	static {
		this.styles = popover_default$1;
	}
};
__decorate([query("slot")], CDSPopover.prototype, "_triggerSlotNode", void 0);
__decorate([query("slot[name=\"content\"]")], CDSPopover.prototype, "_contentSlotNode", void 0);
__decorate([property({
	reflect: true,
	type: String
})], CDSPopover.prototype, "align", void 0);
__decorate([property({
	type: Number,
	reflect: true,
	attribute: "alignment-axis-offset"
})], CDSPopover.prototype, "alignmentAxisOffset", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "autoalign", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "caret", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "dropShadow", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "border", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "highContrast", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "open", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSPopover.prototype, "tabTip", void 0);
__decorate([property({
	reflect: true,
	type: String
})], CDSPopover.prototype, "backgroundToken", void 0);
__decorate([property({
	type: String,
	reflect: true,
	attribute: "autoalign-boundary"
})], CDSPopover.prototype, "autoAlignBoundary", void 0);
__decorate([HostListener("keydown")], CDSPopover.prototype, "_handleKeyDown", null);
__decorate([HostListener("focusout")], CDSPopover.prototype, "_handleFocusOut", null);
CDSPopover = _CDSPopover = __decorate([carbonElement(`cds-custom-popover`)], CDSPopover);
var popover_default = CDSPopover;
//#endregion
export { popover_default as default };

//# sourceMappingURL=popover.js.map