// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Closeable } from '../../../Behaviors/Closeable';
import { Openable } from '../../../Behaviors/Openable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
/**
 * The `{@link OverlayElement}` element.
 *
 * @fires closed - Dispatched when the `OverlayElement` is closed.
 * @fires opened - Dispatched when the `OverlayElement` is opened.
 *
 * @public
 * @abstract
 */
export class OverlayElement extends Openable(Closeable(CustomElement)) {
    // #region Fields
    _isOpen;
    _hasBackdrop;
    _pressEscapeToClose;
    _clickOutsideToClose;
    _boundHandleKeyDown;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._isOpen = false;
        this._hasBackdrop = false;
        this._pressEscapeToClose = false;
        this._clickOutsideToClose = false;
        this._boundHandleKeyDown = null;
    }
    // #endregion
    // #region Properties
    /**
     * Gets or sets the `isOpen` property.
     *
     * @public
     * @attr
     */
    get isOpen() {
        return this._isOpen;
    }
    set isOpen(value) {
        if (this._isOpen !== value) {
            this.onIsOpenChanged(this._isOpen, value);
        }
    }
    /**
     * Gets or sets the `hasBackdrop` property.
     *
     * @public
     * @attr
     */
    get hasBackdrop() {
        return this._hasBackdrop;
    }
    set hasBackdrop(value) {
        if (this._hasBackdrop !== value) {
            this._hasBackdrop = value;
            this.requestUpdate('hasBackdrop');
        }
    }
    /**
     * Gets or sets the `pressEscapeToClose` property.
     *
     * @public
     * @attr
     */
    get pressEscapeToClose() {
        return this._pressEscapeToClose;
    }
    set pressEscapeToClose(value) {
        if (this._pressEscapeToClose !== value) {
            this._pressEscapeToClose = value;
            this.requestUpdate('pressEscapeToClose');
        }
    }
    /**
     * Gets or sets the `clickOutsideToClose` property.
     *
     * @public
     * @attr
     */
    get clickOutsideToClose() {
        return this._clickOutsideToClose;
    }
    set clickOutsideToClose(value) {
        if (this._clickOutsideToClose !== value) {
            this._clickOutsideToClose = value;
            this.requestUpdate('clickOutsideToClose');
        }
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._boundHandleKeyDown = this.handleKeyDown.bind(this);
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        this.removeEscapeListener();
        super.disconnectedCallback();
    }
    /**
     * Opens the `OverlayElement`.
     *
     * @public
     * @override
     */
    async open() {
        if (this._isOpen) {
            return;
        }
        return super.open()
            .then(() => {
            this.isOpen = true;
            this.addEscapeListener();
        });
    }
    /**
     * Closes the `OverlayElement`.
     *
     * @public
     * @override
     */
    async close() {
        if (!this._isOpen) {
            return false;
        }
        this.removeEscapeListener();
        return super.close()
            .then((x) => {
            this.isOpen = false;
            return x;
        });
    }
    /**
     * This method is invoked when the `isOpen` property is changed.
     *
     * @protected
     */
    onIsOpenChanged(_prev, newValue) {
        this._isOpen = newValue;
        this.requestUpdate('isOpen');
        if (newValue) {
            void super.open();
            this.addEscapeListener();
        }
        else {
            this.removeEscapeListener();
            const args = { cancel: false };
            this.closed.emit(args);
        }
    }
    /**
     * Handles the keydown event for the escape key.
     * Only closes if this overlay is the topmost one (last in DOM order among open overlays).
     *
     * @private
     */
    handleKeyDown(event) {
        if (!this._pressEscapeToClose || !this._isOpen || event.code !== 'Escape') {
            return;
        }
        // Find all open overlays that listen to escape
        const allOpenOverlays = Array.from(document.querySelectorAll('[is-open]'))
            .filter((el) => el instanceof OverlayElement && el.isOpen && el.pressEscapeToClose);
        // Only close if this is the topmost overlay (last in the list)
        if (allOpenOverlays.length > 0 && allOpenOverlays[allOpenOverlays.length - 1] === this) {
            event.stopPropagation();
            void this.close();
        }
    }
    /**
     * Adds the escape key listener to the document.
     *
     * @private
     */
    addEscapeListener() {
        if (this._boundHandleKeyDown && this._pressEscapeToClose) {
            document.addEventListener('keydown', this._boundHandleKeyDown);
        }
    }
    /**
     * Removes the escape key listener from the document.
     *
     * @private
     */
    removeEscapeListener() {
        if (this._boundHandleKeyDown) {
            document.removeEventListener('keydown', this._boundHandleKeyDown);
        }
    }
}
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], OverlayElement.prototype, "isOpen", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], OverlayElement.prototype, "hasBackdrop", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], OverlayElement.prototype, "pressEscapeToClose", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], OverlayElement.prototype, "clickOutsideToClose", null);
//# sourceMappingURL=OverlayElement.js.map