/*!
 * Custom elements for Nanopore-Digital Web applications
 */
'use strict';

var index = require('./index-DGttnXif.js');
var renderer = require('./renderer-jVpDRMfV.js');
var math = require('./math-DIjJ3V87.js');

const ratingCss = ".sc-nano-rating-h,*.sc-nano-rating,*.sc-nano-rating::before,*.sc-nano-rating::after{box-sizing:border-box}[hidden].sc-nano-rating{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-rating-h,*.sc-nano-rating,*.sc-nano-rating::before,*.sc-nano-rating::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}.sc-nano-rating-h,*.sc-nano-rating,*.sc-nano-rating::before,*.sc-nano-rating::after{box-sizing:border-box}[hidden].sc-nano-rating{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-rating-h,*.sc-nano-rating,*.sc-nano-rating::before,*.sc-nano-rating::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}.sc-nano-rating-h{--symbol-color:var(--nano-color-neutral-400);--symbol-color-active:var(--nano-color-primary-1200);--symbol-spacing:0.25rem;--symbol-size:1.3125rem;display:inline-block}.rating-wrap.sc-nano-rating{position:relative;margin-block:0;margin-inline:calc(var(--symbol-spacing) * -1)}.rating-label.sc-nano-rating{inline-size:100%;overflow:clip;white-space:nowrap;text-overflow:ellipsis;color:var(--nano-color-base-1000);font-size:var(--nano-font-size-xs);padding-block-end:var(--nano-spacing-sm);line-height:1;display:flex;align-items:center}.visually-hidden.sc-nano-rating{clip-path:inset(50%);block-size:1px;overflow:hidden;position:absolute;white-space:nowrap;inline-size:1px}.rating.sc-nano-rating{position:relative;vertical-align:middle;inline-size:100%}.rating.sc-nano-rating:focus{outline:none}.rating.sc-nano-rating:focus-visible:focus{outline:var(--nano-focus-ring);outline-offset:var(--nano-focus-ring-offset)}.rating__symbols.sc-nano-rating{display:flex;align-items:center;position:relative;font-size:var(--symbol-size);color:var(--symbol-color);white-space:nowrap;cursor:pointer;line-height:0;justify-content:space-between}.rating__symbols--inactive.sc-nano-rating .rating__symbol.sc-nano-rating>.sc-nano-rating:not(.nano-icon){background-color:currentcolor !important}.rating__symbols.sc-nano-rating>*.sc-nano-rating{margin:var(--symbol-spacing)}.rating__symbols--indicator.sc-nano-rating{position:absolute;inset-block-start:0;inset-inline-start:0;color:var(--symbol-color-active);pointer-events:none;inline-size:100%}.rating__symbol.sc-nano-rating{transition:0.2s transform;text-align:center}.rating__symbol--hover.sc-nano-rating{transform:scale(1.2)}.rating--disabled.sc-nano-rating .rating__symbols.sc-nano-rating,.rating--readonly.sc-nano-rating .rating__symbols.sc-nano-rating{cursor:default}.rating--disabled.sc-nano-rating .rating__symbol.sc-nano-rating,.rating--readonly.sc-nano-rating .rating__symbol.sc-nano-rating{transform:none !important}.rating--disabled.sc-nano-rating{opacity:0.5}.rating--disabled.sc-nano-rating .rating__symbols.sc-nano-rating{cursor:not-allowed}";

const Rating = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.nanoChange = index.createEvent(this, "nanoChange", 7);
        this.nanoBlur = index.createEvent(this, "nanoBlur", 7);
        this.nanoFocus = index.createEvent(this, "nanoFocus", 7);
    }
    rating;
    isRtl;
    indicator;
    get host() { return index.getElement(this); }
    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 math.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 (renderer.h(index.Host, { key: '3011ba88cafed0ec3c79d823a3abac433f68b5d1', class: "nano-rating" }, renderer.h("label", { key: 'ea6a01bc5a7f8e7fecbb16a905c472b5e1c62328', class: `rating-label${this.hideLabel ? ' visually-hidden' : ''}`, part: "label", htmlFor: this.name }, renderer.h("slot", { key: '22e31eeaed0aca337a71c1bbb39c238413f1c00c', name: "label" }, this.label)), renderer.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();
            } }), renderer.h("div", { key: '4c0af619c68c230a5994871efdf5608870fb83e0', class: "rating-wrap" }, renderer.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 }, renderer.h("span", { key: 'd514ae0f85be4d59ab6a2ae4496357c5d6601ba9', class: "rating__symbols rating__symbols--inactive" }, counter.map((index) => (renderer.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) })))), renderer.h("span", { key: '0caf2f0561d3b74e6891e6c2a4b970fef53298f3', ref: (span) => (this.indicator = span), class: "rating__symbols rating__symbols--indicator", style: {
                clip: this.clip(displayValue),
            } }, counter.map((index) => (renderer.h("span", { class: {
                rating__symbol: true,
                'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1,
            }, innerHTML: this.symbol(index + 1) }))))))));
    }
    static get watchers() { return {
        "value": ["handleValueChange"],
        "symbolName": ["handleSymbolChange"]
    }; }
};
Rating.style = ratingCss;

exports.nano_rating = Rating;
