import { Host, h } from "@stencil/core";
import Popper from 'popper.js';
import { constrainFocus, getFocusable } from '../../utils/a11y';
import { OVERLAY_OPEN_CLASS } from '../../utils/utils';
/** @internal */
export class Overlay {
    constructor() {
        this.isChildOverlay = false;
        this.clickObserver = (e) => this.onClick(e);
        this.active = false;
        this.showing = false;
        /**
         * The strategy for dismissing the overlay
         * Options are: `"explicit"`and `"auto"`. Defaults to "explicit".
         */
        this.dismiss = 'explicit';
        /**
         * If false, the overlay will lock window scrolling when open
         */
        this.scrollable = false;
        /**
         * Allows for targeted handling of nested overlays
         */
        this.nested = false;
        /**
         * The offset in `"x, y"` form without px
         */
        this.offset = '0, 0';
        /**
         * The preferred placement
         */
        this.placement = 'top';
        /**
         * If true, traps the focus inside the overlay. Making this opt-in for now, but may become the default.
         */
        this.trapFocus = false;
    }
    componentWillLoad() {
        this.parentEl = this.element.parentElement;
        this.bodyEl = this.element.ownerDocument.body;
        this.scrollParentEl = this.getScrollParentEl();
    }
    disconnectedCallback() {
        if (this.bodyEl && !this.isChildOverlay) {
            this.bodyEl.removeEventListener('click', this.clickObserver);
        }
        if (this._popper) {
            this._popper.destroy();
            this._popper = null;
        }
    }
    onChildDismiss(event) {
        if (event.target !== this.element) {
            // eat dismiss events from inside the overlay (nested overlays *vomit*)
            event.stopPropagation();
        }
    }
    async onKeyDown(event) {
        if (!this.trapFocus)
            return;
        event.stopPropagation();
        if (event.key === 'Escape') {
            this.element.focus();
            this.anjWillDismiss.emit();
            if (this.dismiss === 'auto') {
                return this.close();
            }
        }
        else if (event.key === 'Tab') {
            constrainFocus(event, this.element);
        }
    }
    async onClick(event) {
        const target = event.target;
        const parentOverlay = target.closest(this.element.tagName);
        if (target && (!parentOverlay && parentOverlay !== this.element)) {
            this.anjWillDismiss.emit();
            if (this.dismiss === 'auto') {
                return this.close();
            }
        }
        else if (this.nested && this.isChildOverlay && Array.from(parentOverlay.children || []).find(x => x === target)) {
            this.anjWillDismiss.emit();
        }
    }
    /**
     * Display the overlay
     */
    async open(target) {
        if (this.showing || !this.bodyEl) {
            return;
        }
        window.clearTimeout(this.timerClose);
        this.anjWillOpen.emit();
        this.isChildOverlay = this.determineChildOverlay();
        this.element.remove();
        if (!this.scrollable && !this.isChildOverlay) {
            this.bodyEl.classList.add(OVERLAY_OPEN_CLASS);
        }
        if (this.scrollParentEl) {
            this.scrollParentEl.classList.add(OVERLAY_OPEN_CLASS);
        }
        this.bodyEl.appendChild(this.element);
        this.active = true;
        return new Promise(resolve => {
            window.setTimeout(() => {
                this._popper = new Popper(target, this.element, this.popperOptions());
                this.showing = true;
                this.bodyEl.addEventListener('mousedown', this.clickObserver, { passive: true });
                const focusEl = getFocusable(this.element)[0];
                if (this.trapFocus && focusEl) {
                    focusEl.focus();
                }
                this.anjDidOpen.emit();
                resolve();
            }, Overlay.openDelay);
        });
    }
    /**
     * Hide the overlay
     */
    async close() {
        this.showing = false;
        if (this.scrollParentEl) {
            this.scrollParentEl.classList.remove(OVERLAY_OPEN_CLASS);
        }
        return new Promise(resolve => {
            this.timerClose = window.setTimeout(() => {
                this.bodyEl.removeEventListener('click', this.clickObserver, { passive: true });
                this.active = false;
                this.element.remove();
                this.parentEl.appendChild(this.element);
                this.anjDidDismiss.emit();
                resolve();
            }, Overlay.closeDelay);
        });
    }
    /**
     * Returns the popper instance
     */
    async popper() {
        return Promise.resolve(this._popper);
    }
    popperOptions() {
        return {
            placement: this.placement,
            positionFixed: true,
            modifiers: {
                offset: {
                    offset: this.offset
                }
            }
        };
    }
    determineChildOverlay() {
        if (!this.element.parentElement)
            return false;
        return !!(this.element.closest('anj-modal') || this.element.parentElement.closest('anj-overlay'));
    }
    getScrollParentEl() {
        return this.element.closest('anj-modal-body') || this.element.ownerDocument.body;
    }
    render() {
        return h(Host, { class: { 'anj-show': this.showing }, style: { display: this.active ? 'block' : 'none' }, tabindex: this.trapFocus ? -1 : undefined });
    }
    static get is() { return "anj-overlay"; }
    static get originalStyleUrls() { return {
        "$": ["overlay.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["overlay.css"]
    }; }
    static get properties() { return {
        "dismiss": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "'auto' | 'explicit'",
                "resolved": "\"auto\" | \"explicit\"",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "The strategy for dismissing the overlay\nOptions are: `\"explicit\"`and `\"auto\"`. Defaults to \"explicit\"."
            },
            "attribute": "dismiss",
            "reflect": false,
            "defaultValue": "'explicit'"
        },
        "scrollable": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If false, the overlay will lock window scrolling when open"
            },
            "attribute": "scrollable",
            "reflect": false,
            "defaultValue": "false"
        },
        "nested": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Allows for targeted handling of nested overlays"
            },
            "attribute": "nested",
            "reflect": false,
            "defaultValue": "false"
        },
        "offset": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "The offset in `\"x, y\"` form without px"
            },
            "attribute": "offset",
            "reflect": false,
            "defaultValue": "'0, 0'"
        },
        "placement": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "OverlayPlacement",
                "resolved": "\"auto\" | \"auto-end\" | \"auto-start\" | \"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
                "references": {
                    "OverlayPlacement": {
                        "location": "import",
                        "path": "../../types/types"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "The preferred placement"
            },
            "attribute": "placement",
            "reflect": false,
            "defaultValue": "'top'"
        },
        "trapFocus": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If true, traps the focus inside the overlay. Making this opt-in for now, but may become the default."
            },
            "attribute": "trap-focus",
            "reflect": false,
            "defaultValue": "false"
        }
    }; }
    static get states() { return {
        "active": {},
        "showing": {}
    }; }
    static get events() { return [{
            "method": "anjWillOpen",
            "name": "anjWillOpen",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Fires before the overlay opens"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjDidOpen",
            "name": "anjDidOpen",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Fires after the open has completed"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjWillDismiss",
            "name": "anjWillDismiss",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Fires before the overlay dismisses"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjDidDismiss",
            "name": "anjDidDismiss",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Fires after the dismiss has completed"
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }]; }
    static get methods() { return {
        "open": {
            "complexType": {
                "signature": "(target: HTMLElement) => Promise<void>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "HTMLElement": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "Display the overlay",
                "tags": []
            }
        },
        "close": {
            "complexType": {
                "signature": "() => Promise<void>",
                "parameters": [],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "EventListenerOptions": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "Hide the overlay",
                "tags": []
            }
        },
        "popper": {
            "complexType": {
                "signature": "() => Promise<any>",
                "parameters": [],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<any>"
            },
            "docs": {
                "text": "Returns the popper instance",
                "tags": []
            }
        }
    }; }
    static get elementRef() { return "element"; }
    static get listeners() { return [{
            "name": "anjWillDismiss",
            "method": "onChildDismiss",
            "target": undefined,
            "capture": false,
            "passive": false
        }, {
            "name": "keydown",
            "method": "onKeyDown",
            "target": undefined,
            "capture": false,
            "passive": false
        }]; }
}
Overlay.openDelay = 100;
Overlay.closeDelay = 200;
