/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { __decorate } from "tslib";
import { CustomElement, ensureChildren, toggleAttribute } from '@tylertech/forge-core';
import { BaseComponent } from '../core/base/base-component';
import { ALLOWED_CHILDREN, BUTTON_CONSTANTS } from './button-constants';
import { createUserInteractionListener } from '../core/utils/utils';
import { ForgeRipple } from '../ripple';
/**
 * The custom element class behind the `<forge-button>` element.
 *
 * @tag forge-button
 */
let ButtonComponent = class ButtonComponent extends BaseComponent {
    constructor() {
        super();
    }
    static get observedAttributes() {
        return [BUTTON_CONSTANTS.attributes.TYPE];
    }
    connectedCallback() {
        if (this.children.length) {
            this._initialize();
        }
        else {
            ensureChildren(this).then(() => this._initialize());
        }
    }
    attributeChangedCallback(name, oldValue, newValue) {
        switch (name) {
            case BUTTON_CONSTANTS.attributes.TYPE:
                this.type = newValue;
                break;
        }
    }
    disconnectedCallback() {
        if (typeof this._destroyUserInteractionListener === 'function') {
            this._destroyUserInteractionListener();
            this._destroyUserInteractionListener = undefined;
        }
        if (this._rippleInstance) {
            this._rippleInstance.destroy();
        }
        if (this._mutationObserver) {
            this._mutationObserver.disconnect();
        }
        if (this._buttonAttrMutationObserver) {
            this._buttonAttrMutationObserver.disconnect();
        }
    }
    /**
     * Sets the type of button decoration.
     * Possible values are: raised, elevated, outlined, and dense.
     * Can be combined as: outlined-dense.
     */
    get type() {
        return this._type;
    }
    set type(value) {
        if (this._type !== value) {
            this._type = value;
            this._applyType(value);
            this.setAttribute(BUTTON_CONSTANTS.attributes.TYPE, this._type);
        }
    }
    _applyType(type) {
        if (this._buttonElement) {
            this._buttonElement.classList.remove(BUTTON_CONSTANTS.classes.BUTTON_RAISED);
            this._buttonElement.classList.remove(BUTTON_CONSTANTS.classes.BUTTON_UNELEVATED);
            this._buttonElement.classList.remove(BUTTON_CONSTANTS.classes.BUTTON_OUTLINED);
            this._buttonElement.classList.remove(BUTTON_CONSTANTS.classes.BUTTON_DENSE);
            if (type.includes('raised')) {
                this._buttonElement.classList.add(BUTTON_CONSTANTS.classes.BUTTON_RAISED);
            }
            if (type.includes('unelevated')) {
                this._buttonElement.classList.add(BUTTON_CONSTANTS.classes.BUTTON_UNELEVATED);
            }
            if (type.includes('outlined')) {
                this._buttonElement.classList.add(BUTTON_CONSTANTS.classes.BUTTON_OUTLINED);
            }
            if (type.includes('dense')) {
                this._buttonElement.classList.add(BUTTON_CONSTANTS.classes.BUTTON_DENSE);
            }
        }
    }
    _initialize() {
        this._initializeButton();
        this._initializeMutationObserver();
    }
    _initializeButton() {
        this._buttonElement = this.querySelector(BUTTON_CONSTANTS.selectors.BUTTON);
        if (!this._buttonElement) {
            return;
        }
        if (this.hasAttribute(BUTTON_CONSTANTS.attributes.TYPE)) {
            this._type = this.getAttribute(BUTTON_CONSTANTS.attributes.TYPE);
            this._applyType(this._type);
        }
        this._buttonElement.classList.add(BUTTON_CONSTANTS.classes.BUTTON);
        this._syncDisabledState();
        this._initializeButtonChildren();
        // We wait to initialize the ripple instance until the user interacts with the component to avoid unnecessary performance overhead
        this._deferRippleInitialization();
    }
    async _deferRippleInitialization() {
        if (typeof this._destroyUserInteractionListener === 'function') {
            this._destroyUserInteractionListener();
        }
        const { userInteraction, destroy } = createUserInteractionListener(this._buttonElement);
        this._destroyUserInteractionListener = destroy;
        const { type } = await userInteraction;
        this._destroyUserInteractionListener = undefined;
        if (!this.isConnected) {
            return;
        }
        this._rippleInstance = this._createRipple();
        if (type === 'focusin') {
            this._rippleInstance.handleFocus();
        }
    }
    _createRipple() {
        if (this._rippleInstance) {
            this._rippleInstance.destroy();
        }
        return new ForgeRipple(this._buttonElement);
    }
    _initializeButtonChildren() {
        if (!this._buttonElement.querySelector(BUTTON_CONSTANTS.selectors.RIPPLE)) {
            const rippleElement = document.createElement('span');
            rippleElement.classList.add(BUTTON_CONSTANTS.classes.RIPPLE);
            this._buttonElement.appendChild(rippleElement);
        }
        const labelElement = this.querySelector(BUTTON_CONSTANTS.selectors.LABEL);
        if (labelElement) {
            labelElement.classList.add(BUTTON_CONSTANTS.classes.LABEL);
        }
        const iconElements = Array.from(this.querySelectorAll(BUTTON_CONSTANTS.selectors.ICON));
        iconElements.forEach(iconElement => {
            iconElement.classList.add(BUTTON_CONSTANTS.classes.ICON);
            if (!iconElement.hasAttribute('aria-hidden')) {
                iconElement.setAttribute('aria-hidden', 'true');
            }
        });
    }
    _initializeMutationObserver() {
        if (!this._mutationObserver) {
            const config = { childList: true, subtree: true };
            const callback = mutationList => {
                if (this._buttonWasAdded(mutationList)) {
                    this._initializeButton();
                }
                else if (mutationList.some(mutation => mutation.addedNodes.length)) {
                    this._initializeButtonChildren();
                }
            };
            this._mutationObserver = new MutationObserver(callback);
            this._mutationObserver.observe(this, config);
            if (this._buttonElement) {
                // Watch attributes on the `<button>` element
                this._buttonAttrMutationObserver = new MutationObserver(mutationList => {
                    if (mutationList.some(mutation => mutation.attributeName === 'disabled')) {
                        this._syncDisabledState();
                    }
                });
                this._buttonAttrMutationObserver.observe(this._buttonElement, { attributes: true, attributeFilter: ['disabled'] });
            }
        }
    }
    _buttonWasAdded(mutationList) {
        return mutationList.some(mutation => {
            return Array.from(mutation.addedNodes)
                .some(node => ALLOWED_CHILDREN.includes(node.nodeName.toLowerCase()));
        });
    }
    _syncDisabledState() {
        toggleAttribute(this, this._buttonElement.disabled, BUTTON_CONSTANTS.attributes.DISABLED);
    }
};
ButtonComponent = __decorate([
    CustomElement({
        name: BUTTON_CONSTANTS.elementName
    })
], ButtonComponent);
export { ButtonComponent };
