// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { property } from 'lit/decorators/property.js';
import { Attribute } from '../../Controls/Decorators/AttributeDecorator';
/**
 * @public
 */
// eslint-disable-next-line @typescript-eslint/naming-convention
export const FormAssociated = (base) => {
    class FormAssociatedElement extends base {
        // #region Fields
        _internals;
        // #endregion
        // #region Ctor
        /**
         * Constructs a new instance of the `FormAssociatedElement` class.
         *
         * @public
         */
        constructor(...args) {
            super(args);
        }
        // #endregion
        // #region Properties
        /**
         * Returns the indecator that the element is participating in form association.
         *
         * @public
         * @static
         * @readonly
         */
        static get formAssociated() {
            return true;
        }
        /**
         * Gets or sets the `name` property.
         *
         * @public
         * @attr
         */
        get name() {
            return this.getAttribute('name') ?? '';
        }
        set name(value) {
            this.setAttribute('name', value);
            // no need to call `requestUpdate()` since it's called synchronously in `attributeChangedCallback()`.
        }
        /**
         * Gets or sets the `disabled` property.
         *
         * @public
         */
        get disabled() {
            return this.hasAttribute('disabled');
        }
        set disabled(disabled) {
            this.toggleAttribute('disabled', disabled);
            // no need to call `requestUpdate()` since it's called synchronously in `attributeChangedCallback()`.
        }
        /**
         * Returns the `internals` property.
         *
         * @public
         * @readonly
         */
        get internals() {
            if (!this.isConnected) {
                const exceptionMessage = 'ElementInternals is not available until the element is connected to the document.';
                throw new Error(exceptionMessage);
            }
            if (!this._internals) {
                this._internals = this.attachInternals();
            }
            return this._internals;
        }
        /**
         * Returns the `internals` property.
         *
         * @public
         * @readonly
         */
        get form() {
            return this.internals.form;
        }
        /**
         * Returns the `internals` property.
         *
         * @public
         * @readonly
         */
        get labels() {
            return this.internals.labels;
        }
        // #endregion
        // #region Methods
        /**
         * @public
         * @override
         */
        attributeChangedCallback(name, old, value) {
            // Manually `requestUpdate()` for `name` and `disabled` when their attribute or property changes.
            // The properties update their attributes, so this callback is invoked
            // immediately when the properties are set. We call `requestUpdate()` here
            // instead of letting Lit set the properties from the attribute change.
            // That would cause the properties to re-set the attribute and invoke this
            // callback again in a loop. This leads to stale state when Lit tries to
            // determine if a property changed or not.
            if (name === 'name' || name === 'disabled') {
                // Disabled's value is only false if the attribute is missing and null.
                const oldValue = name === 'disabled' ? old !== null : old;
                // Trigger a lit update when the attribute changes.
                this.requestUpdate(name, oldValue);
                return;
            }
            super.attributeChangedCallback(name, old, value);
        }
        /**
         * @public
         * @override
         */
        requestUpdate(name, oldValue, options) {
            super.requestUpdate(name, oldValue, options);
            // If any properties change, update the form value, which may have changed
            // as well.
            // Update the form value synchronously in `requestUpdate()` rather than
            // `update()` or `updated()`, which are async. This is necessary to ensure
            // that form data is updated in time for synchronous event listeners.
            if (this.isConnected) {
                this.internals.setFormValue(this.getFormValue(), this.getFormState());
            }
        }
        /**
         * @public
         */
        getFormState() {
            return this.getFormValue();
        }
        /**
         * @public
         */
        formDisabledCallback(disabled) {
            this.disabled = disabled;
        }
    }
    __decorate([
        Attribute({ type: String }),
        __metadata("design:type", String),
        __metadata("design:paramtypes", [String])
    ], FormAssociatedElement.prototype, "name", null);
    __decorate([
        property({
            type: Boolean,
            noAccessor: true
        }),
        __metadata("design:type", Boolean),
        __metadata("design:paramtypes", [Boolean])
    ], FormAssociatedElement.prototype, "disabled", null);
    return FormAssociatedElement;
};
//# sourceMappingURL=FormAssociated.js.map