/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Host, } from "@stencil/core";
import { h } from "../../utils/renderer";
import { clamp } from "../../utils/math";
/**
 * Rating - a form element to allow the viewing and input of user feedback.
 *
 * @version 1.0.0
 * @status stable
 *
 * @slot label - A slot for a label element. If no label is provided, the `label` prop will be used.
 */
export class Rating {
    rating;
    isRtl;
    indicator;
    host;
    hoverValue = 0;
    isHovering = false;
    /**
     * The current rating.
     */
    value = 0;
    /**
     * The highest rating to show.
     */
    max = 5;
    /**
     * The minimum increment value allowed by the control.
     */
    precision = 1;
    /**
     * Makes the rating readonly.
     */
    readonly = false;
    /**
     * Disables the rating.
     */
    disabled = false;
    /**
     * The name of the control, which is submitted with the form data.
     */
    name = '';
    /**
     * If `true`, the user must fill in a value before submitting a form.
     * By default, setting this will also add an asterisk to the label.
     */
    required = false;
    /**
     * Visually hide the label - but make it accessible.
     */
    hideLabel = true;
    _label = '';
    /**
     * String to place within a label element. Alternatively you may use a label slot.
     */
    get label() {
        return this.required && !this._label.endsWith('*')
            ? this._label + ' *'
            : this._label;
    }
    set label(value) {
        this._label = value;
    }
    /**
     * The name of the control, which is submitted with the form data.
     */
    symbolName = 'solid/star-sharp';
    /**
     * A function that returns the symbols to display.
     * Allows for more granular control than `symbol-name`.
     * Accepts an option `value` parameter you can use to map a specific symbol to a value.
     * @param _number
     * @returns an html string used to render your rating symbol
     */
    symbol = (_number) => '<nano-icon name="' + this.symbolName + '"></nano-icon>';
    handleValueChange() {
        this.nanoChange.emit();
    }
    handleSymbolChange() {
        if (!this.symbol)
            this.symbol = (_) => '<nano-icon name="' + this.symbolName + '"></nano-icon>';
    }
    /**
     * Emitted when the rating's value changes.
     */
    nanoChange;
    /**
     * Emitted when the input loses focus.
     */
    nanoBlur;
    /**
     * Emitted when the input has focus.
     */
    nanoFocus;
    /**
     * Sets focus on the rating.
     */
    async setFocus() {
        this.rating.focus();
    }
    /**
     * Removes focus from the rating.
     */
    async removeFocus() {
        this.rating.blur();
    }
    getValueFromMousePosition(event) {
        const containerLeft = this.rating.getBoundingClientRect().left;
        const containerWidth = this.rating.getBoundingClientRect().width;
        let num;
        num = this.roundToPrecision(((event.clientX - containerLeft) / containerWidth) * this.max, this.precision);
        if (this.isRtl)
            num = this.max + this.precision - num;
        return clamp(num, 0, this.max);
    }
    roundToPrecision(numberToRound, precision = 0.5) {
        const multiplier = 1 / precision;
        return Math.ceil(numberToRound * multiplier) / multiplier;
    }
    handleClick = (event) => {
        if (this.disabled || this.readonly) {
            return;
        }
        const newValue = this.getValueFromMousePosition(event);
        this.value = newValue === this.value ? 0 : newValue;
        this.isHovering = false;
    };
    handleKeyDown = (event) => {
        if (this.disabled || this.readonly) {
            return;
        }
        if (event.key === 'ArrowLeft') {
            const decrement = event.shiftKey ? 1 : this.precision;
            this.value = this.roundToPrecision(Math.max(0, this.value - decrement));
            event.preventDefault();
        }
        if (event.key === 'ArrowRight') {
            const increment = event.shiftKey ? 1 : this.precision;
            this.value = this.roundToPrecision(Math.min(this.max, this.value + increment));
            event.preventDefault();
        }
        if (event.key === 'Home') {
            this.value = 0;
            event.preventDefault();
        }
        if (event.key === 'End') {
            this.value = this.max;
            event.preventDefault();
        }
    };
    handleMouseEnter = () => {
        this.isHovering = true;
    };
    handleMouseLeave = () => {
        this.isHovering = false;
    };
    handleFocus = () => {
        this.nanoFocus.emit();
    };
    handleBlur = () => {
        this.nanoBlur.emit();
    };
    handleMouseMove = (event) => {
        this.hoverValue = this.getValueFromMousePosition(event);
    };
    clip(displayValue) {
        if (!this.rating)
            return;
        const tw = this.rating.getBoundingClientRect().width;
        if (this.isRtl)
            return `rect(0, ${tw}px, 2em, ${tw - (tw / 100) * ((displayValue / this.max) * 100)}px)`;
        return `rect(0, ${(tw / 100) * ((displayValue / this.max) * 100)}px, 2em, 0)`;
    }
    componentDidLoad() {
        setTimeout(() => (this.indicator.style.clip = this.clip(this.value)), 20);
    }
    connectedCallback() {
        this.isRtl =
            this.host.dir === 'rtl' || this.host.ownerDocument.dir === 'rtl';
    }
    render() {
        this.isRtl =
            this.host.dir === 'rtl' || this.host.ownerDocument.dir === 'rtl';
        const counter = Array.from(Array(this.max).keys());
        let displayValue = 0;
        if (this.disabled || this.readonly) {
            displayValue = this.value;
        }
        else {
            displayValue = this.isHovering ? this.hoverValue : this.value;
        }
        return (h(Host, { key: '3011ba88cafed0ec3c79d823a3abac433f68b5d1', class: "nano-rating" }, h("label", { key: 'ea6a01bc5a7f8e7fecbb16a905c472b5e1c62328', class: `rating-label${this.hideLabel ? ' visually-hidden' : ''}`, part: "label", htmlFor: this.name }, h("slot", { key: '22e31eeaed0aca337a71c1bbb39c238413f1c00c', name: "label" }, this.label)), h("input", { key: '265bd0055cbd05911611e0a5e45828d4dab7ac8c', class: "range-input visually-hidden", name: this.name, id: this.name, disabled: this.disabled || this.readonly, required: this.required, value: this.value, onFocus: () => {
                this.setFocus();
            } }), h("div", { key: '4c0af619c68c230a5994871efdf5608870fb83e0', class: "rating-wrap" }, h("div", { key: 'e6f94c258bc04b6a4a6aad66c9364c1c811f859a', dir: this.isRtl ? 'rtl' : null, ref: (el) => (this.rating = el), part: "base", class: {
                rating: true,
                'rating--readonly': this.readonly,
                'rating--disabled': this.disabled,
            }, "aria-disabled": this.disabled ? 'true' : 'false', "aria-readonly": this.readonly ? 'true' : 'false', "aria-valuenow": this.value, "aria-valuemin": 0, "aria-valuemax": this.max, tabIndex: this.disabled ? -1 : 0, onClick: this.handleClick, onKeyDown: this.handleKeyDown, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onMouseMove: this.handleMouseMove, onFocus: this.handleFocus, onBlur: this.handleBlur }, h("span", { key: 'd514ae0f85be4d59ab6a2ae4496357c5d6601ba9', class: "rating__symbols rating__symbols--inactive" }, counter.map((index) => (h("span", { class: {
                rating__symbol: true,
                'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1,
            },
            // Users can click the current value to clear the rating. When this happens, we set this.isHovering to
            // false to prevent the hover state from confusing them as they move the mouse out of the control. This
            // extra mouseenter will reinstate it if they happen to mouse over an adjacent symbol.
            onMouseEnter: this.handleMouseEnter, innerHTML: this.symbol(index + 1) })))), h("span", { key: '0caf2f0561d3b74e6891e6c2a4b970fef53298f3', ref: (span) => (this.indicator = span), class: "rating__symbols rating__symbols--indicator", style: {
                clip: this.clip(displayValue),
            } }, counter.map((index) => (h("span", { class: {
                rating__symbol: true,
                'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1,
            }, innerHTML: this.symbol(index + 1) }))))))));
    }
    static get is() { return "nano-rating"; }
    static get encapsulation() { return "scoped"; }
    static get originalStyleUrls() {
        return {
            "$": ["rating.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["rating.css"]
        };
    }
    static get properties() {
        return {
            "value": {
                "type": "number",
                "attribute": "value",
                "mutable": true,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The current rating."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "0"
            },
            "max": {
                "type": "number",
                "attribute": "max",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The highest rating to show."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "5"
            },
            "precision": {
                "type": "number",
                "attribute": "precision",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The minimum increment value allowed by the control."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "1"
            },
            "readonly": {
                "type": "boolean",
                "attribute": "readonly",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Makes the rating readonly."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "disabled": {
                "type": "boolean",
                "attribute": "disabled",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Disables the rating."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "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": false,
                "defaultValue": "''"
            },
            "required": {
                "type": "boolean",
                "attribute": "required",
                "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.\nBy default, setting this will also add an asterisk to the label."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "hideLabel": {
                "type": "boolean",
                "attribute": "hide-label",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Visually hide the label - but make it accessible."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "true"
            },
            "label": {
                "type": "string",
                "attribute": "label",
                "mutable": true,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "String to place within a label element. Alternatively you may use a label slot."
                },
                "getter": true,
                "setter": true,
                "reflect": false
            },
            "symbolName": {
                "type": "string",
                "attribute": "symbol-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": false,
                "defaultValue": "'solid/star-sharp'"
            },
            "symbol": {
                "type": "unknown",
                "attribute": "symbol",
                "mutable": false,
                "complexType": {
                    "original": "(_number: number) => string",
                    "resolved": "(_number: number) => string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "param",
                            "text": "_number"
                        }, {
                            "name": "returns",
                            "text": "an html string used to render your rating symbol"
                        }],
                    "text": "A function that returns the symbols to display.\nAllows for more granular control than `symbol-name`.\nAccepts an option `value` parameter you can use to map a specific symbol to a value."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "(_number: number) =>\n    '<nano-icon name=\"' + this.symbolName + '\"></nano-icon>'"
            }
        };
    }
    static get states() {
        return {
            "hoverValue": {},
            "isHovering": {}
        };
    }
    static get events() {
        return [{
                "method": "nanoChange",
                "name": "nanoChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the rating's value changes."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }, {
                "method": "nanoBlur",
                "name": "nanoBlur",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input loses focus."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }, {
                "method": "nanoFocus",
                "name": "nanoFocus",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input has focus."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }];
    }
    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 rating.",
                    "tags": []
                }
            },
            "removeFocus": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Removes focus from the rating.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "value",
                "methodName": "handleValueChange"
            }, {
                "propName": "symbolName",
                "methodName": "handleSymbolChange"
            }];
    }
}
