'use strict';

var index = require('./index-CJK1u2Q5.js');
var tslib_es6 = require('./tslib.es6-DrfCPgT9.js');
var mutation_decorator = require('./mutation.decorator-CrrTf-c-.js');
var form = require('./form-BSlIiqcR.js');
var bem = require('./bem-p0PWVN8n.js');
require('./bal-file-upload.type-BzNkF3YQ.js');
var breakpoints_subject = require('./breakpoints.subject-BgiK6gXq.js');
var breakpoints_decorator = require('./breakpoints.decorator-DmVJlnEZ.js');
require('./date-DaSrQCG2.js');
require('./window-resize.subject-fSEteMlj.js');
require('./listener-BHmwpN04.js');
require('./device-D8GN5vuz.js');
require('./tokens.esm-S9lXy5Jj.js');

const balFieldCss = ":root{--bal-field-label-horizontal-width:33.3333%;--bal-field-label-column-gap:.5rem}.bal-field,.bal-field-label,.bal-field-control,.bal-field-message,.bal-field-hint{display:block;position:relative;font-family:var(--bal-font-family-text)}.bal-field-label{display:inline}.bal-field-label~.bal-field-control{margin-top:.25rem}.bal-field-hint{display:inline-block;margin-left:.25rem;height:1rem;width:1rem}.bal-field-hint__hint{position:absolute;top:2px;left:0}.bal-field-message{line-height:var(--bal-line-height-normal)}.bal-field-hidden{display:none !important;visibility:hidden !important}.bal-field-control{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-direction:row;flex-direction:row;gap:.5rem}.bal-field-control .bal-input{-ms-flex:1;flex:1}@media screen and (max-width: 768px){.bal-field-control--expanded-on-mobile{-ms-flex-direction:column;flex-direction:column}.bal-field-control--expanded-on-mobile .bal-button,.bal-field-control--expanded-on-mobile .bal-button .button{width:100%}}.bal-field-message{margin-top:0 !important}.bal-field-control+.bal-field-message{min-height:1.375rem;line-height:1.375rem}.bal-field-control:not(:has(+.bal-field-message)){padding-bottom:1.375rem}.bal-field--horizontal{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-column-gap:var(--bal-field-label-column-gap);-moz-column-gap:var(--bal-field-label-column-gap);column-gap:var(--bal-field-label-column-gap);-ms-flex-align:center;align-items:center}.bal-field--horizontal .bal-field-label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-width:var(--bal-field-label-horizontal-width);max-width:var(--bal-field-label-horizontal-width);-ms-flex-pack:end;justify-content:flex-end;text-align:right;margin-bottom:0}.bal-field--horizontal .bal-field-control{-ms-flex:1;flex:1;padding-bottom:0;-ms-flex-item-align:end;align-self:flex-end}.bal-field--horizontal .bal-field-message{-ms-flex-preferred-size:100%;flex-basis:100%;margin-top:0 !important;margin-left:calc(var(--bal-field-label-horizontal-width) + var(--bal-field-label-column-gap))}.bal-field--horizontal .bal-field-hint{margin-left:0}.bal-field--horizontal .bal-field-hint .bal-hint{top:0}.bal-field--horizontal .bal-field-hint~.bal-field-message{margin-left:calc(var(--bal-field-label-horizontal-width) + var(--bal-field-label-column-gap)*2 + 1.125rem)}.bal-field--horizontal .bal-field-label~.bal-field-control{margin-top:0}";

const Field = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.balFormControlDidLoad = index.createEvent(this, "balFormControlDidLoad");
        this.fieldId = `bal-field-${FieldIds++}`;
        this.formControlElement = ['bal-field-control'];
        this.inputElements = [
            'bal-input',
            'bal-number-input',
            'bal-textarea',
            'bal-select',
            'bal-checkbox',
            'bal-radio',
            'bal-input-group',
            'bal-date',
            'bal-input-date',
            'bal-input-stepper',
            'bal-input-slider',
            'bal-file-upload',
            'bal-dropdown',
            'bal-segment',
        ];
        this.formElements = [...this.formControlElement, 'bal-field-label', 'bal-field-message'];
        /**
         * If `true` the form control needs to be filled. If it is set to
         * `false` an optional label is added to the label..
         */
        this.required = undefined;
        /**
         * If true, label and input are aligned horizontally within the field component, with the message positioned in a new line below.
         */
        this.horizontal = false;
        /**
         * If `true` the component gets a invalid red style.
         */
        this.invalid = undefined;
        /**
         * If `true` the component gets a valid green style.
         */
        this.valid = false;
        /**
         * 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 = undefined;
        /**
         * If `true` the element can not mutated, meaning the user can not edit the control.
         */
        this.readonly = undefined;
        /**
         * If `true` a loading spinner is visible at the end of the input
         */
        this.loading = undefined;
        this.isDirectChild = (el) => {
            if (!el) {
                return false;
            }
            const parent = el.parentElement;
            if (!parent) {
                return false;
            }
            if (parent.nodeName.toLowerCase() === 'bal-field' && parent !== this.el) {
                return false;
            }
            if (parent === this.el) {
                return true;
            }
            return this.isDirectChild(parent);
        };
        this.isVisible = (el) => {
            if (!el) {
                return false;
            }
            return el.ariaHidden !== 'true';
        };
        this.findDirectChild = (selectors) => {
            const element = this.el.querySelector(selectors);
            const isDirectChild = this.isDirectChild(element);
            if (isDirectChild) {
                if (this.isVisible(element)) {
                    return element;
                }
            }
            return undefined;
        };
        this.findDirectChildren = (selectors) => {
            return selectors
                .map(selector => {
                return Array.from(this.el.querySelectorAll(selector)).filter(this.isDirectChild).filter(this.isVisible);
            })
                .flat();
        };
        this.mutationObserverActive = true;
    }
    requiredHandler() {
        this.updateProps([...this.inputElements, 'bal-field-label'], 'required');
    }
    invalidHandler() {
        this.updateProps([...this.inputElements, ...this.formElements], 'invalid');
    }
    validHandler() {
        this.updateProps([...this.inputElements, ...this.formElements], 'valid');
    }
    disabledHandler() {
        this.updateProps([...this.inputElements, ...this.formElements], 'disabled');
    }
    readonlyHandler() {
        this.updateProps([...this.inputElements, ...this.formElements], 'readonly');
    }
    loadingHandler() {
        this.updateProps([...this.inputElements, ...this.formControlElement], 'loading');
    }
    connectedCallback() {
        this.triggerAllHandlers();
    }
    componentWillLoad() {
        this.triggerAllHandlers();
    }
    async componentDidLoad() {
        await this.syncAriaAttributes();
    }
    async syncAriaAttributes() {
        await index.deepReady(this.el);
        await index.waitAfterFramePaint();
        const label = this.findDirectChild('bal-field-label bal-label');
        const message = this.findDirectChild('bal-field-message');
        const controls = this.findDirectChildren([
            'bal-field-control bal-input',
            'bal-field-control bal-select',
            'bal-field-control bal-input-date',
            'bal-field-control bal-dropdown',
            'bal-field-control bal-checkbox',
            'bal-field-control bal-radio',
            'bal-field-control bal-segment',
            'bal-field-control bal-segment-item',
            'bal-field-control bal-checkbox-group',
            'bal-field-control bal-radio-group',
            'bal-field-control bal-number-input',
            'bal-field-control bal-time-input',
            'bal-field-control bal-input-slider',
            'bal-field-control bal-input-stepper',
            'bal-field-control bal-textarea',
            'bal-field-control bal-file-upload',
        ]);
        const ariaForm = Object.assign({}, form.defaultBalAriaForm);
        if (label) {
            ariaForm.labelId = `${this.fieldId}-lbl`;
        }
        if (message) {
            ariaForm.messageId = `${this.fieldId}-msg`;
        }
        for (let index = 0; index < controls.length; index++) {
            const control = controls[index];
            if (index === 0) {
                ariaForm.controlId = `${this.fieldId}-ctrl`;
                await (label === null || label === void 0 ? void 0 : label.setAriaForm(ariaForm));
                await (message === null || message === void 0 ? void 0 : message.setAriaForm(ariaForm));
                await (control === null || control === void 0 ? void 0 : control.setAriaForm(ariaForm));
            }
            else {
                ariaForm.controlId = `${this.fieldId}-ctrl-${index}`;
                await (control === null || control === void 0 ? void 0 : control.setAriaForm(ariaForm));
            }
        }
    }
    mutationListener() {
        this.triggerAllHandlers();
        this.syncAriaAttributes();
    }
    triggerAllHandlers() {
        this.requiredHandler();
        this.invalidHandler();
        this.validHandler();
        this.readonlyHandler();
        this.disabledHandler();
        this.loadingHandler();
    }
    updateProps(selectors, key) {
        const value = this[key];
        if (value !== undefined) {
            this.notifyComponents(selectors, input => (input[key] = value));
        }
    }
    notifyComponents(selectors, callback) {
        const components = this.el.querySelectorAll(selectors.join(', '));
        components.forEach(c => callback(c));
    }
    render() {
        return (index.h(index.Host, { key: '2d5f00847eed504077334ab0a99e7d8ec2d5e933', id: this.fieldId, class: {
                'bal-field': true,
                'field': true,
                'bal-field--invalid': this.invalid === true,
                'bal-field--horizontal': this.horizontal === true,
            } }, index.h("slot", { key: '7e84f2c3b7a5070c3d44616d4f61c798ed201708' }), index.h("span", { key: 'b7999bd90707cf04144c23ee94cf6ef5e8605ba1', class: "bal-field-hidden" })));
    }
    get el() { return index.getElement(this); }
    static get watchers() { return {
        "required": ["requiredHandler"],
        "invalid": ["invalidHandler"],
        "valid": ["validHandler"],
        "disabled": ["disabledHandler"],
        "readonly": ["readonlyHandler"],
        "loading": ["loadingHandler"]
    }; }
};
tslib_es6.__decorate([
    mutation_decorator.ListenToMutation({ subtree: false, waitAfterFramePrint: true }),
    tslib_es6.__metadata("design:type", Function),
    tslib_es6.__metadata("design:paramtypes", []),
    tslib_es6.__metadata("design:returntype", void 0)
], Field.prototype, "mutationListener", null);
let FieldIds = 0;
Field.style = balFieldCss;

const FieldControl = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        /**
         * @deprecated
         * Baloise icon for the right side of the input
         */
        this.iconRight = '';
        /**
         * @deprecated
         * Baloise icon for the left side of the input
         */
        this.iconLeft = '';
        /**
         * If `true` on mobile devices the form control children are aligned verticaly and expanded to the full width
         */
        this.expandedOnMobile = undefined;
        /**
         * If `true` a loading spinner is visible at the end of the input
         */
        this.loading = false;
    }
    get buildIconLeftTemplate() {
        if (this.iconLeft) {
            return index.h("bal-icon", { name: this.iconLeft, color: "info", class: "is-left", size: "small" });
        }
        return '';
    }
    get buildIconRightTemplate() {
        if (this.iconRight) {
            return index.h("bal-icon", { name: this.iconRight, color: "info", class: "is-right", size: "small" });
        }
        return '';
    }
    render() {
        return (index.h(index.Host, { key: '4aecfd6cf7bc49df8feb26cd3161af9174097fcc', class: {
                'bal-field-control': true,
                'control': true,
                'has-icons-left': !!this.iconLeft,
                'has-icons-right': !!this.iconRight,
                'is-loading': this.loading,
                'bal-field-control--expanded-on-mobile': !!this.expandedOnMobile,
            } }, index.h("slot", { key: 'b1d4c61b4ba0cbd96c11d5540e12dafcc4b2518e' }), this.buildIconLeftTemplate, this.buildIconRightTemplate));
    }
};

const FieldHint = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        /**
         * Hide the title on desktop.
         */
        this.hideTitleOnDesktop = false;
        /**
         * Text of the inputs label
         */
        this.subject = '';
        /**
         * Text for the close button.
         */
        this.closeLabel = 'Close';
        /**
         * Disables the close button for tablet and desktop
         */
        this.small = false;
        this.isDesktop = breakpoints_subject.balBreakpoints.isDesktop;
    }
    breakpointListener(breakpoints) {
        this.isDesktop = breakpoints.desktop;
    }
    render() {
        const block = bem.BEM.block('field-hint');
        return (index.h(index.Host, { key: 'a5f895c418c0dfa249da93d3bc39f5563d31b547', class: Object.assign({}, block.class()) }, index.h("bal-hint", { key: '83d9c59c6fce044b361fbd471bf83780314c62e9', class: Object.assign({}, block.element('hint').class()), "data-testid": "bal-field-hint", closeLabel: this.closeLabel, small: this.small }, this.subject && !(this.hideTitleOnDesktop && this.isDesktop) ? (index.h("bal-hint-title", null, this.subject)) : (''), index.h("bal-hint-text", { key: '38b6ef5120c8b5adef31a05ad54f474ed55305f5' }, index.h("slot", { key: '040d24c305badac88e0bb64d21e513a067f6e177' })))));
    }
};
tslib_es6.__decorate([
    breakpoints_decorator.ListenToBreakpoints(),
    tslib_es6.__metadata("design:type", Function),
    tslib_es6.__metadata("design:paramtypes", [Object]),
    tslib_es6.__metadata("design:returntype", void 0)
], FieldHint.prototype, "breakpointListener", null);

const FieldLabel = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        /**
         * PUBLIC PROPERTY API
         * ------------------------------------------------------
         */
        /**
         * The value of the for attribute must be a single id for a labeled
         * form-related element in the same document as the <label> element.
         * So, any given label element can be associated with only one form control.
         */
        this.htmlFor = undefined;
        /**
         * If `true` the form control needs to be filled. If it is set to
         * `false` an optional label is added to the label..
         */
        this.required = true;
        /**
         * If `true` the component gets a valid green style.
         */
        this.valid = undefined;
        /**
         * If `true` the component gets a invalid red style.
         */
        this.invalid = undefined;
        /**
         * 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 = undefined;
        /**
         * If `true` the element can not mutated, meaning the user can not edit the control.
         */
        this.readonly = undefined;
        /**
         * Defines the size of the font. Default is like a heading 5 and small is used
         * with the form fields.
         */
        this.size = 'small';
        /**
         * Defines the font weight of the label.
         */
        this.weight = 'bold';
    }
    /**
     * LIFECYCLE
     * ------------------------------------------------------
     */
    componentDidLoad() {
        if (this.element) {
            this.parentBalFieldElement = this.element.closest('bal-field');
            if (this.parentBalFieldElement) {
                this.parentBalFieldElement.classList.add('has-label');
            }
        }
    }
    disconnectedCallback() {
        if (this.parentBalFieldElement) {
            this.parentBalFieldElement.classList.remove('has-label');
        }
    }
    /**
     * RENDER
     * ------------------------------------------------------
     */
    render() {
        return (index.h(index.Host, { key: '049f3e7c80126a7ffbc005e6c69a1bdc8203979b', class: "bal-field-label" }, index.h("bal-label", { key: '269ecb6de6a5daf2f4d4504b37f3980d05b1a121', multiline: true, size: this.size, htmlFor: this.htmlFor, required: this.required, valid: this.valid, invalid: this.invalid, disabled: this.disabled, readonly: this.readonly, weight: this.weight }, index.h("slot", { key: 'd832133cb85456ec6b7b1a999b5459044579e783' }))));
    }
    get element() { return index.getElement(this); }
};

const FieldMessage = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.ariaForm = form.defaultBalAriaForm;
        /**
         * Defines the color of the message.
         */
        this.color = '';
        /**
         * If `true` the component gets a invalid red style.
         */
        this.invalid = false;
        /**
         * If `true` the component gets a valid green style.
         */
        this.valid = false;
        /**
         * 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 element will not reserve any space for an upcoming message.
         */
        this.noReservedSpace = false;
    }
    /**
     * @internal
     */
    async setAriaForm(ariaForm) {
        this.ariaForm = Object.assign({}, ariaForm);
    }
    render() {
        return (index.h(index.Host, { key: 'f0425dd945959866c1edbfe0affa56a5c325a014', id: this.ariaForm.messageId, class: {
                'bal-field-message': true,
                'help': true,
                'is-danger': this.invalid,
                'is-success': this.valid,
                'is-disabled': this.disabled || this.readonly,
                [`is-${this.color}`]: !!this.color,
            }, style: { minHeight: this.noReservedSpace ? '0' : undefined } }, index.h("slot", { key: 'c693909e5e98a82db73d2884a4f804cf20e24ab3' })));
    }
};

exports.bal_field = Field;
exports.bal_field_control = FieldControl;
exports.bal_field_hint = FieldHint;
exports.bal_field_label = FieldLabel;
exports.bal_field_message = FieldMessage;
