/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { r as registerInstance, c as createEvent, g as getElement, a as Host } from './index-BM3Om9WE.js';
import { h } from './renderer-DpNDfhNy.js';
import { p as parseISODate, a as printISODate, c as createDate } from './date-utils-BZYdjI1P.js';
import { c as createColorClasses } from './theme-aiuyr36I.js';

const dateInputCss = ".sc-nano-date-input-h,*.sc-nano-date-input,*.sc-nano-date-input::before,*.sc-nano-date-input::after{box-sizing:border-box}[hidden].sc-nano-date-input{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-date-input-h,*.sc-nano-date-input,*.sc-nano-date-input::before,*.sc-nano-date-input::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}.sc-nano-date-input-h,*.sc-nano-date-input,*.sc-nano-date-input::before,*.sc-nano-date-input::after{box-sizing:border-box}[hidden].sc-nano-date-input{display:none !important}@media (prefers-reduced-motion: reduce){.sc-nano-date-input-h,*.sc-nano-date-input,*.sc-nano-date-input::before,*.sc-nano-date-input::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}.sc-nano-date-input-h{display:inline-block;inline-size:100%;--focus-shadow:var(--nano-control-focus-shadow, 0 0 0 0.1875rem  var(--nano-control-focus-color, rgba(144, 198, 231, 0.8)));--open-btn-color:var(--nano-button-color, #f0efed);--open-btn-border:none;--close-btn-color:var(--nano-button-color, #f0efed);--picker-base-size:16px}.nano-color.sc-nano-date-input-h{--focus-shadow:0 0 0 0.1875rem rgb(var(--nano-color-tint-rgb)/0.56)}.nano-icon.sc-nano-date-input{pointer-events:none}.date-field.sc-nano-date-input{display:flex;flex-direction:column;position:relative}.date-field__dropdown.sc-nano-date-input{--padding:0;--overflow:visible;padding:0 !important;inline-size:0 !important;inline-size:100%;z-index:var(--nano-layer-index-dropdown, 300) !important}.date-field__close-bar.sc-nano-date-input{align-items:center;display:flex;justify-content:space-between;text-overflow:ellipsis;white-space:nowrap;border:0;margin:0;overflow:visible;padding:0;position:absolute;inset-inline-end:-8px;inset-block-start:-8px;inline-size:auto;z-index:1}.date-field__open.sc-nano-date-input{background:var(--open-btn-color);border:var(--open-btn-border);margin:0;appearance:none}.date-field__open.sc-nano-date-input:focus{box-shadow:var(--focus-shadow);outline:none}.date-field__close.sc-nano-date-input{align-items:center;appearance:none;background:var(--close-btn-color);border:0;border-radius:50%;cursor:pointer;display:flex;block-size:24px;justify-content:center;padding:0;inline-size:24px}@media (width >= 36em){.date-field__close.sc-nano-date-input{opacity:0}}.date-field__close.sc-nano-date-input:focus{box-shadow:var(--focus-shadow);outline:none}@media (width >= 36em){.date-field__close.sc-nano-date-input:focus{opacity:1}}.date-field__close.sc-nano-date-input .nano-icon.sc-nano-date-input{margin-block:0;margin-inline:auto}.date-field.sc-nano-date-input .nano-date-picker.sc-nano-date-input{font-size:var(--picker-base-size)}.vhidden.sc-nano-date-input{clip-path:inset(50%);block-size:1px;overflow:hidden;position:absolute;white-space:nowrap;inline-size:1px}";

const DateRegxps = {
    d: '(\\d{1,2})',
    m: '(\\d{1,2})',
    y: '(\\d{4})',
};
let inputIds = 0;
const DateInput = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.nanoChange = createEvent(this, "nanoChange", 7);
        this.nanoValidate = createEvent(this, "nanoValidate", 7);
    }
    pickerEle;
    trigger;
    pickerCloseBtn;
    dropdown;
    input;
    directInput = false;
    dateOrderIndeces = { d: 0, m: 1, y: 3 };
    inputId = `nano-input-${inputIds++}`;
    locale = window.navigator.languages ||
        window.navigator.language ||
        undefined;
    get host() { return getElement(this); }
    // Private state
    pattern;
    inputValue;
    // Public Api / Prop
    /**
     * 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.validityMessage;
    }
    /**
     * Whether to show a long form, confirmation date string of the one currently entered
     */
    helperText = true;
    /**
     * Options for the date string display. Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString.
     */
    helperTextFormat = {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
    };
    /**
     * Enable floating label behaviour. Will disable placeholder if set.
     */
    floatLabel = false;
    /**
     * The name of the control, which is submitted with the form data.
     */
    name = this.inputId;
    /**
     * If `true`, the user cannot modify the value.
     */
    readonly = false;
    /**
     * The initial size (number of characters) of the control.
     */
    size;
    /**
     * The form element to associate the select with (its form owner). Must be the id of a form.
     */
    form;
    /**
     * Which day is considered first day of the week? `0` for Sunday, `1` for Monday, etc.
     * Default is Monday.
     */
    firstDayOfWeek;
    /**
     * Button labels, day names, month names, etc, used for localization.
     * Default is English.
     */
    localization;
    /**
     * If `true`, the user cannot interact with the input.
     */
    disabled = false;
    /**
     * The color to use from the application's color palette.
     */
    color;
    /**
     * This Boolean attribute lets you specify that a form control should have input focus when the page loads.
     */
    autofocus = false;
    /**
     * If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
     */
    clearable = false;
    /**
     * String to place within a label element. Alternatively you may use a label slot.
     */
    label;
    /**
     * Instructional text that shows before the input has a value.
     * The pattern prop will be used to create a placeholder automatically if unused.
     */
    placeholder;
    /**
     * Current value. Must be in IS0-8601 format: YYYY-MM-DD.
     */
    value = '';
    handleValueChange() {
        if (!this.directInput)
            this.inputValue = this.formatIsoDate(this.value);
        setTimeout(() => {
            this.nanoChange.emit({
                value: this.value,
                date: parseISODate(this.value),
            });
        }, 20);
        this.directInput = false;
    }
    /**
     * When should the field perform validation
     */
    validateOn = 'submitThenDirty';
    /**
     * Whether to show validation errors underneath input
     */
    showInlineError = true;
    /**
     * The order of the date parts for entry and display.
     * e.g. dmy = dd mm yyyy
     */
    dateOrder = 'dmy';
    handleDateOrderChange() {
        this.setDatePattern();
    }
    /**
     * If `true`, the user must fill in a value before submitting a form.
     */
    required = false;
    /**
     * Minimum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD.
     * This setting can be used alone or together with the max property.
     */
    min;
    /**
     * Maximum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD.
     * This setting can be used alone or together with the min property.
     */
    max;
    /**
     * Visually hide the label - but make it accessible.
     */
    hideLabel = false;
    testDateValidity() {
        const valueDate = parseISODate(this.value);
        let min, max, error = '';
        if (this.value && valueDate) {
            if (this.min && (min = parseISODate(this.min)) && valueDate < min) {
                error =
                    'Date below the minimum: ' +
                        min.toLocaleDateString(this.locale, this.helperTextFormat);
            }
            if (this.max && (max = parseISODate(this.max)) && valueDate > max) {
                error =
                    'Date above the maximum: ' +
                        max.toLocaleDateString(this.locale, this.helperTextFormat);
            }
            if (this.isDateDisabled(valueDate)) {
                error = 'Date selected is disabled.';
            }
        }
        requestAnimationFrame(async (_) => {
            if (!this.input)
                return;
            const input = await this.input.getInputElement();
            if (this.value.length && !valueDate)
                error = 'Please enter a valid date';
            input.setCustomValidity(error);
            if (this.input.validateOn === 'dirty') {
                this.input.showError(error);
            }
        });
    }
    /**
     * Show a date picker. Date pickers are not very useful
     * if the potential input is too far in the distance or past
     * e.g. Birthdays
     */
    picker = true;
    /**
     * Initial picker date. Defaults to `value` if set and today's date if not.
     * Must be in IS0-8601 format: YYYY-MM-DD.
     */
    initialPickerDate;
    /**
     * Set / read whether the picker is currently open.
     */
    pickerOpen = false;
    handlePickerOpenChange() {
        this.dropdown.open = this.pickerOpen;
    }
    /**
     * Close the picker after a date is selected
     */
    closeAfterPicked = true;
    /** nano-dropdown config options you can pass to the nested dropdown component */
    get dropDownConfig() {
        return this._dropDownConfig;
    }
    set dropDownConfig(ddc) {
        this._dropDownConfig = { ...this._dropDownConfig, ...ddc };
    }
    _dropDownConfig = {};
    /** @readonly get the value as a `Date` */
    get dateValue() {
        return parseISODate(this.value);
    }
    /** Controls which days are disabled and therefore disallowed.
     * For example, this can be used to disallow selection of weekends.
     * @returns `false` for not disabled and `true` for disabled */
    isDateDisabled = () => false;
    // Event emitters
    /**
     * Event emitted when a date is selected.
     */
    nanoChange;
    /**
     * Called when validation is performed (which depends on `validateOn`).
     * @returns event.detail: `{ isValid: boolean, errorMessage: string, originalEvent: Event }`.
     */
    nanoValidate;
    // Methods
    /**
     * Get the current state of the control.
     * @param validateFirst - perform validation first before reporting
     * @returns `{ isValid: boolean, errorMessage: string }`
     */
    async reportValidity(validateFirst) {
        const initValidity = await this.input.reportValidity(validateFirst);
        if (initValidity.isValid && validateFirst)
            this.testDateValidity();
        return await this.input.reportValidity(validateFirst);
    }
    /**
     * Sets focus on the child `nano-input`.
     */
    async setFocus() {
        if (this.input)
            this.input.setFocus();
    }
    /**
     * Returns the native `<input>` element used under the hood.
     * @returns `HTMLInputElement`
     */
    async getInputElement() {
        return await this.input.getInputElement();
    }
    /**
     * Invalidate the field and show a custom error message. To clear the error you will need to re-call this method with an empty string.
     */
    async showError(message) {
        if (!this.input)
            return;
        this.input.showError(message);
    }
    // Event handlers
    onInputChange = (e) => {
        e.stopPropagation();
        this.setValue(e.target.value);
    };
    onInputValidate = (e) => {
        e.stopPropagation();
        this._invalid = !e.detail.isValid;
        this.nanoValidate.emit({
            isValid: e.detail.isValid,
            errorMessage: e.detail.errorMessage,
            originalEvent: e.detail.originalEvent,
        });
    };
    onInputKey = () => {
        this.directInput = true;
    };
    onDatePicked = (e) => {
        this.directInput = false;
        this.value = e.detail.value;
        if (this.closeAfterPicked)
            this.pickerOpen = false;
    };
    onDropdownHide = () => {
        setTimeout((_) => (this.pickerOpen = false), 200);
        setTimeout((_) => this.trigger.focus(), 50);
    };
    onTriggerClick = () => {
        if (!this.pickerOpen) {
            this.pickerOpen = true;
        }
    };
    onTriggerKey = (e) => {
        if ([' ', 'Enter'].includes(e.key)) {
            if (!this.pickerOpen) {
                this.pickerOpen = true;
            }
        }
    };
    onCloseClick = () => {
        if (this.pickerOpen)
            this.pickerOpen = false;
    };
    onCloseKeyDown = (e) => {
        // this ensures focus is trapped inside the picker
        if (e.key === 'Tab' && e.shiftKey) {
            this.pickerEle.setFocus(true);
            e.preventDefault();
        }
        if (e.key === ' ' || e.key === 'Enter') {
            if (this.pickerOpen)
                this.pickerOpen = false;
        }
    };
    // Private logic
    // set the regexp input pattern and placeholder (if necessary)
    setDatePattern() {
        const dateRegexOrdered = [];
        const dateStrOrd = [];
        Array.from(this.dateOrder).map((datepart, i) => {
            dateRegexOrdered.push(DateRegxps[datepart]);
            this.dateOrderIndeces[datepart] = i;
            dateStrOrd.push(datepart === 'y' ? 'yyyy' : datepart + datepart);
        });
        this.pattern = dateRegexOrdered.join('\\W+');
        if (!this.placeholder && this.placeholder !== 'false')
            this.placeholder = dateStrOrd.join(' ');
    }
    // set the public facing date string
    formatIsoDate(isoDate) {
        const dateRegexOrdered = [];
        Array.from('ymd').map((datepart) => dateRegexOrdered.push(DateRegxps[datepart]));
        const matches = isoDate.match(new RegExp(dateRegexOrdered.join('\\W+')));
        if (!matches)
            return '';
        const formatted = [];
        formatted[this.dateOrderIndeces.d] = matches[3];
        formatted[this.dateOrderIndeces.m] = matches[2];
        formatted[this.dateOrderIndeces.y] = matches[1];
        return formatted.join(' ');
    }
    // on manual user entry, set the value that will be sent with the form field
    setValue(inputValue) {
        const matches = inputValue.match(new RegExp(this.pattern));
        // it's an invalid date, but we still need to set it
        if (!matches) {
            this.value = inputValue;
            return;
        }
        let date = createDate(matches[this.dateOrderIndeces.y + 1], matches[this.dateOrderIndeces.m + 1], matches[this.dateOrderIndeces.d + 1]);
        if (!date) {
            // last ditch attempt - see if the browser can get something
            date = new Date(inputValue);
            // it's definitely an invalid date, but set it anyway for validation messages
            if (!date) {
                this.value = inputValue;
                return;
            }
        }
        const dateStr = printISODate(date);
        this.value = dateStr;
        return dateStr;
    }
    connectedCallback() {
        console.warn('nano-date-input is deprecated and will be removed in a future version. Use nano-input with type="date" instead.');
        this.setDatePattern();
        this.handleValueChange();
    }
    componentDidLoad() {
        if (!this.pickerCloseBtn || !this.picker)
            return;
        this.pickerEle.firstFocusEle = this.pickerCloseBtn;
        this.dropdown.tetherTo = this.trigger;
        setTimeout((_) => this.handlePickerOpenChange(), 300);
    }
    render() {
        this.locale =
            navigator.languages || navigator.language || undefined;
        this.dropDownConfig.placement =
            this.dropDownConfig.placement || 'bottom-end';
        if (this.host.ownerDocument.dir === 'rtl') {
            this.dropDownConfig.placement.replace('start', 'end');
        }
        if (this.trigger)
            this.dropDownConfig.tetherTo = this.trigger;
        const valueDate = parseISODate(this.value);
        const hasHelperSlot = !!this.host.querySelector('[slot="helper"]');
        return (h(Host, { key: 'd584003b7188229e35c59048e46b0c2be1068987', class: { ...createColorClasses(this.color), 'date-input': true } }, h("div", { key: '88ef9423db0ed1e11b5ccad2c75a0c9d0f9b9d29', class: "date-field" }, h("nano-input", { key: 'a4d5c368da0bb9b296563e09760d8c450360d2d3', class: "date-field__input", slot: "trigger", required: this.required || undefined, showInlineError: this.showInlineError, validateOn: this.validateOn, placeholder: this.placeholder !== 'false' ? this.placeholder : undefined, pattern: this.pattern, label: this.label, disabled: this.disabled || undefined, color: this.color || undefined, autofocus: this.autofocus || undefined, clearable: this.clearable || undefined, onNanoChange: this.onInputChange, onNanoInput: this.onInputKey, onNanoValidate: this.onInputValidate, name: "", form: this.form || undefined, size: this.size || undefined, readonly: this.readonly, value: this.inputValue, ref: (input) => (this.input = input), floatLabel: this.floatLabel, hideLabel: this.hideLabel, inputmode: 'numeric', part: "input" }, h("slot", { key: '8852fd0a14ed85773706f6313be4af121c33f212', name: "start", slot: "start" }), h("slot", { key: 'c34815b4acd3bd9e556d908dcebb4e39a9ab1f78', name: "label", slot: "label" }), h("slot", { key: '3ba077636a9908c1ff57ca6a82824586becd8497', name: "end", slot: "end" }), this.picker && [
            h("button", { key: 'c45a42017fc0023f1f9b6c8201b209979678fd52', slot: "end", class: "date-field__open", type: "button", onKeyDown: this.onTriggerKey, onClick: this.onTriggerClick, ref: (trigger) => (this.trigger = trigger), disabled: this.disabled || this.readonly }, h("nano-icon", { key: 'ae888424999bff07e6693023e1ef38a2ae471c96', name: "light/calendar-days" })),
            h("nano-dropdown", { key: 'd82337659d8656f162e51789dcd32c102f733f77', slot: "end", onNanoHide: this.onDropdownHide, dialogTitle: "Choose a date", class: "date-field__dropdown", ref: (dropdown) => (this.dropdown = dropdown), ...this.dropDownConfig, part: "dropdown" }, h("div", { key: 'f5c9d99cd1a6725068f7f1acd27cf6e3e3717754' }, h("div", { key: 'b9e02ade28a5213382b993e57143dff2d19ececd', class: "date-field__close-bar" }, h("button", { key: 'af6aebad9c406b500d17338a0f5fb178638d3a01', class: "date-field__close", type: "button", onMouseDown: this.onCloseClick, onKeyDown: this.onCloseKeyDown, ref: (pickerClose) => (this.pickerCloseBtn = pickerClose) }, h("nano-icon", { key: '6cecd49256234320e73d732e689dd552dbf22645', name: "light/xmark" }), h("span", { key: 'fc9f86d2f3dbf06d53217ccf6556b3b119240ceb', class: "vhidden" }, "Close window"))), h("nano-date-picker", { key: 'd0a388667a9372ecfebae22d0175fe68230c11ac', isDateDisabled: this.isDateDisabled, onNanoDatePicked: this.onDatePicked, min: this.min || undefined, max: this.max || undefined, "is-modal": true, ref: (picker) => (this.pickerEle = picker), localization: this.localization, selectedDate: this.value || this.initialPickerDate, firstDayOfWeek: this.firstDayOfWeek, color: this.color || undefined, part: "date-picker" }))),
        ], (hasHelperSlot || this.helperText || this.showInlineError) && (h("span", { key: '109ec3fe3dd22087fca3240b3ad2b712b7444a3e', slot: "helper" }, h("span", { key: 'a709814dfcb66923cb512737768b4385c6a2fa85', class: { vhidden: !!this.value.length } }, h("slot", { key: '16375d1e2af0839d94b93b02117817fe54ed5887', name: "helper" })), this.helperText && !!valueDate && (h("span", { key: 'dce160d23dbf15337800f15f43380c75643f6373' }, valueDate.toLocaleDateString(this.locale, this.helperTextFormat)))))), h("input", { key: 'c50fb0b2a5104229cf44f9564a902b813e45111f', type: "hidden", value: this.value, name: this.name }))));
    }
    static get watchers() { return {
        "value": ["handleValueChange", "testDateValidity"],
        "dateOrder": ["handleDateOrderChange"],
        "min": ["testDateValidity"],
        "max": ["testDateValidity"],
        "pickerOpen": ["handlePickerOpenChange"]
    }; }
};
DateInput.style = dateInputCss;

export { DateInput as nano_date_input };
