import { h, Host } from "@stencil/core";
import isNil from "lodash.isnil";
import { ariaBooleanToString } from "../../utils/aria";
import { BEM } from "../../utils/bem";
import { defaultBalAriaForm } from "../../utils/form";
import { stopEventBubbling } from "../../utils/form-input";
import { debounceEvent } from "../../utils/helpers";
export class InputSlider {
    constructor() {
        this.inputId = `bal-input-slider-${inputSliderIds++}`;
        this.didInit = false;
        this.hasFocus = false;
        this.initialValue = '';
        this.ariaForm = defaultBalAriaForm;
        /**
         * The name of the control, which is submitted with the form data.
         */
        this.name = this.inputId;
        /**
         * The step size. 0 means no steps.
         */
        this.step = 0;
        /**
         * Min value of the model.
         */
        this.min = 0;
        /**
         * Max value of the model.
         */
        this.max = 100;
        /**
         * If `true` the component gets a invalid style.
         */
        this.invalid = false;
        /**
         * The tabindex of the control.
         */
        this.balTabindex = 0;
        /**
         * If `true`, the element is not mutable, focusable, or even submitted with the form. The user can neither edit nor focus on the control, nor its form control descendants.
         */
        this.disabled = false;
        /**
         * If `true` the element can not mutated, meaning the user can not edit the control.
         */
        this.readonly = false;
        /**
         * If `true`, the user must fill in a value before submitting a form.
         */
        this.required = false;
        /**
         * If `true`, small ticks for the steps are shown.
         */
        this.hasTicks = false;
        /**
         * Set the amount of time, in milliseconds, to wait to trigger the `balChange` event after each keystroke. This also impacts form bindings such as `ngModel` or `v-model`.
         */
        this.debounce = 0;
        /**
         * The value of the input.
         */
        this.value = '';
        /**
         * If `true`, in Angular reactive forms the control will not be set invalid
         */
        this.autoInvalidOff = false;
        this.onInput = (ev) => {
            const input = ev.target;
            if (input) {
                this.value = input.value || '';
            }
            this.balInput.emit(this.value);
        };
        this.handleClick = (ev) => {
            if (this.disabled || this.readonly) {
                ev.preventDefault();
                ev.stopPropagation();
            }
        };
        this.onFocus = (ev) => {
            this.hasFocus = true;
            this.balFocus.emit(ev);
        };
        this.onBlur = (ev) => {
            this.hasFocus = false;
            this.balBlur.emit(ev);
            this.balChange.emit(this.value);
        };
    }
    debounceChanged() {
        this.balChange = debounceEvent(this.balChange, this.debounce);
    }
    listenOnClick(ev) {
        if ((this.disabled || this.readonly) && ev.target && ev.target === this.el) {
            stopEventBubbling(ev);
        }
    }
    resetHandler(ev) {
        const formElement = ev.target;
        if (formElement === null || formElement === void 0 ? void 0 : formElement.contains(this.el)) {
            this.value = this.initialValue;
            clearTimeout(this.resetHandlerTimer);
            this.resetHandlerTimer = setTimeout(() => {
                if (this.nativeInput) {
                    this.nativeInput.value = this.initialValue;
                }
            }, 0);
        }
    }
    /**
     * Update the native input element when the value changes
     */
    valueChanged(newValue, oldValue) {
        if (this.didInit && !this.hasFocus && newValue !== oldValue) {
            this.balChange.emit(this.value);
        }
    }
    connectedCallback() {
        this.debounceChanged();
        this.initialValue = this.value;
    }
    componentDidLoad() {
        this.didInit = true;
        if (!isNil(this.value) && this.value !== '') {
            this.valueChanged(this.value, undefined);
        }
    }
    /**
     * Sets focus on the native `input` in `bal-input`. Use this method instead of the global
     * `input.focus()`.
     */
    async setFocus() {
        clearTimeout(this.setFocusTimer);
        this.setFocusTimer = setTimeout(() => {
            if (this.nativeInput) {
                this.nativeInput.focus();
            }
        });
    }
    /**
     * Returns the native `<input>` element used under the hood.
     */
    getInputElement() {
        return Promise.resolve(this.nativeInput);
    }
    /**
     * @internal
     */
    async setAriaForm(ariaForm) {
        this.ariaForm = Object.assign({}, ariaForm);
    }
    get numberOfSteps() {
        const max = this.max - this.min;
        if (this.step <= 0 || this.step >= max) {
            return 0;
        }
        return ~~(max / this.step) + 1;
    }
    cssWidth(isUpper = false) {
        const a = this.value === '' ? 0 : Math.round(Number(this.value) / this.step) * this.step;
        const b = (100 / this.max) * a;
        if (!isUpper) {
            return `${100 - b}%`;
        }
        return `${b}%`;
    }
    getNumberOfSteps() {
        const steps = [];
        for (let step = 0; step < this.numberOfSteps; step++) {
            steps.push(step);
        }
        return steps;
    }
    render() {
        const block = BEM.block('input-slider');
        const backgroundEl = block.element('background');
        const backgroundUpperEl = backgroundEl.element('upper');
        const backgroundUpperInnerEl = backgroundUpperEl.element('inner');
        const backgroundLowerEl = backgroundEl.element('lower');
        const backgroundLowerInnerEl = backgroundLowerEl.element('inner');
        const inputEl = block.element('input');
        const inputNativeEl = inputEl.element('native');
        const inputValueEl = inputEl.element('value');
        const inputValueLeftEl = inputValueEl.modifier('left');
        const inputValueRightEl = inputValueEl.modifier('right');
        const stepsEl = block.element('steps');
        const stepsItemEl = stepsEl.element('item');
        return (h(Host, { key: 'ad6fdbbb33727000cb6ff16e7daf168c6d35602b', class: Object.assign(Object.assign({}, block.class()), block.modifier('disabled').class(this.disabled || this.readonly)), onClick: this.handleClick, "aria-disabled": ariaBooleanToString(this.disabled || this.readonly) }, h("div", { key: '0c3ec1cb883d285ef62d06c47b9a8ead7198e235', class: Object.assign(Object.assign({}, backgroundEl.class()), backgroundEl.modifier('disabled').class(this.disabled || this.readonly)) }, h("div", { key: '0c80561dffd1ecbf2ace34f268270dbd0fdd8fe9', class: Object.assign({}, backgroundUpperEl.class()), style: {
                width: this.cssWidth(),
            } }, h("div", { key: '7ae875637c76f930b34acef9c0b1063a14c11110', class: Object.assign({}, backgroundUpperInnerEl.class()) })), h("div", { key: 'd767b75c90733f309a6f2d11eadc22b4c8d8a579', class: Object.assign({}, backgroundLowerEl.class()), style: {
                width: this.cssWidth(true),
            } }, h("div", { key: '414cc007b301fa2f2775c40d4134295797a970b9', class: Object.assign({}, backgroundLowerInnerEl.class()) }))), h("div", { key: '8e474c378f92ffe8df9d65a3063114fe3833159e', class: Object.assign({}, inputEl.class()) }, h("div", { key: '811d58e16f4a261065b3f4ad446cc802d4e32c30', class: Object.assign(Object.assign({}, inputValueEl.class()), inputValueLeftEl.class()) }), h("input", { key: 'fb5781181cbba5f4438b70429a3d53a6aabdada0', type: "range", class: Object.assign(Object.assign({}, inputNativeEl.class()), inputNativeEl.modifier('disabled').class(this.disabled || this.readonly)), ref: inputEl => (this.nativeInput = inputEl), id: this.ariaForm.controlId || this.inputId, "aria-labelledby": this.ariaForm.labelId, "aria-describedby": this.ariaForm.messageId, "aria-disabled": ariaBooleanToString(this.disabled), "aria-invalid": this.invalid === true ? 'true' : 'false', disabled: this.disabled, readonly: this.readonly, name: this.name, required: this.required, tabIndex: this.balTabindex, step: this.step, min: this.min, max: this.max, value: this.value !== '' && this.value !== undefined ? this.value : 0, onInput: this.onInput, onBlur: this.onBlur, onFocus: this.onFocus, onKeyPress: e => this.balKeyPress.emit(e), "data-testid": "bal-input-slider" }), h("div", { key: '48e05291bc6fb797d06bb0d022ac47d4b1f6fc3f', class: Object.assign(Object.assign({}, inputValueEl.class()), inputValueRightEl.class()) })), h("div", { key: '0fd9bcddf9a98ac5c8706c6e7d33d1d0161dd8ed', class: Object.assign({}, stepsEl.class()), style: { display: this.hasTicks ? 'flex' : 'none' } }, this.getNumberOfSteps().map(step => (h("div", { key: step, class: Object.assign(Object.assign({}, stepsItemEl.class()), stepsItemEl.modifier('disabled').class(this.disabled || this.readonly)), "data-step-id": step }))))));
    }
    static get is() { return "bal-input-slider"; }
    static get originalStyleUrls() {
        return {
            "$": ["bal-input-slider.sass"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bal-input-slider.css"]
        };
    }
    static get properties() {
        return {
            "name": {
                "type": "string",
                "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": false,
                "attribute": "name",
                "defaultValue": "this.inputId"
            },
            "step": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The step size. 0 means no steps."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "step",
                "defaultValue": "0"
            },
            "min": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Min value of the model."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "min",
                "defaultValue": "0"
            },
            "max": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Max value of the model."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "max",
                "defaultValue": "100"
            },
            "invalid": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true` the component gets a invalid style."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "invalid",
                "defaultValue": "false"
            },
            "balTabindex": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The tabindex of the control."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "bal-tabindex",
                "defaultValue": "0"
            },
            "disabled": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the element is not mutable, focusable, or even submitted with the form. The user can neither edit nor focus on the control, nor its form control descendants."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "disabled",
                "defaultValue": "false"
            },
            "readonly": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true` the element can not mutated, meaning the user can not edit the control."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "readonly",
                "defaultValue": "false"
            },
            "required": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the user must fill in a value before submitting a form."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "required",
                "defaultValue": "false"
            },
            "hasTicks": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, small ticks for the steps are shown."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "has-ticks",
                "defaultValue": "false"
            },
            "debounce": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set the amount of time, in milliseconds, to wait to trigger the `balChange` event after each keystroke. This also impacts form bindings such as `ngModel` or `v-model`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "debounce",
                "defaultValue": "0"
            },
            "value": {
                "type": "any",
                "mutable": true,
                "complexType": {
                    "original": "string | number",
                    "resolved": "number | string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The value of the input."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "value",
                "defaultValue": "''"
            },
            "autoInvalidOff": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, in Angular reactive forms the control will not be set invalid"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "auto-invalid-off",
                "defaultValue": "false"
            }
        };
    }
    static get states() {
        return {
            "ariaForm": {}
        };
    }
    static get events() {
        return [{
                "method": "balInput",
                "name": "balInput",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a keyboard input occurred."
                },
                "complexType": {
                    "original": "BalEvents.BalInputSliderInputDetail",
                    "resolved": "number | string",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balBlur",
                "name": "balBlur",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a keyboard input occurred."
                },
                "complexType": {
                    "original": "BalEvents.BalInputSliderBlurDetail",
                    "resolved": "FocusEvent",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balKeyPress",
                "name": "balKeyPress",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a keyboard key has pressed."
                },
                "complexType": {
                    "original": "BalEvents.BalInputSliderKeyPressDetail",
                    "resolved": "KeyboardEvent",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balFocus",
                "name": "balFocus",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input has focus."
                },
                "complexType": {
                    "original": "BalEvents.BalInputSliderFocusDetail",
                    "resolved": "FocusEvent",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balChange",
                "name": "balChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input value has changed."
                },
                "complexType": {
                    "original": "BalEvents.BalInputSliderChangeDetail",
                    "resolved": "number | string",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "setFocus": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Sets focus on the native `input` in `bal-input`. Use this method instead of the global\n`input.focus()`.",
                    "tags": []
                }
            },
            "getInputElement": {
                "complexType": {
                    "signature": "() => Promise<HTMLInputElement | undefined>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "HTMLInputElement": {
                            "location": "global",
                            "id": "global::HTMLInputElement"
                        }
                    },
                    "return": "Promise<HTMLInputElement>"
                },
                "docs": {
                    "text": "Returns the native `<input>` element used under the hood.",
                    "tags": []
                }
            },
            "setAriaForm": {
                "complexType": {
                    "signature": "(ariaForm: BalAriaForm) => Promise<void>",
                    "parameters": [{
                            "name": "ariaForm",
                            "type": "BalAriaForm",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "BalAriaForm": {
                            "location": "import",
                            "path": "../../utils/form",
                            "id": "src/utils/form.ts::BalAriaForm"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "debounce",
                "methodName": "debounceChanged"
            }, {
                "propName": "value",
                "methodName": "valueChanged"
            }];
    }
    static get listeners() {
        return [{
                "name": "click",
                "method": "listenOnClick",
                "target": "document",
                "capture": true,
                "passive": false
            }, {
                "name": "reset",
                "method": "resetHandler",
                "target": "document",
                "capture": true,
                "passive": false
            }];
    }
}
let inputSliderIds = 0;
