/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Build, Host, } from "@stencil/core";
import { h } from "../../utils/renderer";
import { HasSlotController } from "../../utils/slot";
/**
 * Details show a brief summary and on interaction expand to show additional content.
 *
 * @version 1.0
 * @status stable
 *
 * @slot - content that will be hidden / revealed
 * @slot icon-start - used for icons at the start of the handle. Rotates on open by default; use ::part selector to override.
 * @slot label - can be used when you wish to insert complex label markup
 * @slot icon-end - used for icons at the end of the handle.
 * Alternatively use `icon-expand` / `icon-collapse` slots. Rotates on open by default; use ::part selector to override.
 * @slot icon-expand - used for icons at the end of the handle when closed. Rotates on open by default; use ::part selector to override.
 * @slot icon-collapse - used for icons at the end of the handle when open. Rotates on open by default; use ::part selector to override.
 *
 * @part base - the root `details` element
 * @part header - the main `summary` ui control
 * @part label - the text wrapper of the ui control
 * @part icon - the wrapper around both start and end icons
 * @part icon--start - the icon wrapper at the start of the ui control
 * @part icon--end - the icon wrapper at the end of the ui control
 * @part body - the main body block
 * @part content-wrapper - the wrapper around the content
 * @part content - the main content
 */
export class NanoDetails {
    mo;
    stateChanging = false;
    slotCtrl = new HasSlotController(this, 'icon-start', 'icon-end', 'icon-collapse', 'icon-expand');
    detailsEl;
    headerEl;
    _bodyEl;
    get bodyEl() {
        return this._bodyEl;
    }
    set bodyEl(el) {
        if (this.bodyEl && this.bodyEl === this._bodyEl)
            return;
        if (this.bodyEl) {
            this.bodyEl.removeEventListener('transitionend', this.handleTransitionEnd);
        }
        el.addEventListener('transitionend', this.handleTransitionEnd);
        this._bodyEl = el;
    }
    /** Summary / handle text. Use the `label` slot for HTML markup */
    label = '';
    /** Should item be open on load */
    open = false;
    /** Disables the details so it can't be toggled. */
    disabled = false;
    /** The size of the details. Primarily controls the trigger element and overall padding. */
    size = 'medium';
    /**
     * Emitted when the component opens.
     * Note: when wrapped in an accordion this event will not propagate. Use `nanoToggle` events instead.
     */
    nanoOpen;
    /**
     * Emitted when the component closes.
     * Note: when wrapped in an accordion this event will not propagate. Use `nanoToggle` events instead.
     */
    nanoClose;
    /** Emitted after the details opens and all transitions are complete. */
    nanoAfterOpen;
    /** Emitted after the details closes and all transitions are complete. */
    nanoAfterClose;
    toggleClick() {
        this.stateChanging = true;
        if (this.open)
            this.show();
        else
            this.hide();
    }
    onKeyDown = (e) => {
        if (this.stateChanging || this.disabled)
            return;
        switch (e.key) {
            case 'Enter':
            case ' ':
                e.preventDefault();
                this.open = !this.open;
                break;
            case 'ArrowUp':
            case 'ArrowLeft':
                e.preventDefault();
                this.open = false;
                break;
            case 'ArrowDown':
            case 'ArrowRight':
                e.preventDefault();
                this.open = true;
                break;
        }
    };
    onMouseDown = (e) => {
        e.preventDefault();
        this.headerEl.focus();
        if (this.stateChanging || this.disabled)
            return;
        this.open = !this.open;
    };
    handleTransitionEnd = (e) => {
        if (e.propertyName !== 'opacity' ||
            !e.composedPath().find((node) => node === this.bodyEl))
            return;
        if (this.open) {
            this.nanoAfterOpen.emit();
            requestAnimationFrame(() => (this.stateChanging = false));
        }
        else {
            this.detailsEl.open = false;
            this.nanoAfterClose.emit();
            requestAnimationFrame(() => (this.stateChanging = false));
        }
    };
    hide() {
        const nanoClose = this.nanoClose.emit(this.open);
        if (nanoClose.defaultPrevented) {
            this.open = true;
            this.detailsEl.open = true;
            return;
        }
    }
    show() {
        const nanoOpen = this.nanoOpen.emit();
        this.detailsEl.open = true;
        if (nanoOpen.defaultPrevented) {
            this.open = false;
            this.detailsEl.open = false;
            return;
        }
    }
    attachMo() {
        if (this.mo || !this.detailsEl || !Build.isBrowser)
            return;
        this.mo = new MutationObserver((changes) => {
            if (this.stateChanging)
                return;
            for (const change of changes) {
                if (change.type === 'attributes' &&
                    change.attributeName === 'open' &&
                    !this.disabled) {
                    this.open = this.detailsEl.open;
                }
            }
        });
        this.mo.observe(this.detailsEl, { attributes: true });
    }
    componentDidLoad() {
        if (this.open)
            this.detailsEl.setAttribute('open', 'true');
        this.attachMo();
    }
    connectedCallback() {
        if (this.bodyEl) {
            this.bodyEl.addEventListener('transitionend', this.handleTransitionEnd);
        }
        this.attachMo();
    }
    disconnectedCallback() {
        if (this.mo) {
            this.mo.disconnect();
            this.mo = undefined;
        }
        if (this.bodyEl) {
            this.bodyEl.removeEventListener('transitionend', this.handleTransitionEnd);
        }
    }
    render() {
        return (h(Host, { key: '1cbedc078a3390a3ad82b99ac0f37e8ea0f8d480', class: "nano-details" }, h("details", { key: '22659218ba7d1ec936523ff33c7ed2a1efb2af74', part: "base", ref: (d) => (this.detailsEl = d), class: {
                details: true,
                disabled: this.disabled,
            } }, h("summary", { key: '3a7cd64e7d8e2b5235b7c0f7d58c434cb2a52469', part: "header", "aria-controls": "content", "aria-expanded": this.open ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', tabindex: this.disabled ? '-1' : '0', id: "header", role: "button", class: "header", ref: (s) => (this.headerEl = s), onKeyDown: this.onKeyDown, onClick: this.onMouseDown }, this.slotCtrl.has('icon-start') && (h("span", { key: '4a8de08dca34823e162019e2d4dddef2ed2c123d', part: "icon icon--start", class: "icon icon--start" }, h("slot", { key: 'cf6ea31f1685afa4bde64a6cbdef43cb0d0a053a', name: "icon-start" }))), h("div", { key: '0b11c544cfbb5852dfeae66b482154f1780a2569', part: "label", class: "label" }, this.label ? this.label : h("slot", { name: "label" })), h("span", { key: '5470af7891318c513870c473a8ad1f501174f51b', part: "icon icon--end", class: "icon icon--end" }, this.open ? (h("slot", { name: "icon-collapse" })) : (h("slot", { name: "icon-expand" })), h("slot", { key: '45960716eeec5d5ad08b63fd536608fcd33ab8f2', name: "icon-end" }, !this.slotCtrl.has('icon-start') &&
            !this.slotCtrl.has('icon-end') &&
            !this.slotCtrl.has('icon-expand') &&
            !this.slotCtrl.has('icon-collapse') && (h("nano-icon", { key: '5357b61cb197dc4a1ceccf415a34defdfeb6b290', class: "default-icon", name: "light/chevron-down" }))))), h("div", { key: 'aa7f850c8415c2cd40fd7a965fba8eb98fca62b5', part: "body", class: "body", ref: (div) => (this.bodyEl = div), role: "region", "aria-labelledby": "header" }, h("div", { key: 'e98e6a68e4c15525b4377d4229fb4a1855650732', part: "content-wrapper", class: "content-wrapper" }, h("div", { key: '6710e302f7e2a5987ccd6703ea3c6cc0bf705d23', part: "content", class: "content", id: "content" }, h("slot", { key: '891525e66383979e621787f766bcfbcea78a9630' })))))));
    }
    static get is() { return "nano-details"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["details.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["details.css"]
        };
    }
    static get properties() {
        return {
            "label": {
                "type": "string",
                "attribute": "label",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Summary / handle text. Use the `label` slot for HTML markup"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "''"
            },
            "open": {
                "type": "boolean",
                "attribute": "open",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Should item be open on load"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "disabled": {
                "type": "boolean",
                "attribute": "disabled",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Disables the details so it can't be toggled."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "size": {
                "type": "string",
                "attribute": "size",
                "mutable": false,
                "complexType": {
                    "original": "'small' | 'medium' | 'large'",
                    "resolved": "\"large\" | \"medium\" | \"small\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The size of the details. Primarily controls the trigger element and overall padding."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "'medium'"
            }
        };
    }
    static get events() {
        return [{
                "method": "nanoOpen",
                "name": "nanoOpen",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the component opens.\nNote: when wrapped in an accordion this event will not propagate. Use `nanoToggle` events instead."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoClose",
                "name": "nanoClose",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the component closes.\nNote: when wrapped in an accordion this event will not propagate. Use `nanoToggle` events instead."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoAfterOpen",
                "name": "nanoAfterOpen",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the details opens and all transitions are complete."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoAfterClose",
                "name": "nanoAfterClose",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the details closes and all transitions are complete."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }];
    }
    static get watchers() {
        return [{
                "propName": "open",
                "methodName": "toggleClick"
            }];
    }
}
