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;
};
import { html } from 'lit';
import { property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { BaseFormAssociatedElement } from '../radio/form-associated-element';
import { RequiredValidator } from '../radio/required-validator';
import { HasSlotController } from '../radio/slot';
import { watch } from '../radio/watch';
import '@warp-ds/icons/elements/check-16';
import { reset } from '../styles';
import { toggleStyles } from '../toggle-styles';
export class WCheckbox extends BaseFormAssociatedElement {
    constructor() {
        super(...arguments);
        this.hasSlotController = new HasSlotController(this, 'hint');
        this.title = ''; // make reactive to pass through
        /** The name of the checkbox, submitted as a name/value pair with form data. */
        this.name = '';
        this._value = this.getAttribute('value') ?? null;
        /** The checkbox's size. */
        this.size = 'medium';
        /** Disables the checkbox. */
        this.disabled = false;
        /**
         * Draws the checkbox in an indeterminate state. This is usually applied to checkboxes that represents a "select
         * all/none" behavior when associated checkboxes have a mix of checked and unchecked states.
         */
        this.indeterminate = false;
        /** Draws the checkbox in a checked state. */
        this.checked = this.hasAttribute('checked');
        /** The default value of the form control. Primarily used for resetting the form control. */
        this.defaultChecked = this.hasAttribute('checked');
        /**
         * By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you
         * to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
         * the same document or shadow root for this to work.
         */
        this.form = null;
        /** Makes the checkbox a required field. */
        this.required = false;
        /** The checkbox's hint. If you need to display HTML, use the `hint` slot instead. */
        this.hint = '';
    }
    static { this.css = [reset, toggleStyles]; }
    static { this.shadowRootOptions = { ...BaseFormAssociatedElement.shadowRootOptions, delegatesFocus: true }; }
    static get validators() {
        const validators = [
            RequiredValidator({
                validationProperty: 'checked',
                // Use a checkbox so we get "free" translation strings.
                validationElement: Object.assign(document.createElement('input'), {
                    type: 'checkbox',
                    required: true,
                }),
            }),
        ];
        return [...super.validators, ...validators];
    }
    /** The value of the checkbox, submitted as a name/value pair with form data. */
    get value() {
        return this._value ?? 'on';
    }
    set value(val) {
        this._value = val;
    }
    connectedCallback() {
        super.connectedCallback();
        this.setInitialAttributes();
    }
    // NB: not from WA, this eases shared-styling
    setInitialAttributes() {
        this.setAttribute('type', 'checkbox');
    }
    handleClick() {
        this.hasInteracted = true;
        this.checked = !this.checked;
        this.indeterminate = false;
        this.updateComplete.then(() => {
            this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
        });
    }
    handleDefaultCheckedChange() {
        if (!this.hasInteracted && this.checked !== this.defaultChecked) {
            this.checked = this.defaultChecked;
            this.handleValueOrCheckedChange();
        }
    }
    handleValueOrCheckedChange() {
        // These @watch() commands seem to override the base element checks for changes, so we need to setValue for the form and and updateValidity()
        this.setValue(this.checked ? this.value : null, this._value);
        this.updateValidity();
    }
    handleStateChange() {
        if (this.hasUpdated) {
            this.input.checked = this.checked; // force a sync update
            this.input.indeterminate = this.indeterminate; // force a sync update
        }
        this.customStates.set('checked', this.checked);
        this.customStates.set('indeterminate', this.indeterminate);
        this.updateValidity();
    }
    handleDisabledChange() {
        this.customStates.set('disabled', this.disabled);
    }
    willUpdate(changedProperties) {
        super.willUpdate(changedProperties);
        if (changedProperties.has('defaultChecked')) {
            if (!this.hasInteracted) {
                this.checked = this.defaultChecked;
            }
        }
        if (changedProperties.has('value') || changedProperties.has('checked')) {
            this.handleValueOrCheckedChange();
        }
    }
    formResetCallback() {
        // Evaluate checked before the super call because of our watcher on value.
        this.checked = this.defaultChecked;
        super.formResetCallback();
        this.handleValueOrCheckedChange();
    }
    /** Simulates a click on the checkbox. */
    click() {
        this.input.click();
    }
    /** Sets focus on the checkbox. */
    focus(options) {
        this.input.focus(options);
    }
    /** Removes focus from the checkbox. */
    blur() {
        this.input.blur();
    }
    render() {
        const hasHintSlot = this.hasSlotController.test('hint');
        const hasHint = this.hint ? true : !!hasHintSlot;
        const isIndeterminate = !this.checked && this.indeterminate;
        return html `
      <label part="base" class="wrapper">
        <span part="control" class="checkbox control">
          <input
            class="input hide-toggle"
            type="checkbox"
            title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
            name=${this.name}
            value=${ifDefined(this._value)}
            .indeterminate=${live(this.indeterminate)}
            .checked=${live(this.checked)}
            .disabled=${this.disabled}
            .required=${this.required}
            aria-checked=${this.checked ? 'true' : 'false'}
            aria-describedby="hint"
            @click=${this.handleClick} />
          ${isIndeterminate ? '–' : ''}
        </span>

        <slot part="label"></slot>
      </label>

      <slot id="hint" part="hint" name="hint" aria-hidden=${hasHint ? 'false' : 'true'} class="${classMap({ 'has-slotted': hasHint })}">
        ${this.hint}
      </slot>
    `;
    }
}
__decorate([
    query('input[type="checkbox"]')
], WCheckbox.prototype, "input", void 0);
__decorate([
    property()
], WCheckbox.prototype, "title", void 0);
__decorate([
    property({ reflect: true })
], WCheckbox.prototype, "name", void 0);
__decorate([
    property({ reflect: true })
], WCheckbox.prototype, "value", null);
__decorate([
    property({ reflect: true })
], WCheckbox.prototype, "size", void 0);
__decorate([
    property({ type: Boolean })
], WCheckbox.prototype, "disabled", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], WCheckbox.prototype, "indeterminate", void 0);
__decorate([
    property({ type: Boolean, attribute: false })
], WCheckbox.prototype, "checked", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'checked' })
], WCheckbox.prototype, "defaultChecked", void 0);
__decorate([
    property({ reflect: true })
], WCheckbox.prototype, "form", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], WCheckbox.prototype, "required", void 0);
__decorate([
    property()
], WCheckbox.prototype, "hint", void 0);
__decorate([
    watch('defaultChecked')
], WCheckbox.prototype, "handleDefaultCheckedChange", null);
__decorate([
    watch(['checked', 'indeterminate'])
], WCheckbox.prototype, "handleStateChange", null);
__decorate([
    watch('disabled')
], WCheckbox.prototype, "handleDisabledChange", null);
if (!customElements.get('w-checkbox')) {
    customElements.define('w-checkbox', WCheckbox);
}
