/**
 * 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 { selectorTabbable } from "../../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 iconLoader from "../../globals/internal/icon-loader.js";
import HostListener from "../../globals/decorators/host-listener.js";
import HostListenerMixin from "../../globals/mixins/host-listener.js";
import "./defs.js";
import inline_notification_default from "./inline-notification.js";
import actionable_notification_default$1 from "./actionable-notification.scss.js";
import { html } from "lit";
import { property, query } from "lit/decorators.js";
import ErrorFilled20 from "@carbon/icons/es/error--filled/20.js";
import WarningAltFilled20 from "@carbon/icons/es/warning--alt--filled/20.js";
import CheckmarkFilled20 from "@carbon/icons/es/checkmark--filled/20.js";
import InformationFilled20 from "@carbon/icons/es/information--filled/20.js";
import InformationSquareFilled20 from "@carbon/icons/es/information--square--filled/20.js";
import WarningFilled20 from "@carbon/icons/es/warning--filled/20.js";
//#region src/components/notification/actionable-notification.ts
/**
* Copyright IBM Corp. 2019, 2025
*
* 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 _CDSActionableNotification;
/**
* The default icons, keyed by notification kind.
*/
const iconsForKinds = {
	["success"]: CheckmarkFilled20,
	["info"]: InformationFilled20,
	["info-square"]: InformationSquareFilled20,
	["warning"]: WarningFilled20,
	["warning-alt"]: WarningAltFilled20,
	["error"]: ErrorFilled20
};
const PRECEDING = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS;
const FOLLOWING = Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;
/**
* Tries to focus on the given elements and bails out if one of them is successful.
*
* @param elems The elements.
* @param reverse `true` to go through the list in reverse order.
* @returns `true` if one of the attempts is successful, `false` otherwise.
*/
function tryFocusElems(elems, reverse = false) {
	if (!reverse) for (let i = 0; i < elems.length; ++i) {
		const elem = elems[i];
		elem.focus();
		const active = elem.ownerDocument.activeElement;
		if (active === elem || active?.contains(elem) || active?.shadowRoot?.contains(elem)) return true;
	}
	else for (let i = elems.length - 1; i >= 0; --i) {
		const elem = elems[i];
		elem.focus();
		const active = elem.ownerDocument.activeElement;
		if (active === elem || active?.contains(elem) || active?.shadowRoot?.contains(elem)) return true;
	}
	return false;
}
/**
* Actionable notification.
*
* @element cds-custom-actionable-notification
* @slot subtitle - The subtitle.
* @slot title - The title.
* @fires cds-custom-notification-beingclosed
*   The custom event fired before this notification is being closed upon a user gesture.
*   Cancellation of this event stops the user-initiated action of closing this notification.
* @fires cds-custom-notification-closed - The custom event fired after this notification is closed upon a user gesture.
*/
let CDSActionableNotification = class CDSActionableNotification extends HostListenerMixin(inline_notification_default) {
	static {
		_CDSActionableNotification = this;
	}
	constructor(..._args) {
		super(..._args);
		this._type = "actionable";
		this.inline = false;
		this.actionButtonLabel = "";
		this.closeOnEscape = true;
		this.hasFocus = true;
		this._handleKeyDown = async (event) => {
			const { key } = event;
			if (this.closeOnEscape && key === "Escape") this.open = false;
		};
		this._handleBlur = async ({ target, relatedTarget }) => {
			const { open, _startSentinelNode: startSentinelNode, _endSentinelNode: endSentinelNode } = this;
			const oldContains = target !== this && (this.contains(target) || this.shadowRoot?.contains(target) && target !== startSentinelNode && target !== endSentinelNode);
			const currentContains = relatedTarget !== this && (this.contains(relatedTarget) || this.shadowRoot?.contains(relatedTarget) && relatedTarget !== startSentinelNode && relatedTarget !== endSentinelNode);
			const { selectorTabbable: selectorTabbableForActionableNotification } = this.constructor;
			if (open && this.getAttribute("role") === "alertdialog" && relatedTarget && !(relatedTarget instanceof _CDSActionableNotification) && oldContains && !currentContains) {
				const comparisonResult = target.compareDocumentPosition(relatedTarget);
				const shadowElems = this.shadowRoot.querySelectorAll(selectorTabbableForActionableNotification);
				const lightElems = this.querySelectorAll(selectorTabbableForActionableNotification);
				if (relatedTarget === startSentinelNode || comparisonResult & PRECEDING) {
					await this.constructor._delay();
					if (!tryFocusElems(shadowElems, true) && !tryFocusElems(lightElems, true) && relatedTarget !== this) this.focus();
				} else if (relatedTarget === endSentinelNode || comparisonResult & FOLLOWING) {
					await this.constructor._delay();
					if (!tryFocusElems(lightElems) && !tryFocusElems(shadowElems)) this.focus();
				}
			}
		};
		this.caption = "";
	}
	connectedCallback() {
		if (!this.hasAttribute("role")) this.setAttribute("role", "alertdialog");
		super.connectedCallback();
	}
	_renderIcon() {
		const { kind, inline } = this;
		const IconComponent = iconsForKinds[kind];
		return !IconComponent ? void 0 : iconLoader(IconComponent, { class: `cds-custom--${inline ? "inline" : "toast"}-notification__icon` });
	}
	_renderText() {
		const { caption, subtitle, title, _type: type } = this;
		return html`
      <div class="${"cds-custom"}--${type}-notification__text-wrapper">
        <div class="${"cds-custom"}--${type}-notification__content">
          <div class="${"cds-custom"}--${type}-notification__title">
            ${title}<slot name="title"></slot>
          </div>
          <div class="${"cds-custom"}--${type}-notification__subtitle">
            ${subtitle}<slot name="subtitle"></slot>
          </div>
          ${caption && html`<div class="${"cds-custom"}--${type}-notification__caption">
            ${caption}<slot name="caption"></slot>
          </div>`}
          <slot></slot>
        </div>
      </div>
    `;
	}
	updated(changedProperties) {
		super.updated(changedProperties);
		const button = this.querySelector(this.constructor.selectorActionButton);
		if (changedProperties.has("inline")) button?.setAttribute("kind", this.inline ? "ghost" : "tertiary");
		if (changedProperties.has("lowContrast")) if (this.lowContrast) button?.setAttribute("low-contrast", "true");
		else button?.removeAttribute("low-contrast");
		if (changedProperties.has("hideCloseButton")) if (this.hideCloseButton) button?.setAttribute("hide-close-button", "true");
		else button?.removeAttribute("hide-close-button");
		if (changedProperties.has("hasFocus")) {
			if (this.hasFocus) if (button) button.updateComplete.then(() => {
				button.focus();
			});
			else this.focus();
		}
	}
	render() {
		const { _type: type } = this;
		return html`
      <a
        id="start-sentinel"
        class="${"cds-custom"}--visually-hidden"
        href="javascript:void 0"
        role="navigation"></a>
      <div class="${"cds-custom"}--${type}-notification__details">
        ${this._renderIcon()} ${this._renderText()}
      </div>
      <slot name="action"></slot>
      ${this._renderButton()}
      <a
        id="end-sentinel"
        class="${"cds-custom"}--visually-hidden"
        href="javascript:void 0"
        role="navigation"></a>
    `;
	}
	/**
	* @param ms The number of milliseconds.
	* @returns A promise that is resolves after the given milliseconds.
	*/
	static _delay(ms = 0) {
		return new Promise((resolve) => {
			setTimeout(resolve, ms);
		});
	}
	/**
	* A selector selecting tabbable nodes.
	*/
	static get selectorTabbable() {
		return selectorTabbable;
	}
	/**
	* A selector that will return the action button element
	*/
	static get selectorActionButton() {
		return `cds-custom-actionable-notification-button`;
	}
	static {
		this.styles = actionable_notification_default$1;
	}
};
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSActionableNotification.prototype, "inline", void 0);
__decorate([property({
	type: String,
	reflect: true,
	attribute: "action-button-label"
})], CDSActionableNotification.prototype, "actionButtonLabel", void 0);
__decorate([property({
	type: Boolean,
	reflect: true,
	attribute: "close-on-escape"
})], CDSActionableNotification.prototype, "closeOnEscape", void 0);
__decorate([property({
	type: Boolean,
	reflect: true,
	attribute: "has-focus"
})], CDSActionableNotification.prototype, "hasFocus", void 0);
__decorate([query("#start-sentinel")], CDSActionableNotification.prototype, "_startSentinelNode", void 0);
__decorate([query("#end-sentinel")], CDSActionableNotification.prototype, "_endSentinelNode", void 0);
__decorate([HostListener("keydown")], CDSActionableNotification.prototype, "_handleKeyDown", void 0);
__decorate([HostListener("shadowRoot:focusout")], CDSActionableNotification.prototype, "_handleBlur", void 0);
__decorate([property()], CDSActionableNotification.prototype, "caption", void 0);
CDSActionableNotification = _CDSActionableNotification = __decorate([carbonElement(`cds-custom-actionable-notification`)], CDSActionableNotification);
var actionable_notification_default = CDSActionableNotification;
//#endregion
export { actionable_notification_default as default, iconsForKinds };

//# sourceMappingURL=actionable-notification.js.map