import { h } from "@stencil/core";
import { constrainFocus } from '../../utils/a11y';
import { OVERLAY_OPEN_CLASS, debounce } from '../../utils/utils';
export class Modal {
    constructor() {
        this.overlayListener = (event) => this.guardedClose(event);
        /**
         * If false, clicking the backdrop will not close the modal
         */
        this.overlayClose = true;
        /**
         * The modal size
         * Possible values are: `"small"`, `"medium"`, `"large"`, or `"xlarge"`.
         */
        this.size = 'medium';
    }
    componentWillLoad() {
        this.onResize = debounce(this.onResize.bind(this), 50);
    }
    connectedCallback() {
        this.bodyEl = this.element.ownerDocument.body;
    }
    disconnectedCallback() {
        this.bodyEl.classList.remove(OVERLAY_OPEN_CLASS);
        this.modalEl.removeEventListener('mouseup', this.overlayListener);
        if (this.showing) {
            this.modalEl.remove();
        }
    }
    onBottomContentLoaded({ target }) {
        this.bottomEl = target;
    }
    onResize() {
        if (!this.showing)
            return;
        this.setContentHeight();
    }
    /**
     * Show the modal
     */
    async open() {
        this.anjModalWillOpen.emit();
        this.triggerEl = document.activeElement;
        this.appendModal(this.bodyEl);
        this.bodyEl.classList.add(OVERLAY_OPEN_CLASS);
        this.active = true;
        return new Promise(resolve => {
            window.setTimeout(() => {
                this.setContentHeight();
                this.showing = true;
                this.modalEl.focus();
                this.anjModalDidOpen.emit();
                resolve();
            }, Modal.openDelay);
        });
    }
    /**
     * Hide the modal
     */
    async close() {
        if (!this.showing)
            return;
        this.showing = false;
        return new Promise(resolve => {
            window.setTimeout(() => {
                this.active = false;
                this.disconnectedCallback();
                if (this.triggerEl) {
                    this.triggerEl.focus();
                }
                this.appendModal(this.element);
                this.anjModalDidClose.emit();
                resolve();
            }, Modal.closeDelay);
        });
    }
    async guardedClose(event) {
        if (!event || event instanceof CustomEvent || this.overlayClose) {
            this.anjModalWillClose.emit();
        }
    }
    async onKeyDown(event) {
        if (event.key === 'Escape') {
            return this.guardedClose();
        }
        else if (event.key === 'Tab') {
            constrainFocus(event, this.modalEl);
        }
    }
    setContentHeight(offset) {
        if (this.contentEl) {
            const bottomOffset = offset ? offset : this.bottomEl ? this.bottomEl.offsetHeight : 0;
            this.contentEl.style.maxHeight = `${this.modalEl.offsetHeight - bottomOffset - (this.dialogEl.offsetTop * 2)}px`;
        }
    }
    appendModal(el) {
        const modalEl = (el.contains(this.modalEl)) ? this.element.removeChild(this.modalEl) : this.modalEl;
        el.appendChild(modalEl);
    }
    render() {
        const modalClasses = this.showing ? 'anj-modal anj-show' : 'anj-modal';
        const dialogClasses = `anj-modal-dialog anj-modal-${this.size}`;
        const contentClasses = this.bottomEl ? 'anj-modal-content anj-animate' : 'anj-modal-content';
        // Gets around a weird typing thing with custom event hooks on native elements
        const containerEvents = {
            'onAnjClose': (e) => this.guardedClose(e),
            'onAnjTrayCollapse': ({ detail }) => this.setContentHeight(detail)
        };
        return (h("div", Object.assign({ class: modalClasses, style: { display: this.active ? 'block' : 'none' }, onKeyDown: (ev) => this.onKeyDown(ev), ref: ref => this.modalEl = ref, tabindex: "-1", onMouseDown: () => this.modalEl.addEventListener('mouseup', this.overlayListener) }, containerEvents),
            h("div", { class: dialogClasses, role: "document", ref: ref => this.dialogEl = ref, onMouseDown: (e) => e.stopPropagation(), onMouseUp: (e) => e.stopPropagation() },
                h("div", { class: contentClasses, ref: ref => this.contentEl = ref },
                    h("slot", null),
                    h("slot", { name: "nav-left" }),
                    h("slot", { name: "nav-right" }))),
            h("slot", { name: "tray" })));
    }
    static get is() { return "anj-modal"; }
    static get encapsulation() { return "scoped"; }
    static get originalStyleUrls() { return {
        "$": ["modal.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["modal.css"]
    }; }
    static get properties() { return {
        "overlayClose": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If false, clicking the backdrop will not close the modal"
            },
            "attribute": "overlay-close",
            "reflect": false,
            "defaultValue": "true"
        },
        "size": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "'small' | 'medium' | 'large' | 'xlarge'",
                "resolved": "\"large\" | \"medium\" | \"small\" | \"xlarge\"",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": "The modal size\nPossible values are: `\"small\"`, `\"medium\"`, `\"large\"`, or `\"xlarge\"`."
            },
            "attribute": "size",
            "reflect": false,
            "defaultValue": "'medium'"
        }
    }; }
    static get states() { return {
        "active": {},
        "showing": {}
    }; }
    static get events() { return [{
            "method": "anjModalWillOpen",
            "name": "anjModalWillOpen",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the modal will open"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjModalDidOpen",
            "name": "anjModalDidOpen",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the modal has opened"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjModalWillClose",
            "name": "anjModalWillClose",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the modal will close"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjModalDidClose",
            "name": "anjModalDidClose",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the modal has closed"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }]; }
    static get methods() { return {
        "open": {
            "complexType": {
                "signature": "() => Promise<void>",
                "parameters": [],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "HTMLElement": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "Show the modal",
                "tags": []
            }
        },
        "close": {
            "complexType": {
                "signature": "() => Promise<void>",
                "parameters": [],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "Hide the modal",
                "tags": []
            }
        },
        "guardedClose": {
            "complexType": {
                "signature": "(event?: MouseEvent | CustomEvent<any>) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "MouseEvent": {
                        "location": "global"
                    },
                    "CustomEvent": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        }
    }; }
    static get elementRef() { return "element"; }
    static get listeners() { return [{
            "name": "anjTrayDidLoad",
            "method": "onBottomContentLoaded",
            "target": undefined,
            "capture": false,
            "passive": false
        }, {
            "name": "resize",
            "method": "onResize",
            "target": "window",
            "capture": false,
            "passive": true
        }, {
            "name": "anjModalWillClose",
            "method": "close",
            "target": "body",
            "capture": false,
            "passive": false
        }]; }
}
Modal.closeDelay = 350;
Modal.openDelay = 50;
