import { __decorate, __metadata } from "tslib";
import { Host, h, } from "@stencil/core";
import { BEM } from "../../utils/bem";
import { balBrowser } from "../../utils/browser";
import { stopEventBubbling } from "../../utils/form-input";
import { debounce, isDescendant } from "../../utils/helpers";
import { isEscapeKey } from "../../utils/keyboard";
import { Logger } from "../../utils/log";
import { DrawerVariantRenderer, FullscreenVariantRenderer, PopoverVariantRenderer, } from "./variants";
import { VariantRenderer } from "./variants/variant.renderer";
export class Popup {
    constructor() {
        this.popupId = `bal-pu-${popupIds++}`;
        this.isClickedOutsideOnMouseDown = false;
        this.isClickedOutsideOnMouseUp = false;
        this.popoverVariantRenderer = new VariantRenderer(new PopoverVariantRenderer());
        this.fullscreenVariantRenderer = new VariantRenderer(new FullscreenVariantRenderer());
        this.drawerVariantRenderer = new VariantRenderer(new DrawerVariantRenderer());
        this.lastVariant = 'popover';
        this.activeClosable = false;
        this.activeBackdropDismiss = false;
        this.activeVariant = 'popover';
        this.minContainerWidth = '16.25rem';
        /**
         * PUBLIC PROPERTY API
         * ------------------------------------------------------
         */
        /**
         * Label or title of the popup element
         */
        this.label = '';
        /**
         * Defines the variant / type of popup
         */
        this.variant = 'popover';
        /**
         * If set it turns a popover into a fullscreen or a drawer on touch devices
         */
        this.placement = 'bottom';
        /**
         * If `true`, it shows a little indicator to the trigger element.
         */
        this.arrow = false;
        /**
         * If `true`, a backdrop will be displayed behind the modal.
         */
        this.backdrop = false;
        /**
         * Offset form trigger to popup.
         */
        this.offset = 0;
        /**
         * If `true`, the modal can be closed with the escape key or the little close button.
         */
        this.closable = false;
        /**
         * If `true`, the modal can be closed with the click outside of the modal
         */
        this.backdropDismiss = false;
        /**
         * If `true` the popup is open.
         */
        this.active = false;
        /**
         * Internal active state
         */
        this.presented = false;
        this.initialActive = this.active;
        /**
         * @internal
         */
        this.demo = false;
        /**
         * LISTENERS
         * ------------------------------------------------------
         */
        this.debouncedGlobalClick = debounce((trigger) => this.notifyGlobalClick(trigger), 10);
        /**
         * EVENT BINDING
         * ------------------------------------------------------
         */
        this.onBackdropClick = (ev) => {
            if (this.activeBackdropDismiss && this.presented && ev && ev.target) {
                const element = ev.target;
                return element.classList.contains('bal-popup__backdrop');
            }
            return false;
        };
        this.onCloseClick = () => {
            if (this.activeClosable) {
                this.dismiss();
            }
        };
    }
    createLogger(log) {
        this.log = log;
    }
    async variantChanged(newVariant, oldVariant) {
        if (newVariant !== oldVariant) {
            await this.getVariantRenderer(oldVariant).dismiss(this);
            if (this.activeVariant !== newVariant) {
                this.lastVariant = this.activeVariant;
                this.activeVariant = newVariant;
                await this.getVariantRenderer(this.lastVariant).dismiss(this);
            }
            if (this.presented) {
                await this.getVariantRenderer(newVariant).present(this);
            }
        }
    }
    async activeChanged(newActive, oldActive) {
        if (newActive !== oldActive && newActive !== this.presented) {
            if (newActive) {
                this.present();
            }
            else {
                this.dismiss();
            }
        }
    }
    contentWidthChanged(newValue, oldValue) {
        if (newValue !== oldValue) {
            if (newValue === undefined) {
                this.el.style.removeProperty('--bal-popup-variant-popover-max-width');
            }
            else {
                this.el.style.setProperty('--bal-popup-variant-popover-max-width', `${this.contentWidth}px`);
            }
        }
    }
    /**
     * LIFECYCLE
     * ------------------------------------------------------
     */
    componentDidLoad() {
        this.contentWidthChanged(this.contentWidth, 0);
        if (this.initialActive === true && this.presented !== true) {
            this.present();
        }
        if (this.demo) {
            this.present();
        }
    }
    async listenOnGlobalClick(ev) {
        var _a;
        const target = ev.target;
        const trigger = target.closest('[bal-popup]');
        if (trigger && balBrowser.hasWindow) {
            const popupId = ((_a = trigger.attributes.getNamedItem('bal-popup')) === null || _a === void 0 ? void 0 : _a.nodeValue) || '';
            if (this.el.id === popupId) {
                this.debouncedGlobalClick(trigger);
            }
        }
        else if (!this.backdrop && this.closable && this.presented && !isDescendant(this.el, target)) {
            await this.dismiss();
        }
    }
    async listenOnKeyDown(ev) {
        if (this.activeClosable && this.presented && isEscapeKey(ev)) {
            stopEventBubbling(ev);
            await this.dismiss();
        }
    }
    async listenOnMouseDown(ev) {
        this.isClickedOutsideOnMouseDown = this.onBackdropClick(ev);
    }
    async listenOnMouseUp(ev) {
        this.isClickedOutsideOnMouseUp = this.onBackdropClick(ev);
    }
    async listenOnComponentClick() {
        if (this.presented &&
            this.activeBackdropDismiss &&
            this.isClickedOutsideOnMouseUp &&
            this.isClickedOutsideOnMouseDown) {
            await this.dismiss();
        }
    }
    /**
     * PUBLIC METHODS
     * ------------------------------------------------------
     */
    /**
     * Opens the popup
     */
    async present() {
        await this.resetAllVariants();
        if (await this._present()) {
            this.lastTrigger = this.trigger;
            this.balChange.emit(this.presented);
        }
    }
    /**
     * Closes the popup
     */
    async dismiss() {
        await this.resetAllVariants();
        if (await this._dismiss()) {
            this.lastTrigger = this.trigger;
            this.balChange.emit(this.presented);
        }
    }
    /**
     * Triggers the popup
     */
    async toggle() {
        if (this.presented) {
            return this.dismiss();
        }
        else {
            return this.present();
        }
    }
    /**
     * @internal
     */
    async setMinWidth(value) {
        if (this.containerEl) {
            this.containerEl.style.minWidth = `${value}px`;
            this.minContainerWidth = `${value}px`;
        }
    }
    /**
     * @internal
     */
    async _emitChange() {
        this.balChange.emit(this.presented);
    }
    /**
     * @internal
     */
    async _present() {
        if (balBrowser.hasDocument) {
            this.lastFocus = document.activeElement || undefined;
        }
        if (this.lastVariantRenderer) {
            await this.lastVariantRenderer.dismiss(this);
            this.presented = true;
        }
        this.lastVariantRenderer = this.getVariantRenderer();
        const result = await this.lastVariantRenderer.present(this);
        this.focusFirstDescendant();
        return result;
    }
    /**
     * @internal
     */
    async _dismiss() {
        var _a;
        const result = await this.getVariantRenderer().dismiss(this);
        this.lastVariantRenderer = undefined;
        if (this.lastFocus && this.lastFocus.focus) {
            (_a = this.lastFocus) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true });
        }
        return result;
    }
    /**
     * GETTERS
     * ------------------------------------------------------
     */
    getVariantRenderer(variant = this.activeVariant) {
        switch (variant) {
            case 'fullscreen':
                return this.fullscreenVariantRenderer;
            case 'drawer':
                return this.drawerVariantRenderer;
            default:
                return this.popoverVariantRenderer;
        }
    }
    getValue(trigger, attributeName, componentValue) {
        const attributeValue = trigger.attributes.getNamedItem(attributeName);
        return attributeValue ? attributeValue.value : componentValue;
    }
    getNumberValue(trigger, attributeName, componentValue) {
        const attributeValue = trigger.attributes.getNamedItem(attributeName);
        if (attributeValue) {
            return parseInt(attributeValue.value, 10) || componentValue;
        }
        return componentValue;
    }
    getBooleanValue(trigger, attributeName, componentValue) {
        const attributeValue = trigger.attributes.getNamedItem(attributeName);
        if (attributeValue) {
            const booleanValue = attributeValue.value === '' || attributeValue.value === 'true' ? true : false;
            return attributeValue ? booleanValue : componentValue;
        }
        return componentValue;
    }
    /**
     * PRIVATE METHODS
     * ------------------------------------------------------
     */
    notifyGlobalClick(trigger) {
        this.trigger = trigger;
        this.lastTrigger = this.lastTrigger === undefined ? this.trigger : this.lastTrigger;
        this.activeVariant = this.getValue(trigger, 'bal-popup-variant', this.variant);
        this.activeClosable = this.getBooleanValue(trigger, 'bal-popup-closable', this.closable);
        this.activeBackdropDismiss = this.getBooleanValue(trigger, 'bal-popup-backdrop-dismiss', this.backdropDismiss);
        // present or dismiss active variant
        if (this.presented && this.lastTrigger !== this.trigger) {
            this._present();
            this.lastTrigger = this.trigger;
        }
        else {
            this.toggle();
        }
    }
    async resetAllVariants() {
        await this.dismissAllOtherPopups();
        if (this.lastVariant !== this.activeVariant) {
            const lastVariant = this.getVariantRenderer(this.lastVariant);
            await lastVariant.dismiss(this);
        }
        this.lastVariant = this.activeVariant;
    }
    async dismissAllOtherPopups() {
        if (balBrowser.hasDocument) {
            const popups = Array.from(document.getElementsByTagName('bal-popup')).filter(el => el.id !== this.el.id && el.ariaHidden !== 'true');
            for (let index = 0; index < popups.length; index++) {
                const popup = popups[index];
                await popup._dismiss();
                await popup._emitChange();
            }
        }
    }
    focusFirstDescendant() {
        const contentEl = this.contentEl;
        if (contentEl) {
            contentEl.focus({ preventScroll: true });
        }
    }
    /**
     * RENDER
     * ------------------------------------------------------
     */
    render() {
        const block = BEM.block('popup');
        const containerBlock = block.element('container');
        const arrowBlock = block.element('arrow');
        const backdropBlock = block.element('backdrop');
        const innerBlock = block.element('inner');
        const innerHeadBlock = innerBlock.element('head');
        const innerContentBlock = innerBlock.element('content');
        return (h(Host, { key: '815e1a03c79472bb0913b4a28519802606bac73c', class: Object.assign({}, block.class()), role: "dialog", "aria-hidden": `${this.presented !== true}`, "aria-modal": `${this.presented === true}`, "aria-presented": `${this.presented === true}`, "aria-labelledby": `${this.popupId}-heading` }, h("div", { key: 'effa9ca039cb7c5b27db07f23e02a464e5f09ce9', class: Object.assign({}, backdropBlock.class()), ref: backdropEl => (this.backdropEl = backdropEl) }), h("div", { key: '343a483098c5d4b657298c3f0b5d14705a3e78bd', class: Object.assign(Object.assign({}, containerBlock.class()), containerBlock.modifier(`variant-${this.activeVariant}`).class()), ref: containerEl => (this.containerEl = containerEl), style: { minWidth: this.minContainerWidth } }, h("div", { key: 'dbcb76dfb93527828e6f73974cbfd62225bd26c3', class: Object.assign({}, arrowBlock.class()), ref: arrowEl => (this.arrowEl = arrowEl) }), h("bal-stack", { key: '119c391a7fa3081548740bf23b57a6ae05417188', layout: "vertical", px: this.activeVariant === 'popover' ? 'medium' : 'none', py: "medium", class: Object.assign({}, innerBlock.class()), ref: innerBlock => (this.innerEl = innerBlock) }, this.label ? (h("bal-stack", { space: "auto", class: Object.assign({}, innerHeadBlock.class()) }, h("bal-heading", { "data-testid": "bal-popup-label", level: "span", "visual-level": "large", id: `${this.popupId}-heading` }, this.label), this.activeClosable ? (h("bal-close", { "data-testid": "bal-popup-close", tabindex: -1, onClick: () => this.onCloseClick() })) : (''))) : (''), h("div", { key: 'ff97c08a3151dc9f71552eede345d84716ea7e3b', class: Object.assign({}, innerContentBlock.class()), ref: contentEl => (this.contentEl = contentEl), "data-testid": "bal-popup-content", tabindex: "-1" }, h("slot", { key: '21e9b66eec4627f414c4802eccc5276c20a9c536' }))))));
    }
    static get is() { return "bal-popup"; }
    static get originalStyleUrls() {
        return {
            "$": ["bal-popup.sass"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bal-popup.css"]
        };
    }
    static get properties() {
        return {
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Label or title of the popup element"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "label",
                "defaultValue": "''"
            },
            "reference": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Id of the reference element default is the trigger element."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "reference"
            },
            "variant": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalPopupVariant",
                    "resolved": "\"drawer\" | \"fullscreen\" | \"popover\"",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines the variant / type of popup"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "variant",
                "defaultValue": "'popover'"
            },
            "placement": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalPopupPlacement",
                    "resolved": "\"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If set it turns a popover into a fullscreen or a drawer on touch devices"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "placement",
                "defaultValue": "'bottom'"
            },
            "arrow": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, it shows a little indicator to the trigger element."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "arrow",
                "defaultValue": "false"
            },
            "backdrop": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, a backdrop will be displayed behind the modal."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "backdrop",
                "defaultValue": "false"
            },
            "offset": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Offset form trigger to popup."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "offset",
                "defaultValue": "0"
            },
            "closable": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the modal can be closed with the escape key or the little close button."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "closable",
                "defaultValue": "false"
            },
            "backdropDismiss": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the modal can be closed with the click outside of the modal"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "backdrop-dismiss",
                "defaultValue": "false"
            },
            "active": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true` the popup is open."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "active",
                "defaultValue": "false"
            },
            "contentWidth": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Defines the width of the content"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "content-width"
            },
            "demo": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "demo",
                "defaultValue": "false"
            }
        };
    }
    static get states() {
        return {
            "activeClosable": {},
            "activeBackdropDismiss": {},
            "activeVariant": {},
            "trigger": {},
            "lastTrigger": {},
            "minContainerWidth": {},
            "presented": {}
        };
    }
    static get events() {
        return [{
                "method": "balChange",
                "name": "balChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the accordion has opened or closed"
                },
                "complexType": {
                    "original": "BalEvents.BalPopupChangeDetail",
                    "resolved": "boolean",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balWillAnimate",
                "name": "balWillAnimate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted before the animation starts"
                },
                "complexType": {
                    "original": "BalEvents.BalPopupWillAnimateDetail",
                    "resolved": "boolean",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balDidAnimate",
                "name": "balDidAnimate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the animation has finished"
                },
                "complexType": {
                    "original": "BalEvents.BalPopupDidAnimateDetail",
                    "resolved": "boolean",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "present": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Opens the popup",
                    "tags": []
                }
            },
            "dismiss": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Closes the popup",
                    "tags": []
                }
            },
            "toggle": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Triggers the popup",
                    "tags": []
                }
            },
            "setMinWidth": {
                "complexType": {
                    "signature": "(value: number) => Promise<void>",
                    "parameters": [{
                            "name": "value",
                            "type": "number",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            },
            "_emitChange": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            },
            "_present": {
                "complexType": {
                    "signature": "() => Promise<boolean>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        }
                    },
                    "return": "Promise<boolean>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            },
            "_dismiss": {
                "complexType": {
                    "signature": "() => Promise<boolean>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<boolean>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "variant",
                "methodName": "variantChanged"
            }, {
                "propName": "active",
                "methodName": "activeChanged"
            }, {
                "propName": "contentWidth",
                "methodName": "contentWidthChanged"
            }];
    }
    static get listeners() {
        return [{
                "name": "click",
                "method": "listenOnGlobalClick",
                "target": "window",
                "capture": false,
                "passive": false
            }, {
                "name": "keydown",
                "method": "listenOnKeyDown",
                "target": "document",
                "capture": false,
                "passive": false
            }, {
                "name": "mousedown",
                "method": "listenOnMouseDown",
                "target": undefined,
                "capture": false,
                "passive": true
            }, {
                "name": "mouseup",
                "method": "listenOnMouseUp",
                "target": undefined,
                "capture": false,
                "passive": true
            }, {
                "name": "click",
                "method": "listenOnComponentClick",
                "target": undefined,
                "capture": false,
                "passive": false
            }];
    }
}
__decorate([
    Logger('bal-popup'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Function]),
    __metadata("design:returntype", void 0)
], Popup.prototype, "createLogger", null);
let popupIds = 0;
