/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Host, readTask, } from "@stencil/core";
import { transformTag, h } from "../../utils/renderer";
let checkboxIds = 0;
/**
 * Checkboxes are used to let a user choose one or more values from a limited number of options.
 *
 * @status stable
 * @version 1.0.0
 *
 * @slot - used for more complex, label markup
 */
export class Checkbox {
    inputId = `nano-cb-${checkboxIds++}`;
    input;
    _slotWrapper;
    get slotWrapper() {
        return this._slotWrapper;
    }
    set slotWrapper(value) {
        this._slotWrapper = value;
        readTask(() => {
            this.hasLabel = !!value?.querySelectorAll('*').length || !!this.label;
        });
    }
    host;
    inputType = 'checkbox';
    hasLabel = true;
    /** @internal */
    hasFocus = false;
    /**
     * checked property that can be used to get/set the value. accepts only boolean values
     */
    checked = false;
    async handleCheckedChange() {
        if (!this.input)
            return;
        this.input.checked = this.checked;
        if (this.inputType === 'radio' &&
            this.name &&
            this.checked &&
            this.host.isConnected) {
            const form = this.host.closest('form');
            const root = this.host.getRootNode();
            let ctrls;
            if (form) {
                ctrls = Array.from(form.querySelectorAll(`${transformTag('nano-checkbox')}[name="${this.name}"]`));
            }
            else {
                ctrls = Array.from(root.querySelectorAll(`${transformTag('nano-checkbox')}[name="${this.name}"]`))?.filter((radio) => !radio.closest('form'));
            }
            ctrls.map((el) => {
                if (el !== this.host)
                    el.checked = false;
            });
        }
        this.nanoChange.emit({ value: this.value, checked: this.checked });
    }
    /**
     * If `true`, the user cannot interact with the checkbox.
     */
    disabled = false;
    /**
     * The value of a checkbox is analogous to the value of an `<input type='checkbox'>`,
     * it's only present when `checked` is true.
     */
    value = 'on';
    /**
     * The name of the control, which is submitted with the form data.
     */
    name;
    /**
     * Set to true to make the field required.
     */
    required = false;
    /**
     * Controls the underlying field type and style.
     */
    type = 'checkbox';
    typeChange() {
        if (['checkbox', 'switch', 'tag'].includes(this.type))
            this.inputType = 'checkbox';
        else
            this.inputType = 'radio';
    }
    /**
     * label property that can be used to set the label text. Alternatively you may use a label slot.
     */
    label;
    /**
     * Visually hide the label - but make it accessible.
     */
    hideLabel = false;
    /**
     * If `true`, the checkbox will visually appear as indeterminate (only relevant for type="checkbox")
     */
    indeterminate = false;
    handleIndeterminateChange() {
        this.checked = false;
        this.input.indeterminate = this.indeterminate;
    }
    /**
     * This will be true when the control is in an invalid state.
     * Validity is determined by the `required` prop. Or if custom validity message is set. @readonly
     */
    get invalid() {
        return this._invalid;
    }
    _invalid = false;
    /**
     * Current validation message - if any. @readonly
     */
    get validityMessage() {
        if (!this.input)
            return '';
        return this.input.validationMessage;
    }
    /**
     * The form element to associate the input with (its form owner). Must be the id of a form.
     */
    form;
    /**
     * Emited when the checkbox is toggled
     */
    nanoChange;
    /**
     * Emited when the checkbox is focused
     */
    nanoFocus;
    /**
     * Emited when the checkbox is blurred
     */
    nanoBlur;
    // public methods
    /**
     * Returns the native input control
     * @returns the native input control
     */
    async getInputElement() {
        if (this.input)
            return this.input;
    }
    /**
     * Get the current state of the control.
     * @param validateFirst - perform validation first before reporting
     * @returns `Promise<{ isValid: boolean, errorMessage: string }>`
     */
    async reportValidity(validateFirst = false) {
        if (validateFirst)
            this.input.reportValidity();
        this._invalid = !this.input.validity.valid;
        return {
            isValid: !this.invalid,
            errorMessage: this.input.validationMessage,
        };
    }
    /**
     * Sets a custom validation message.
     * If `message` is not empty, the field will be considered invalid. Use in conjunction with `nano-checkbox-group`
     */
    async setError(message, updateStatus = true) {
        if (!this.input)
            return;
        if (updateStatus)
            this._invalid = !!message.length;
        this.input.setCustomValidity(message);
    }
    /**
     * Sets focus on the checkbox.
     */
    async setFocus() {
        if (this.input) {
            this.input.focus();
        }
    }
    /**
     * Removes focus from the checkbox.
     */
    async removeFocus() {
        if (this.input) {
            this.input.blur();
        }
    }
    onHostClick(e) {
        // only click events coming from the host itself should toggle the checkbox
        // (ignore ones coming from the native input or label as this will cause a double toggle)
        if (this.host !== e.target && this.host.contains(e.target)) {
            return;
        }
        this.checked = !this.checked;
    }
    onReset(e) {
        const form = this.form
            ? document.querySelector('#' + this.form)
            : this.host.closest('form');
        if (!form || e.target !== this.host.closest('form'))
            return;
        this.checked = false;
    }
    // private handlers
    handleInvalid = (ev) => {
        this._invalid = !ev.target.validity.valid;
    };
    handleChange = (ev) => {
        this.checked = ev.target.checked;
        this.indeterminate = false;
    };
    handleFocus = () => {
        this.hasFocus = true;
        this.nanoFocus.emit();
    };
    handleBlur = () => {
        this.hasFocus = false;
        this.nanoBlur.emit();
    };
    /* Although many radio components can be 'checked',
    the underlying control may not be. Check */
    isRadioChecked() {
        requestAnimationFrame(() => (this.checked = this.input.checked));
    }
    // Stencil hooks
    componentWillLoad() {
        this.typeChange();
        this.hasLabel = !!this.host.querySelectorAll('*').length || !!this.label;
    }
    componentDidLoad() {
        this.input.indeterminate = this.indeterminate;
        this.isRadioChecked();
    }
    render() {
        const labelId = this.inputId + '-lbl';
        return (h(Host, { key: '4f3947cf07b077e7ae28748515f1e2997931906e' }, h("label", { key: '286a3e5f4c13c79883120aa20d6659a131f013f8', class: {
                nanocb: true,
                'nanocb--checked': this.checked,
                'nanocb--invalid': this.invalid,
                'nanocb--disabled': this.disabled,
                'nanocb--focused': this.hasFocus,
                'nanocb--indeterminate': this.indeterminate,
                ['nanocb__' + this.type]: true,
            }, htmlFor: this.inputId }, h("input", { key: 'efb1fbaef6017dba124b2919e7975722b371bb4e', type: this.inputType, name: this.name, form: this.form, required: this.required, checked: this.checked, disabled: this.disabled, value: this.value, "aria-labelledby": this.hasLabel ? labelId : undefined, onBlur: this.handleBlur, onFocus: this.handleFocus, onChange: this.handleChange, ref: (input) => (this.input = input), id: this.inputId, onInvalid: this.handleInvalid }), h("span", { key: '172e0eb05c62daef3f2cbb5eaebdebed2ba19f35', class: 'nanocb__input' }), this.hasLabel && (h("div", { key: '0662be227b2cb39c9c062b5b66da97f89bc7c94a', id: labelId, class: {
                nanocb__label: true,
                [`nanocb__label--${this.type}`]: true,
                'nanocb__label--hidden': this.hideLabel,
            } }, !!this.label?.length && h("span", { key: 'b4a03cea8fa9a0ac7781676a45af3dd7a826c2e0' }, this.label), h("span", { key: 'a6e9c1c733cd6d0285ed5bd9a22bb8f548ee9260', hidden: !!this.label?.length, ref: (s) => (this.slotWrapper = s) }, h("slot", { key: '3db145f44f978a49e445677a98b527f1b590beca' })))))));
    }
    static get is() { return "nano-checkbox"; }
    static get encapsulation() { return "scoped"; }
    static get originalStyleUrls() {
        return {
            "$": ["checkbox.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["checkbox.css"]
        };
    }
    static get properties() {
        return {
            "hasFocus": {
                "type": "boolean",
                "attribute": "has-focus",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "checked": {
                "type": "boolean",
                "attribute": "checked",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "checked property that can be used to get/set the value. accepts only boolean values"
                },
                "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": "If `true`, the user cannot interact with the checkbox."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "value": {
                "type": "string",
                "attribute": "value",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The value of a checkbox is analogous to the value of an `<input type='checkbox'>`,\nit's only present when `checked` is true."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "'on'"
            },
            "name": {
                "type": "string",
                "attribute": "name",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The name of the control, which is submitted with the form data."
                },
                "getter": false,
                "setter": false,
                "reflect": true
            },
            "required": {
                "type": "boolean",
                "attribute": "required",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set to true to make the field required."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "type": {
                "type": "string",
                "attribute": "type",
                "mutable": false,
                "complexType": {
                    "original": "| 'radio'\n    | 'checkbox'\n    | 'tag'\n    | 'segment'\n    | 'switch'",
                    "resolved": "\"checkbox\" | \"radio\" | \"segment\" | \"switch\" | \"tag\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Controls the underlying field type and style."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "'checkbox'"
            },
            "label": {
                "type": "string",
                "attribute": "label",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "label property that can be used to set the label text. Alternatively you may use a label slot."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "hideLabel": {
                "type": "boolean",
                "attribute": "hide-label",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Visually hide the label - but make it accessible."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "indeterminate": {
                "type": "boolean",
                "attribute": "indeterminate",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the checkbox will visually appear as indeterminate (only relevant for type=\"checkbox\")"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "invalid": {
                "type": "boolean",
                "attribute": "invalid",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "readonly",
                            "text": undefined
                        }],
                    "text": "This will be true when the control is in an invalid state.\nValidity is determined by the `required` prop. Or if custom validity message is set."
                },
                "getter": true,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "validityMessage": {
                "type": "string",
                "attribute": "validity-message",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "readonly",
                            "text": undefined
                        }],
                    "text": "Current validation message - if any."
                },
                "getter": true,
                "setter": false,
                "reflect": false
            },
            "form": {
                "type": "string",
                "attribute": "form",
                "mutable": false,
                "complexType": {
                    "original": "string | null",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The form element to associate the input with (its form owner). Must be the id of a form."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            }
        };
    }
    static get states() {
        return {
            "inputType": {},
            "hasLabel": {},
            "_invalid": {}
        };
    }
    static get events() {
        return [{
                "method": "nanoChange",
                "name": "nanoChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emited when the checkbox is toggled"
                },
                "complexType": {
                    "original": "CheckboxChangeEventDetail",
                    "resolved": "CheckboxChangeEventDetail",
                    "references": {
                        "CheckboxChangeEventDetail": {
                            "location": "import",
                            "path": "./checkbox-interface",
                            "id": "src/components/checkbox/checkbox-interface.ts::CheckboxChangeEventDetail"
                        }
                    }
                }
            }, {
                "method": "nanoFocus",
                "name": "nanoFocus",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emited when the checkbox is focused"
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoBlur",
                "name": "nanoBlur",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emited when the checkbox is blurred"
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }];
    }
    static get methods() {
        return {
            "getInputElement": {
                "complexType": {
                    "signature": "() => Promise<HTMLInputElement>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "HTMLInputElement": {
                            "location": "global",
                            "id": "global::HTMLInputElement"
                        }
                    },
                    "return": "Promise<HTMLInputElement>"
                },
                "docs": {
                    "text": "Returns the native input control",
                    "tags": [{
                            "name": "returns",
                            "text": "the native input control"
                        }]
                }
            },
            "reportValidity": {
                "complexType": {
                    "signature": "(validateFirst?: boolean) => Promise<ControlValidity>",
                    "parameters": [{
                            "name": "validateFirst",
                            "type": "boolean",
                            "docs": "- perform validation first before reporting"
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "ControlValidity": {
                            "location": "import",
                            "path": "../../types/shared",
                            "id": "src/types/shared.ts::ControlValidity"
                        }
                    },
                    "return": "Promise<ControlValidity>"
                },
                "docs": {
                    "text": "Get the current state of the control.",
                    "tags": [{
                            "name": "param",
                            "text": "validateFirst - perform validation first before reporting"
                        }, {
                            "name": "returns",
                            "text": "`Promise<{ isValid: boolean, errorMessage: string }>`"
                        }]
                }
            },
            "setError": {
                "complexType": {
                    "signature": "(message: string, updateStatus?: boolean) => Promise<void>",
                    "parameters": [{
                            "name": "message",
                            "type": "string",
                            "docs": ""
                        }, {
                            "name": "updateStatus",
                            "type": "boolean",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Sets a custom validation message.\nIf `message` is not empty, the field will be considered invalid. Use in conjunction with `nano-checkbox-group`",
                    "tags": []
                }
            },
            "setFocus": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Sets focus on the checkbox.",
                    "tags": []
                }
            },
            "removeFocus": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Removes focus from the checkbox.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "checked",
                "methodName": "handleCheckedChange"
            }, {
                "propName": "type",
                "methodName": "typeChange"
            }, {
                "propName": "indeterminate",
                "methodName": "handleIndeterminateChange"
            }];
    }
    static get listeners() {
        return [{
                "name": "click",
                "method": "onHostClick",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "reset",
                "method": "onReset",
                "target": "body",
                "capture": false,
                "passive": false
            }];
    }
}
