/**
 * 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 HostListener from "../../globals/decorators/host-listener.js";
import HostListenerMixin from "../../globals/mixins/host-listener.js";
import "../button/button-set-base.js";
import "../button/index.js";
import "../layer/index.js";
import "../modal/index.js";
import { TEARSHEET_INFLUENCER_PLACEMENT, TEARSHEET_INFLUENCER_WIDTH, TEARSHEET_WIDTH } from "./defs.js";
import { LitElement, html } from "lit";
import { property, query, queryAssignedElements, state } from "lit/decorators.js";
//#region src/components/tearsheet/tearsheet.ts
/**
* Copyright IBM Corp. 2023, 2024
*
* 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 _CDSTearsheet;
const maxStackDepth = 3;
const PRECEDING = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS;
const FOLLOWING = Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;
const blockClass = `cds-custom--tearsheet`;
const blockClassModalHeader = `cds-custom--modal-header`;
const blockClassActionSet = `cds-custom--action-set`;
/**
* 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) {
	if (!reverse) for (let i = 0; i < elems.length; ++i) {
		const elem = elems[i];
		elem.focus();
		if (elem.ownerDocument.activeElement === elem) return true;
	}
	else for (let i = elems.length - 1; i >= 0; --i) {
		const elem = elems[i];
		elem.focus();
		if (elem.ownerDocument.activeElement === elem) return true;
	}
	return false;
}
/**
* Tearsheet.
*
* @deprecated Use Carbon for IBM Products `tearsheet` component.
*   This component has been deprecated in `@carbon/web-components` and will instead be maintained
*   in the Carbon for IBM Products library:
*   https://github.com/carbon-design-system/ibm-products/tree/main/packages/ibm-products-web-components
* @element cds-custom-tearsheet
* @csspart dialog The dialog.
* @fires cds-custom-tearsheet-beingclosed
*   The custom event fired before this tearsheet is being closed upon a user gesture.
*   Cancellation of this event stops the user-initiated action of closing this tearsheet.
* @fires cds-custom-tearsheet-closed - The custom event fired after this tearsheet is closed upon a user gesture.
*/
let CDSTearsheet = class CDSTearsheet extends HostListenerMixin(LitElement) {
	static {
		_CDSTearsheet = this;
	}
	constructor(..._args) {
		super(..._args);
		this._launcher = null;
		this._actionsCount = 0;
		this._hasHeaderActions = false;
		this._hasLabel = false;
		this._hasSlug = false;
		this._hasTitle = false;
		this._hasDescription = false;
		this._hasInfluencerLeft = false;
		this._hasInfluencerRight = false;
		this._isOpen = false;
		this._hasHeaderNavigation = false;
		this._handleClick = (event) => {
			if (event.composedPath().indexOf(this.shadowRoot) < 0 && !this.preventCloseOnClickOutside) this._handleUserInitiatedClose(event.target);
		};
		this._handleBlur = async ({ target, relatedTarget }) => {
			if (!this._topOfStack()) return;
			const { open, _startSentinelNode: startSentinelNode, _endSentinelNode: endSentinelNode } = this;
			const oldContains = target !== this && this.contains(target);
			const currentContains = relatedTarget !== this && (this.contains(relatedTarget) || this.shadowRoot?.contains(relatedTarget) && relatedTarget !== startSentinelNode && relatedTarget !== endSentinelNode);
			const { selectorTabbable: selectorTabbableForTearsheet } = this.constructor;
			if (open && relatedTarget && oldContains && !currentContains) {
				const comparisonResult = target.compareDocumentPosition(relatedTarget);
				if (relatedTarget === startSentinelNode || comparisonResult & PRECEDING) {
					await this.constructor._delay();
					if (!tryFocusElems(this.querySelectorAll(selectorTabbableForTearsheet), true) && relatedTarget !== this) this.focus();
				} else if (relatedTarget === endSentinelNode || comparisonResult & FOLLOWING) {
					await this.constructor._delay();
					if (!tryFocusElems(this.querySelectorAll(selectorTabbableForTearsheet), true)) this.focus();
				}
			}
		};
		this._handleKeydown = ({ key, target }) => {
			if ((key === "Esc" || key === "Escape") && this._topOfStack()) this._handleUserInitiatedClose(target);
		};
		this.ariaLabel = "";
		this.closeIconDescription = "Close";
		this.hasCloseIcon = false;
		this.influencerPlacement = "right";
		this.influencerWidth = "narrow";
		this.open = false;
		this.preventCloseOnClickOutside = false;
		this.width = "narrow";
		this._checkUpdateActionSizes = () => {
			if (this._actions) for (let i = 0; i < this._actions.length; i++) this._actions[i].setAttribute("size", this.width === "wide" ? "2xl" : "xl");
		};
		this._maxActions = 4;
		this._stackDepth = -1;
		this._stackPosition = -1;
		this._topOfStack = () => {
			return this._stackDepth === this._stackPosition;
		};
		this._notifyStack = () => {
			_CDSTearsheet._stack.all.forEach((handler) => {
				handler(Math.min(_CDSTearsheet._stack.open.length, maxStackDepth), _CDSTearsheet._stack.open.indexOf(handler) + 1);
			});
		};
		this._handleStackChange = (newDepth, newPosition) => {
			this._stackDepth = newDepth;
			this._stackPosition = newPosition;
			if (this._stackDepth > 1 && this._stackPosition > 0) {
				this.setAttribute("stack-position", `${newPosition}`);
				this.setAttribute("stack-depth", `${this._stackDepth}`);
			} else {
				this.removeAttribute("stack-position");
				this.removeAttribute("stack-depth");
			}
		};
		this._updateStack = () => {
			if (this.open) _CDSTearsheet._stack.open.push(this._handleStackChange);
			else {
				const indexOpen = _CDSTearsheet._stack.open.indexOf(this._handleStackChange);
				if (indexOpen >= 0) _CDSTearsheet._stack.open.splice(indexOpen, 1);
			}
			this._notifyStack();
		};
		this.actionsMultiple = [
			"",
			"single",
			"double",
			"triple"
		][this._actionsCount];
		this._checkSetOpen = () => {
			const { _tearsheet: tearsheet } = this;
			if (tearsheet && this._isOpen) tearsheet.addEventListener("transitionend", () => {
				this._isOpen = false;
			});
			else window.requestAnimationFrame(() => {
				this._isOpen = this.open;
			});
		};
	}
	_checkSetHasSlot(e) {
		const t = e.target;
		const dataPostfix = t.getAttribute("data-postfix");
		const postfix = dataPostfix ? `-${dataPostfix}` : "";
		const hasName = `_has-${t.name}${postfix}`.replace(/-./g, (c) => c[1].toUpperCase());
		this[hasName] = (t?.assignedElements()?.length ?? 0) > 0;
	}
	/**
	* Handles `click` event on the modal container.
	*
	* @param event The event.
	*/
	_handleClickContainer(event) {
		if (event.target.matches(this.constructor.selectorCloseButton)) this._handleUserInitiatedClose(event.target);
	}
	/**
	* Handles user-initiated close request of this tearsheet.
	*
	* @param triggeredBy The element that triggered this close request.
	*/
	_handleUserInitiatedClose(triggeredBy) {
		if (this.open) {
			const init = {
				bubbles: true,
				cancelable: true,
				composed: true,
				detail: { triggeredBy }
			};
			if (this.dispatchEvent(new CustomEvent(this.constructor.eventBeforeClose, init))) {
				this.open = false;
				this.dispatchEvent(new CustomEvent(this.constructor.eventClose, init));
			}
		}
	}
	_handleSlugChange(e) {
		const childItems = e.target.assignedElements();
		this._hasSlug = childItems.length > 0;
		if (this._hasSlug) {
			childItems[0].setAttribute("size", "lg");
			this.setAttribute("slug", "");
		} else this.removeAttribute("slug");
	}
	_handleActionsChange(e) {
		const actions = e.target?.assignedElements();
		const actionsCount = actions?.length ?? 0;
		if (actionsCount > this._maxActions) {
			this._actionsCount = this._maxActions;
			console.error(`Too many tearsheet actions, max ${this._maxActions}.`);
		} else this._actionsCount = actionsCount;
		for (let i = 0; i < actions?.length; i++) if (i + 1 > this._maxActions) {
			actions[i].setAttribute("hidden", "true");
			actions[i].setAttribute(`data-actions-limit-${this._maxActions}-exceeded`, `${actions.length}`);
		} else actions[i].classList.add(`${blockClassActionSet}__action-button`);
		this._checkUpdateActionSizes();
	}
	static {
		this._stack = {
			open: [],
			all: []
		};
	}
	connectedCallback() {
		super.connectedCallback();
		_CDSTearsheet._stack.all.push(this._handleStackChange);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		const indexAll = _CDSTearsheet._stack.all.indexOf(this._handleStackChange);
		_CDSTearsheet._stack.all.splice(indexAll, 1);
		const indexOpen = _CDSTearsheet._stack.all.indexOf(this._handleStackChange);
		_CDSTearsheet._stack.open.splice(indexOpen, 1);
	}
	render() {
		const { closeIconDescription, influencerPlacement, influencerWidth, open, width } = this;
		const actionsMultiple = [
			"",
			"single",
			"double",
			"triple"
		][this._actionsCount];
		const headerFieldsTemplate = html`<div
      class=${`${blockClass}__header-fields`}>
      <h2 class=${`${blockClassModalHeader}__label`} ?hidden=${!this._hasLabel}>
        <slot name="label" @slotchange=${this._checkSetHasSlot}></slot>
      </h2>
      <h3
        class=${`${blockClassModalHeader}__heading ${blockClass}__heading`}
        ?hidden=${!this._hasTitle}>
        <slot name="title" @slotchange=${this._checkSetHasSlot}></slot>
      </h3>
      <div
        class=${`${blockClass}__header-description`}
        ?hidden=${!this._hasDescription}>
        <slot name="description" @slotchange=${this._checkSetHasSlot}></slot>
      </div>
    </div>`;
		const headerActionsTemplate = html` <div
      class=${`${blockClass}__header-actions`}
      ?hidden=${!this._hasHeaderActions || this.width === "narrow"}>
      <slot name="header-actions" @slotchange=${this._checkSetHasSlot}></slot>
    </div>`;
		const headerTemplate = html` <cds-custom-modal-header
      class=${`${blockClass}__header`}
      ?has-close-icon=${this.hasCloseIcon || this?._actionsCount === 0}
      ?has-navigation=${this._hasHeaderNavigation && this.width === "wide"}
      ?has-header-actions=${this._hasHeaderActions && this.width === "wide"}
      ?has-actions=${this?._actionsCount > 0}
      ?has-slug=${this?._hasSlug}
      width=${width}>
      ${this.width === "wide" ? html`<cds-custom-layer level="1" class=${`${blockClass}__header-content`}
            >${headerFieldsTemplate}${headerActionsTemplate}</cds-custom-layer
          >` : html`<div>${headerFieldsTemplate}${headerActionsTemplate}</div>`}

      <div
        class=${`${blockClass}__header-navigation`}
        ?hidden=${!this._hasHeaderNavigation || this.width === "narrow"}>
        <slot
          name="header-navigation"
          @slotchange=${this._checkSetHasSlot}></slot>
      </div>
      <slot name="slug" @slotchange=${this._handleSlugChange}></slot>
      ${this.hasCloseIcon || this?._actionsCount === 0 ? html`<cds-custom-modal-close-button
            close-button-label=${closeIconDescription}
            @click=${this._handleUserInitiatedClose}></cds-custom-modal-close-button>` : ""}
    </cds-custom-modal-header>`;
		return html`
      <a
        id="start-sentinel"
        class="${"cds-custom"}--visually-hidden"
        href="javascript:void 0"
        role="navigation"></a>
      <div
        aria-label=${this.ariaLabel}
        class=${`${blockClass}__container cds-custom--modal-container cds-custom--modal-container--sm`}
        part="dialog"
        role="complementary"
        ?open=${this._isOpen}
        ?opening=${open && !this._isOpen}
        ?closing=${!open && this._isOpen}
        width=${width}
        stack-position=${this._stackPosition}
        stack-depth=${this._stackDepth}
        @click=${this._handleClickContainer}>
        <!-- Header -->
        ${headerTemplate}

        <!-- Body  -->
        <cds-custom-modal-body class=${`${blockClass}__body`} width=${width}>
          <!-- Influencer when on left -->
          ${influencerPlacement !== "right" ? html`<div
                class=${`${blockClass}__influencer`}
                ?wide=${influencerWidth === "wide"}
                ?hidden=${!this._hasInfluencerLeft || this.width === "narrow"}>
                <slot
                  name="influencer"
                  data-postfix="left"
                  @slotchange=${this._checkSetHasSlot}></slot>
              </div>` : ""}

          <div class=${`${blockClass}__right`}>
            <div class=${`${blockClass}__main`}>
              <div class=${`${blockClass}__content`}>
                <cds-custom-layer level="0">
                  <slot></slot>
                </cds-custom-layer>
              </div>

              <!-- Influencer when on right -->
              ${influencerPlacement === "right" ? html`<div
                    class=${`${blockClass}__influencer`}
                    ?wide=${influencerWidth}
                    ?hidden=${!this._hasInfluencerRight || this.width === "narrow"}>
                    <slot
                      name="influencer"
                      data-postfix="right"
                      @slotchange=${this._checkSetHasSlot}></slot>
                  </div>` : ""}
            </div>
            <!-- Action buttons -->
            <cds-custom-button-set-base
              class=${`${blockClass}__buttons ${blockClass}__button-container`}
              actions-multiple=${actionsMultiple}
              ?tearsheet-wide=${width === "wide"}
              ?hidden=${this._actionsCount === 0}>
              <slot
                name="actions"
                @slotchange=${this._handleActionsChange}></slot>
            </cds-custom-button-set-base>
          </div>
        </cds-custom-modal-body>
      </div>
      <a
        id="end-sentinel"
        class="${"cds-custom"}--visually-hidden"
        href="javascript:void 0"
        role="navigation"></a>
    `;
	}
	async updated(changedProperties) {
		if (changedProperties.has("width")) this._checkUpdateActionSizes();
		if (changedProperties.has("width") || changedProperties.has("_hasHeaderNavigation") || changedProperties.has("_hasInfluencerLeft") || changedProperties.has("_hasInfluencerRight") || changedProperties.has("_hasHeaderActions")) {
			if (this.width === "narrow") {
				if (this._hasHeaderNavigation) console.error(`Header navigation is not permitted in narrow Tearsheet.`);
				if (this._hasInfluencerLeft || this._hasInfluencerRight) console.error(`Influencer is not permitted in narrow Tearsheet.`);
				if (this._hasHeaderActions) console.error(`Header actions are not permitted in narrow Tearsheet.`);
			}
		}
		if (changedProperties.has("open")) {
			this._updateStack();
			this._checkSetOpen();
			if (this.open) {
				this._launcher = this.ownerDocument.activeElement;
				const focusNode = this.selectorInitialFocus && this.querySelector(this.selectorInitialFocus);
				await this.constructor._delay();
				if (focusNode) focusNode.focus();
				else if (!tryFocusElems(this.querySelectorAll(this.constructor.selectorTabbable), true)) this.focus();
			} else if (this._launcher && typeof this._launcher.focus === "function") {
				this._launcher.focus();
				this._launcher = null;
			}
		}
	}
	/**
	* @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 buttons that should close this modal.
	*/
	static get selectorCloseButton() {
		return `[data-modal-close],cds-custom-modal-close-button`;
	}
	/**
	* A selector selecting tabbable nodes.
	*/
	static get selectorTabbable() {
		return selectorTabbable;
	}
	/**
	* The name of the custom event fired before this tearsheet is being closed upon a user gesture.
	* Cancellation of this event stops the user-initiated action of closing this tearsheet.
	*/
	static get eventBeforeClose() {
		return `cds-custom-tearsheet-beingclosed`;
	}
	/**
	* The name of the custom event fired after this tearsheet is closed upon a user gesture.
	*/
	static get eventClose() {
		return `cds-custom-tearsheet-closed`;
	}
	/**
	* The name of the custom event fired on clicking the navigate back button
	*/
	static get eventNavigateBack() {
		return `cds-custom-tearsheet-header-navigate-back`;
	}
};
__decorate([query("#start-sentinel")], CDSTearsheet.prototype, "_startSentinelNode", void 0);
__decorate([query("#end-sentinel")], CDSTearsheet.prototype, "_endSentinelNode", void 0);
__decorate([query(`.${blockClass}__container`)], CDSTearsheet.prototype, "_tearsheet", void 0);
__decorate([queryAssignedElements({
	slot: "actions",
	selector: `cds-custom-button`
})], CDSTearsheet.prototype, "_actions", void 0);
__decorate([state()], CDSTearsheet.prototype, "_actionsCount", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasHeaderActions", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasLabel", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasSlug", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasTitle", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasDescription", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasInfluencerLeft", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasInfluencerRight", void 0);
__decorate([state()], CDSTearsheet.prototype, "_isOpen", void 0);
__decorate([state()], CDSTearsheet.prototype, "_hasHeaderNavigation", void 0);
__decorate([HostListener("click")], CDSTearsheet.prototype, "_handleClick", void 0);
__decorate([HostListener("shadowRoot:focusout")], CDSTearsheet.prototype, "_handleBlur", void 0);
__decorate([HostListener("document:keydown")], CDSTearsheet.prototype, "_handleKeydown", void 0);
__decorate([property({
	reflect: true,
	attribute: "aria-label"
})], CDSTearsheet.prototype, "ariaLabel", void 0);
__decorate([property({
	reflect: true,
	attribute: "close-icon-description"
})], CDSTearsheet.prototype, "closeIconDescription", void 0);
__decorate([property({
	reflect: true,
	type: Boolean,
	attribute: "has-close-icon"
})], CDSTearsheet.prototype, "hasCloseIcon", void 0);
__decorate([property({
	reflect: true,
	attribute: "influencer-placement"
})], CDSTearsheet.prototype, "influencerPlacement", void 0);
__decorate([property({
	reflect: true,
	attribute: "influencer-width"
})], CDSTearsheet.prototype, "influencerWidth", void 0);
__decorate([property({
	type: Boolean,
	reflect: true
})], CDSTearsheet.prototype, "open", void 0);
__decorate([property({
	type: Boolean,
	attribute: "prevent-close-on-click-outside"
})], CDSTearsheet.prototype, "preventCloseOnClickOutside", void 0);
__decorate([property({
	reflect: true,
	attribute: "selector-initial-focus",
	type: String
})], CDSTearsheet.prototype, "selectorInitialFocus", void 0);
__decorate([property({
	reflect: true,
	attribute: "width"
})], CDSTearsheet.prototype, "width", void 0);
__decorate([state()], CDSTearsheet.prototype, "_stackDepth", void 0);
__decorate([state()], CDSTearsheet.prototype, "_stackPosition", void 0);
CDSTearsheet = _CDSTearsheet = __decorate([carbonElement(`cds-custom-tearsheet`)], CDSTearsheet);
var tearsheet_default = CDSTearsheet;
//#endregion
export { TEARSHEET_INFLUENCER_PLACEMENT, TEARSHEET_INFLUENCER_WIDTH, TEARSHEET_WIDTH, tearsheet_default as default };

//# sourceMappingURL=tearsheet.js.map