import { createComponentOptionsManager, setMaybeRefValue, isObject, hasOwnProperty, hasNormalizedSlot, normalizeSlot, unrefWithDefault, isPromise, installStoreManager, applyStoreManagerOptions } from '@vuecs/core';
import { isReactive, h, defineComponent, unref, mergeProps, ref, toRef, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, computed, renderSlot, createTextVNode, toDisplayString, resolveComponent, withDirectives, vModelText, Fragment, renderList, createBlock, withCtx, normalizeClass, vShow, createCommentVNode } from 'vue';

function buildFormBaseOptions(options, component, defaults) {
    defaults = defaults || {};
    const manager = createComponentOptionsManager({
        name: component
    });
    return {
        ...options,
        slotItems: options.slotItems || {},
        class: manager.buildOrFail({
            key: 'class',
            value: options.class,
            alt: defaults.class || ''
        }),
        props: manager.buildOrFail({
            key: 'props',
            value: options.props,
            alt: defaults.props || {}
        })
    };
}
function handleFormValueChanged(options, value) {
    if (typeof options.value !== 'undefined') {
        if (isReactive(options.value)) {
            options.value = value;
        } else {
            setMaybeRefValue(options.value, value);
        }
    }
    if (options.onChange) {
        options.onChange.call(null, value);
    }
    return options;
}

var Component;
(function(Component) {
    Component["FormGroup"] = "formGroup";
    Component["FormInput"] = "formInput";
    Component["FormInputCheckbox"] = "formInputCheckbox";
    Component["FormInputText"] = "formInputText";
    Component["FormSelect"] = "formSelect";
    Component["FormSubmit"] = "formSubmit";
    Component["FormTextarea"] = "formTextarea";
})(Component || (Component = {}));
var SlotName;
(function(SlotName) {
    SlotName["DEFAULT"] = "default";
    SlotName["LABEL"] = "label";
    SlotName["HINT"] = "hint";
    SlotName["VALIDATION_GROUP"] = "validationGroup";
    SlotName["VALIDATION_ITEM"] = "validationItem";
})(SlotName || (SlotName = {}));

function isValidationRuleResultWithoutParams(input) {
    return isObject(input) && hasOwnProperty(input, '$message') && hasOwnProperty(input, '$pending') && hasOwnProperty(input, '$invalid') && hasOwnProperty(input, '$response');
}
function isValidationRuleResultWithParams(input) {
    return isValidationRuleResultWithoutParams(input) && hasOwnProperty(input, '$params');
}
function template(str, data, regex = /\{\{(.+?)\}\}/g) {
    return Array.from(str.matchAll(regex)).reduce((acc, match)=>{
        if (typeof data[match[1]] !== 'undefined') {
            return acc.replace(match[0], data[match[1]]);
        }
        return acc;
    }, str);
}

function buildValidationGroupOptions(options) {
    return {
        ...options,
        slotItems: options.slotItems || {},
        validationMessages: options.validationMessages || {},
        validationResult: options.validationResult || {}
    };
}
function buildValidationGroup(input) {
    const options = buildValidationGroupOptions(input);
    const translate = (validator, properties)=>{
        if (options.validationMessages && Object.prototype.hasOwnProperty.call(options.validationMessages, validator)) {
            return template(options.validationMessages[validator], properties || {});
        }
        if (typeof options.validationTranslator !== 'undefined') {
            let translation = options.validationTranslator(validator, properties || {});
            if (typeof translation === 'string') {
                translation = template(translation, properties || {});
                if (translation !== validator) {
                    return translation;
                }
            }
        }
        return `The ${validator} operator condition is not fulfilled.`;
    };
    const errors = [];
    const keys = Object.keys(options.validationResult);
    for(let i = 0; i < keys.length; i++){
        if (isObject(options.validationResult[keys[i]]) && options.validationResult[keys[i]].$invalid) {
            if (isValidationRuleResultWithParams(options.validationResult[keys[i]])) {
                errors.push(translate(keys[i], options.validationResult[keys[i]].$params));
            } else if (isValidationRuleResultWithoutParams(options.validationResult[keys[i]])) {
                errors.push(translate(keys[i]));
            }
        }
    }
    const invalid = !!options.validationResult && !!options.validationResult.$dirty && !!options.validationResult.$invalid;
    if (hasNormalizedSlot(SlotName.VALIDATION_GROUP, options.slotItems)) {
        return normalizeSlot(SlotName.VALIDATION_GROUP, {
            data: errors,
            invalid
        }, options.slotItems);
    }
    const children = [];
    for(let i = 0; i < errors.length; i++){
        if (hasNormalizedSlot(SlotName.VALIDATION_ITEM, options.slotItems)) {
            children.push(normalizeSlot(SlotName.VALIDATION_ITEM, {
                data: errors[i],
                invalid
            }, options.slotItems));
        } else {
            children.push(h('div', {
                class: 'form-group-hint group-required'
            }, [
                errors[i]
            ]));
        }
    }
    return children;
}

function buildFormGroupOptions(input) {
    const manager = createComponentOptionsManager({
        name: Component.FormGroup
    });
    return {
        ...input,
        slotItems: input.slotItems || {},
        hint: manager.build({
            key: 'hint',
            value: input.hint
        }),
        hintClass: manager.buildOrFail({
            key: 'hintClass',
            value: input.hintClass,
            alt: []
        }),
        hintContent: manager.build({
            key: 'hintContent',
            value: input.hintContent
        }),
        hintTag: manager.buildOrFail({
            key: 'hintTag',
            value: input.hintTag,
            alt: 'div'
        }),
        class: manager.buildOrFail({
            key: 'class',
            value: input.class,
            alt: []
        }),
        props: manager.buildOrFail({
            key: 'props',
            value: input.props,
            alt: {}
        }),
        label: manager.build({
            key: 'label',
            value: input.label
        }),
        labelClass: manager.buildOrFail({
            key: 'labelClass',
            value: input.labelClass,
            alt: []
        }),
        labelContent: manager.build({
            key: 'labelContent',
            value: input.labelContent
        }),
        labelTag: manager.buildOrFail({
            key: 'labelTag',
            value: input.labelTag,
            alt: 'label'
        }),
        validation: manager.buildOrFail({
            key: 'validation',
            value: input.validation,
            alt: true
        }),
        validationMessages: input.validationMessages || {},
        validationResult: input.validationResult || {},
        // errorClass
        validationErrorClass: manager.buildOrFail({
            key: 'validationErrorClass',
            value: input.validationErrorClass,
            alt: []
        }),
        // warningClass
        validationWarningClass: manager.buildOrFail({
            key: 'validationWarningClass',
            value: input.validationWarningClass,
            alt: []
        })
    };
}
function buildFormGroup(input) {
    const options = buildFormGroupOptions(input);
    const children = [];
    let label;
    if (typeof options.label === 'boolean') {
        label = options.label;
    } else {
        label = !!options.labelContent || hasNormalizedSlot(SlotName.LABEL, options.slotItems);
    }
    if (label) {
        if (hasNormalizedSlot(SlotName.LABEL, options.slotItems)) {
            children.push(h(options.labelTag, {
                class: options.labelClass
            }, [
                normalizeSlot(SlotName.LABEL, {}, options.slotItems)
            ]));
        } else if (options.labelContent) {
            children.push(h(options.labelTag, {
                class: options.labelClass
            }, [
                options.labelContent
            ]));
        }
    }
    if (hasNormalizedSlot(SlotName.DEFAULT, options.slotItems)) {
        children.push(normalizeSlot(SlotName.DEFAULT, {}, options.slotItems));
    } else if (options.content) {
        children.push(options.content);
    }
    if (options.validation) {
        children.push(buildValidationGroup({
            slotItems: options.slotItems,
            validationResult: options.validationResult,
            validationMessages: options.validationMessages,
            validationTranslator: options.validationTranslator
        }));
    }
    let hint;
    if (typeof options.hint === 'boolean') {
        hint = options.hint;
    } else {
        hint = !!options.hintContent || hasNormalizedSlot(SlotName.HINT, options.slotItems);
    }
    if (hint) {
        if (hasNormalizedSlot(SlotName.HINT, options.slotItems)) {
            children.push(h(options.hintTag, {
                class: options.hintClass
            }, [
                normalizeSlot(SlotName.HINT, {}, options.slotItems)
            ]));
        } else if (options.hintContent) {
            children.push(h(options.hintTag, {
                class: options.hintClass
            }, [
                options.hintContent
            ]));
        }
    }
    return h('div', {
        class: [
            options.class,
            ...options.validationResult && options.validationResult.$invalid && options.validationResult.$dirty ? [
                options.validationErrorClass
            ] : [],
            ...options.validationResult && options.validationResult.$invalid && !options.validationResult.$dirty ? [
                options.validationWarningClass
            ] : []
        ],
        ...options.props
    }, children);
}

const VCFormGroup = defineComponent({
    slots: Object,
    props: {
        label: {
            type: Boolean,
            default: undefined
        },
        labelClass: {
            type: String
        },
        labelContent: {
            type: String
        },
        hint: {
            type: Boolean,
            default: undefined
        },
        hintClass: {
            type: String
        },
        hintContent: {
            type: String
        },
        validation: {
            type: Boolean,
            default: undefined
        },
        validationResult: {
            type: Object,
            default: undefined
        },
        validationMessages: {
            type: Object,
            default: undefined
        },
        validationTranslator: {
            type: Function,
            default: undefined
        }
    },
    setup (props, { attrs, slots }) {
        return ()=>buildFormGroup({
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                hint: props.hint,
                hintClass: props.hintClass,
                hintContent: props.hintContent,
                validation: props.validation,
                validationResult: props.validationResult,
                validationMessages: props.validationMessages,
                validationTranslator: props.validationTranslator,
                slotItems: slots,
                props: attrs
            });
    }
});

function buildFormInputOptions(input, component) {
    component = component || Component.FormInput;
    const options = buildFormBaseOptions(input, component);
    const manager = createComponentOptionsManager({
        name: component
    });
    return {
        ...options,
        type: manager.buildOrFail({
            key: 'type',
            value: options.type,
            alt: 'text'
        }),
        group: manager.buildOrFail({
            key: 'group',
            value: options.group,
            alt: false
        }),
        groupClass: manager.buildOrFail({
            key: 'groupClass',
            value: options.groupClass,
            alt: []
        }),
        groupAppend: manager.buildOrFail({
            key: 'groupAppend',
            value: options.groupAppend,
            alt: false
        }),
        groupAppendClass: manager.build({
            key: 'groupAppendClass',
            value: options.groupAppendClass,
            alt: ''
        }),
        groupAppendContent: manager.build({
            key: 'groupAppendContent',
            value: options.groupAppendContent,
            alt: ''
        }),
        groupPrepend: manager.buildOrFail({
            key: 'groupPrepend',
            value: options.groupPrepend,
            alt: false
        }),
        groupPrependClass: manager.build({
            key: 'groupPrependClass',
            value: options.groupPrependClass,
            alt: ''
        }),
        groupPrependContent: manager.build({
            key: 'groupPrependContent',
            value: options.groupPrependContent,
            alt: ''
        })
    };
}
function buildFormInput(input) {
    const options = buildFormInputOptions(input);
    return buildFormInputFromOptions(options);
}
function buildFormInputFromOptions(options) {
    const children = [];
    if (options.groupPrepend) {
        children.push(h('span', {
            class: options.groupPrependClass
        }, [
            options.groupPrependContent
        ]));
    }
    const rawValue = unref(options.value);
    children.push(h('input', mergeProps({
        type: options.type,
        class: options.class,
        onInput ($event) {
            if ($event.target.composing) {
                return;
            }
            handleFormValueChanged(options, $event.target.value);
        },
        ...typeof rawValue !== 'undefined' ? {
            value: rawValue
        } : {}
    }, options.props)));
    if (options.groupAppend) {
        children.push(h('span', {
            class: options.groupAppendClass
        }, [
            options.groupAppendContent
        ]));
    }
    if (children.length > 1 || options.group) {
        return h('div', {
            class: options.groupClass
        }, children);
    }
    return children[0];
}

const VCFormInput = defineComponent({
    props: {
        modelValue: {
            type: String,
            default: ''
        },
        type: {
            type: String,
            default: 'text'
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormInput({
                type: props.type,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                props: attrs
            });
    }
});

function buildFormInputCheckboxOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormInputCheckbox);
    const manager = createComponentOptionsManager({
        name: Component.FormInputCheckbox
    });
    return {
        ...options,
        group: manager.buildOrFail({
            key: 'group',
            value: options.group,
            alt: false
        }),
        groupClass: manager.buildOrFail({
            key: 'groupClass',
            value: unref(options.groupClass),
            alt: ''
        }),
        label: manager.buildOrFail({
            key: 'label',
            value: options.label,
            alt: true
        }),
        labelClass: manager.buildOrFail({
            key: 'labelClass',
            value: options.labelClass,
            alt: []
        }),
        labelContent: manager.buildOrFail({
            key: 'labelContent',
            value: options.labelContent,
            alt: 'Input'
        })
    };
}
function buildFormInputCheckbox(input) {
    const options = buildFormInputCheckboxOptions(input);
    const id = (Math.random() + 1).toString(36).substring(7);
    const rawValue = unref(options.value);
    let isChecked;
    let index = -1;
    if (typeof rawValue !== 'undefined') {
        if (Array.isArray(rawValue)) {
            if (typeof options.props.value !== 'undefined') {
                index = rawValue.indexOf(options.props.value);
                isChecked = index !== -1;
            }
        } else {
            isChecked = !!rawValue;
        }
    }
    const element = h('input', mergeProps({
        id,
        type: 'checkbox',
        class: options.class,
        onInput ($event) {
            if ($event.target.composing) {
                return;
            }
            if (Array.isArray(rawValue)) {
                if (typeof options.props.value !== 'undefined') {
                    if (index === -1) {
                        rawValue.push(options.props.value);
                    } else {
                        rawValue.splice(index, 1);
                    }
                }
                handleFormValueChanged(options, rawValue);
            } else {
                handleFormValueChanged(options, !rawValue);
            }
        },
        ...typeof isChecked === 'boolean' ? {
            checked: isChecked
        } : {}
    }, options.props));
    if (options.label || options.group) {
        const children = [];
        if (options.label) {
            if (hasNormalizedSlot(SlotName.LABEL, options.slotItems)) {
                children.push(normalizeSlot(SlotName.LABEL, {
                    class: options.class,
                    id
                }, options.slotItems));
            } else {
                children.push(h('label', {
                    class: options.labelClass,
                    for: id
                }, [
                    options.labelContent
                ]));
            }
        }
        children.push(element);
        return h('div', {
            class: options.groupClass
        }, children);
    }
    return element;
}

const VCFormInputCheckbox = defineComponent({
    slots: Object,
    props: {
        modelValue: {
            type: [
                Object,
                Boolean,
                String,
                Number,
                Array
            ]
        },
        group: {
            type: Boolean
        },
        groupClass: {
            type: String
        },
        label: {
            type: Boolean
        },
        labelClass: {
            type: String
        },
        labelContent: {
            type: String
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit, slots }) {
        return ()=>buildFormInputCheckbox({
                group: props.group,
                groupClass: props.groupClass,
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                slotItems: slots,
                props: attrs
            });
    }
});

function buildFormInputText(input) {
    const options = buildFormInputOptions(input, Component.FormInputText);
    return buildFormInputFromOptions(options);
}

class FormRangeSliderThumb {
    mount() {
        this.el.addEventListener('mousedown', this.mouseDownEventHandler.bind(this));
        this.el.addEventListener('touchstart', this.touchStartEventHandler.bind(this));
    }
    unmount() {
        this.el.removeEventListener('mousedown', this.mouseDownEventHandler.bind(this));
        this.el.removeEventListener('touchstart', this.touchStartEventHandler.bind(this));
    }
    update(event) {
        event.preventDefault();
        event.stopPropagation();
        this.interval = setInterval(()=>{
            this.drag();
        }, 2);
    }
    setPercent(percent, update = true) {
        this.percent = percent;
        this.el.style.left = `calc(${percent}% - ${16 / 2}px)`;
        if (!update) return;
        this.parent.change();
    }
    getPercent() {
        return this.percent;
    }
    stopDrag() {
        if (!this.interval) return;
        clearInterval(this.interval);
        this.interval = undefined;
    }
    drag() {
        this.setPercent(this.parent.mousePercent());
    }
    mouseDownEventHandler(event) {
        this.update(event);
    }
    touchStartEventHandler(event) {
        this.update(event);
    }
    constructor(el, parent){
        this.percent = 0;
        if (!el) throw new Error('Thumb was undefined');
        this.parent = parent;
        this.el = el;
    }
}

class FormRangeSlider {
    mount() {
        this.trackElement.addEventListener('click', this.clickEventHandler.bind(this));
        this.trackElement.addEventListener('touchend', this.touchendEventHandler.bind(this));
        this.sliderMin = new FormRangeSliderThumb(this.el.querySelector('.lower'), this);
        this.sliderMin.mount();
        this.sliderMin.setPercent(this._min);
        this.sliderMax = new FormRangeSliderThumb(this.el.querySelector('.upper'), this);
        this.sliderMax.mount();
        this.sliderMax.setPercent(this._max);
        if (typeof window !== 'undefined') {
            window.addEventListener('mousemove', this.mouseMoveEventHandler.bind(this));
            window.addEventListener('mouseup', this.mouseUpEventHandler.bind(this));
            window.addEventListener('touchmove', this.touchMoveEventHandler.bind(this));
            window.addEventListener('touchend', this.touchEndEventHandler.bind(this));
        }
    }
    unmount() {
        this.trackElement.removeEventListener('click', this.clickEventHandler);
        this.trackElement.removeEventListener('touchend', this.touchendEventHandler);
        if (this.sliderMin) {
            this.sliderMin.unmount();
            this.sliderMin = undefined;
        }
        if (this.sliderMax) {
            this.sliderMax.unmount();
            this.sliderMax = undefined;
        }
        if (typeof window !== 'undefined') {
            window.removeEventListener('mousemove', this.mouseMoveEventHandler);
            window.removeEventListener('mouseup', this.mouseUpEventHandler);
            window.removeEventListener('touchmove', this.touchMoveEventHandler);
            window.removeEventListener('touchend', this.touchEndEventHandler);
        }
    }
    mousePercent() {
        const newBoundingClientRect = this.el.getBoundingClientRect();
        this.x = newBoundingClientRect.x;
        this.width = newBoundingClientRect.width;
        const val = (this.mouseX - this.x) / this.width * 100;
        if (val < 0) return 0;
        if (val > 100) return 100;
        return val;
    }
    change() {
        if (!this.sliderMin || !this.sliderMax) return;
        const newMin = this.sliderMin.getPercent();
        const newMax = this.sliderMax.getPercent();
        if (newMax - newMin - 1 <= 0) {
            this.sliderMin.setPercent(this._min, false);
            this.sliderMax.setPercent(this._max, false);
            return;
        }
        this._min = newMin;
        this._max = newMax;
        this.updateDiff();
        this.el.dispatchEvent(new CustomEvent('change'));
    }
    get min() {
        return this._min;
    }
    set min(value) {
        if (!this.sliderMin) return;
        if (value >= this._max) return;
        this._min = value;
        this.sliderMin.setPercent(this._min);
        this.change();
    }
    get max() {
        return this._max;
    }
    set max(value) {
        if (!this.sliderMax) return;
        if (value <= this._min) return;
        this._max = value;
        this.sliderMax.setPercent(this._max);
        this.change();
    }
    updateDiff() {
        if (!this.diffElement) return;
        this.diffElement.style.left = `${this._min}%`;
        this.diffElement.style.width = `${this._max - this._min}%`;
    }
    static getTouchPosition(event) {
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-expect-error
        event = typeof event.originalEvent === 'undefined' ? event : event.originalEvent;
        const touch = event.touches[0] || event.changedTouches[0];
        if (!touch) return -1;
        return touch.pageX;
    }
    mouseMoveEventHandler(event) {
        this.mouseX = event.x;
    }
    mouseUpEventHandler() {
        if (!this.sliderMin || !this.sliderMax) return;
        this.sliderMin.stopDrag();
        this.sliderMax.stopDrag();
    }
    touchMoveEventHandler(event) {
        this.mouseX = FormRangeSlider.getTouchPosition(event);
    }
    touchEndEventHandler() {
        if (!this.sliderMin || !this.sliderMax) return;
        this.sliderMin.stopDrag();
        this.sliderMax.stopDrag();
    }
    clickEventHandler(event) {
        this.handleClick(event.x);
    }
    touchendEventHandler(event) {
        this.handleClick(FormRangeSlider.getTouchPosition(event));
    }
    handleClick(position) {
        if (!this.sliderMin || !this.sliderMax) {
            return;
        }
        this.mouseX = position;
        const percent = this.mousePercent();
        const thumb = Math.abs(this.sliderMin.getPercent() - percent) <= Math.abs(this.sliderMax.getPercent() - percent) ? this.sliderMin : this.sliderMax;
        thumb.setPercent(percent);
    }
    constructor(ctx){
        this._min = ctx.min;
        this._max = ctx.max;
        this.mouseX = 0;
        this.el = ctx.el;
        const track = this.el.querySelector('.track');
        track.style.cursor = 'pointer';
        this.trackElement = track;
        const boundingClientRect = this.el.getBoundingClientRect();
        this.width = boundingClientRect.width;
        this.x = boundingClientRect.x;
        this.diffElement = this.el.querySelector('.track-diff');
        this.updateDiff();
    }
}

var _sfc_main$2 = defineComponent({
    props: {
        min: {
            type: Number,
            default: 0
        },
        max: {
            type: Number,
            default: 100
        }
    },
    emits: [
        'change'
    ],
    setup (props, { emit }) {
        const el = ref(null);
        let instance;
        const min = toRef(props, 'min');
        const max = toRef(props, 'max');
        watch(min, (value)=>{
            if (instance) {
                instance.min = value;
            }
        });
        watch(max, (value)=>{
            if (instance) {
                instance.max = value;
            }
        });
        onMounted(()=>{
            instance = new FormRangeSlider({
                el: el.value,
                min: props.min,
                max: props.max
            });
            instance.mount();
        });
        onUnmounted(()=>{
            if (instance) {
                instance.unmount();
            }
        });
        const handleChanged = ()=>{
            if (!instance) return;
            emit('change', {
                min: instance.min,
                max: instance.max
            });
        };
        return {
            el,
            handleChanged
        };
    }
});

var _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};

const _hoisted_1$1 = /* @__PURE__ */ createElementVNode("div", {
    class: "track"
}, [
    /* @__PURE__ */ createElementVNode("div", {
        class: "thumb upper"
    }),
    /* @__PURE__ */ createElementVNode("div", {
        class: "thumb lower"
    }),
    /* @__PURE__ */ createElementVNode("div", {
        class: "track-diff"
    })
], -1);
const _hoisted_2$1 = [
    _hoisted_1$1
];
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
    return openBlock(), createElementBlock("div", {
        ref: "el",
        class: "form-range-multi-slider",
        onChange: _cache[0] || (_cache[0] = (...args)=>_ctx.handleChanged && _ctx.handleChanged(...args))
    }, [
        ..._hoisted_2$1
    ], 544);
}
var VCFormRangeMultiSlider = /* @__PURE__ */ _export_sfc(_sfc_main$2, [
    [
        "render",
        _sfc_render$2
    ],
    [
        "__file",
        "/home/runner/work/vuecs/vuecs/packages/form-controls/src/components/form-range-multi-slider/FormRangeMultiSlider.vue"
    ]
]);

function buildFormSelectOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormSelect);
    const manager = createComponentOptionsManager({
        name: Component.FormSelect
    });
    return {
        ...options,
        options: options.options,
        optionDefault: manager.buildOrFail({
            key: 'optionDefault',
            value: options.optionDefault,
            alt: true
        }),
        optionDefaultId: manager.buildOrFail({
            key: 'optionDefaultId',
            value: options.optionDefaultId,
            alt: ''
        }),
        optionDefaultValue: manager.buildOrFail({
            key: 'optionDefaultValue',
            value: options.optionDefaultValue,
            alt: '-- Select --'
        })
    };
}
function buildFormSelect(input) {
    const options = buildFormSelectOptions(input);
    const rawValue = unref(options.value);
    const children = [];
    if (options.optionDefault) {
        children.push(h('option', {
            value: options.optionDefaultId
        }, [
            options.optionDefaultValue
        ]));
    }
    for(let i = 0; i < options.options.length; i++){
        children.push(h('option', {
            key: options.options[i].id,
            value: options.options[i].id,
            selected: options.options[i].id === rawValue
        }, options.options[i].value));
    }
    return h('select', mergeProps({
        class: options.class,
        onChange ($event) {
            const $$selectedVal = Array.prototype.filter.call($event.target.options, (o)=>o.selected).map((o)=>'_value' in o ? o._value : o.value);
            const value = $event.target.multiple ? $$selectedVal : $$selectedVal[0];
            handleFormValueChanged(options, value);
        },
        ...typeof rawValue !== 'undefined' ? {
            value: rawValue
        } : {}
    }, options.props), children);
}

const VCFormSelect = defineComponent({
    props: {
        modelValue: {
            type: String,
            default: ''
        },
        options: {
            type: Object,
            required: true
        },
        optionDefault: {
            type: Boolean,
            default: true
        },
        optionDefaultId: {
            type: [
                String,
                Number
            ]
        },
        optionDefaultValue: {
            type: String
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormSelect({
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                props: attrs,
                options: props.options,
                optionDefault: props.optionDefault,
                optionDefaultId: props.optionDefaultId,
                optionDefaultValue: props.optionDefaultValue
            });
    }
});

var _sfc_main$1 = defineComponent({
    props: {
        entry: {
            type: Object,
            required: true
        },
        selected: {
            type: Array
        }
    },
    setup (props) {
        const active = computed(()=>props.selected && props.selected.findIndex((el)=>el.id === props.entry.id) !== -1);
        return {
            active
        };
    }
});

function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
    return renderSlot(_ctx.$slots, "default", {
        entry: _ctx.entry,
        active: _ctx.active
    }, ()=>[
            createTextVNode(toDisplayString(_ctx.entry.id), 1)
        ]);
}
var FormSelectSearchEntry = /* @__PURE__ */ _export_sfc(_sfc_main$1, [
    [
        "render",
        _sfc_render$1
    ],
    [
        "__file",
        "/home/runner/work/vuecs/vuecs/packages/form-controls/src/components/form-select-search/FormSelectSearchEntry.vue"
    ]
]);

var _sfc_main = defineComponent({
    components: {
        FormSelectSearchEntry
    },
    props: {
        modelValue: {
            type: [
                String,
                Object,
                Array
            ],
            default: ''
        },
        options: {
            type: Array,
            required: true,
            default: ()=>[]
        },
        placeholder: {
            type: String,
            required: false,
            default: '...'
        },
        disabled: {
            type: Boolean,
            required: false,
            default: false
        },
        maxItems: {
            type: Number,
            required: false,
            default: 6
        }
    },
    emits: [
        'update:modelValue',
        'change'
    ],
    async setup (props, { emit }) {
        const q = ref('');
        const currentIndex = ref(-1);
        const selected = ref([]);
        const modelValue = toRef(props, 'modelValue');
        const reset = ()=>{
            if (Array.isArray(props.modelValue)) {
                selected.value = [
                    ...props.modelValue
                ];
                return;
            }
            if (typeof props.modelValue === 'undefined' || props.modelValue === null) {
                selected.value = [];
                q.value = '';
                return;
            }
            const index = props.options.findIndex((el)=>el.id === props.modelValue);
            if (index !== -1) {
                selected.value = [
                    props.options[index]
                ];
                q.value = props.options[index].value;
            } else {
                selected.value = [];
                q.value = '';
            }
        };
        reset();
        watch(modelValue, ()=>{
            reset();
        }, {
            deep: true
        });
        const isMulti = computed(()=>Array.isArray(modelValue.value));
        const isScalar = computed(()=>typeof modelValue.value === 'string' || typeof modelValue.value === 'number' || typeof modelValue.value === 'undefined' || modelValue.value === null);
        const items = computed(()=>{
            const output = [];
            const pattern = new RegExp(q.value, 'ig');
            for(let i = 0; i < props.options.length; i++){
                const option = props.options[i];
                if (!q.value || q.value.length < 1 || option.value.match(pattern)) {
                    if (output.length < props.maxItems) {
                        output.push(option);
                    }
                }
            }
            return output;
        });
        const itemsLength = computed(()=>items.value.length);
        watch(itemsLength, (val, oldValue)=>{
            if (val !== oldValue) {
                currentIndex.value = 0;
            }
        });
        const isDisplayed = ref(false);
        const toggle = (option)=>{
            if (isMulti.value) {
                const index = selected.value.findIndex((el)=>el.id === option.id);
                if (index === -1) {
                    selected.value.push(option);
                } else {
                    selected.value.splice(index, 1);
                }
                emit('update:modelValue', selected.value);
                emit('change', selected.value);
                return;
            }
            let isBlank = false;
            const [selectedValue] = selected.value;
            if (selectedValue) {
                if (selectedValue.id === option.id) {
                    q.value = '';
                    selected.value.length = 0;
                    isBlank = true;
                } else {
                    q.value = option.value;
                    selected.value = [
                        option
                    ];
                }
            } else {
                q.value = option.value;
                selected.value = [
                    option
                ];
            }
            isDisplayed.value = false;
            if (isBlank) {
                emit('update:modelValue', null);
                emit('change', null);
                return;
            }
            if (isScalar.value) {
                emit('update:modelValue', option.id);
                emit('change', option.id);
            } else {
                emit('update:modelValue', option);
                emit('change', option);
            }
        };
        const display = ()=>{
            if (props.disabled) return;
            isDisplayed.value = true;
        };
        const hide = ()=>{
            if (!isMulti.value && selected.value.length === 1) {
                q.value = selected.value[0].value;
            }
            isDisplayed.value = false;
        };
        const toggleHide = (option)=>{
            isDisplayed.value = false;
            toggle(option);
        };
        const onBlur = ()=>{
            hide();
        };
        const onFocus = ()=>{
            q.value = '';
            display();
        };
        const onKeyUp = (ev)=>{
            if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') {
                display();
                if (ev.key === 'ArrowUp') {
                    if (currentIndex.value > 0) {
                        currentIndex.value--;
                    }
                    return;
                }
                if (currentIndex.value < items.value.length - 1) {
                    currentIndex.value++;
                }
            }
            if (ev.key !== 'Enter') {
                display();
            }
        };
        const onKeyDown = (ev)=>{
            if (ev.key === 'Enter') {
                if (!isDisplayed.value) {
                    return;
                }
                if (items.value.length === 1) {
                    toggleHide(items.value[0]);
                    return;
                }
                if (currentIndex.value >= 0 && items.value[currentIndex.value]) {
                    toggleHide(items.value[currentIndex.value]);
                    return;
                }
                if (selected.value.length === 0) {
                    if (items.value[0]) {
                        toggleHide(items.value[0]);
                    }
                    return;
                }
                hide();
                return;
            }
            if (ev.key === 'Tab') {
                hide();
            }
        };
        const onMouseLeave = (event)=>{
            event.preventDefault();
            hide();
        };
        return {
            isMulti,
            toggle,
            toggleHide,
            currentIndex,
            q,
            items,
            selected,
            display,
            onBlur,
            onFocus,
            onKeyUp,
            onKeyDown,
            onMouseLeave,
            isDisplayed
        };
    }
});

const _hoisted_1 = {
    class: "form-select-search"
};
const _hoisted_2 = [
    "disabled",
    "placeholder"
];
const _hoisted_3 = [
    "onMousedown"
];
const _hoisted_4 = {
    key: 0,
    class: "form-select-search-selected"
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
    const _component_FormSelectSearchEntry = resolveComponent("FormSelectSearchEntry");
    return openBlock(), createElementBlock("div", _hoisted_1, [
        withDirectives(createElementVNode("input", {
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event)=>_ctx.q = $event),
            class: "form-select-search-input",
            disabled: _ctx.disabled,
            placeholder: _ctx.placeholder,
            onFocus: _cache[1] || (_cache[1] = (...args)=>_ctx.onFocus && _ctx.onFocus(...args)),
            onKeyup: _cache[2] || (_cache[2] = (...args)=>_ctx.onKeyUp && _ctx.onKeyUp(...args)),
            onKeydown: _cache[3] || (_cache[3] = (...args)=>_ctx.onKeyDown && _ctx.onKeyDown(...args)),
            onBlur: _cache[4] || (_cache[4] = (...args)=>_ctx.onBlur && _ctx.onBlur(...args))
        }, null, 40, _hoisted_2), [
            [
                vModelText,
                _ctx.q
            ]
        ]),
        withDirectives(createElementVNode("div", {
            class: "form-select-search-content",
            onMouseleave: _cache[5] || (_cache[5] = (...args)=>_ctx.onMouseLeave && _ctx.onMouseLeave(...args))
        }, [
            (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (option, index)=>{
                return openBlock(), createBlock(_component_FormSelectSearchEntry, {
                    key: option.id,
                    entry: option,
                    selected: _ctx.selected
                }, {
                    default: withCtx(({ entry, active })=>[
                            createElementVNode("div", {
                                class: normalizeClass([
                                    "form-select-search-item",
                                    {
                                        "active": active,
                                        "current": index === _ctx.currentIndex || index === 0 && _ctx.currentIndex === -1
                                    }
                                ]),
                                onMousedown: ($event)=>_ctx.toggleHide(entry)
                            }, toDisplayString(entry.value), 43, _hoisted_3)
                        ]),
                    _: 2
                }, 1032, [
                    "entry",
                    "selected"
                ]);
            }), 128))
        ], 544), [
            [
                vShow,
                _ctx.isDisplayed
            ]
        ]),
        _ctx.isMulti ? (openBlock(), createElementBlock("div", _hoisted_4, [
            renderSlot(_ctx.$slots, "selected", {
                items: _ctx.selected,
                toggle: _ctx.toggle
            }, ()=>[
                    (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.selected, (item)=>{
                        return openBlock(), createElementBlock(Fragment, {
                            key: item.id
                        }, [
                            createTextVNode(toDisplayString(item.value), 1)
                        ], 64);
                    }), 128))
                ])
        ])) : createCommentVNode("v-if", true)
    ]);
}
var VCFormSelectSearch = /* @__PURE__ */ _export_sfc(_sfc_main, [
    [
        "render",
        _sfc_render
    ],
    [
        "__file",
        "/home/runner/work/vuecs/vuecs/packages/form-controls/src/components/form-select-search/FormSelectSearch.vue"
    ]
]);

function buildFormSubmitOptions(options) {
    const manager = createComponentOptionsManager({
        name: Component.FormSubmit
    });
    return {
        ...options,
        type: manager.buildOrFail({
            key: 'type',
            value: options.type,
            alt: 'button'
        }),
        class: manager.buildOrFail({
            key: 'class',
            value: options.class,
            alt: []
        }),
        props: manager.buildOrFail({
            key: 'props',
            value: options.props,
            alt: {}
        }),
        icon: manager.buildOrFail({
            key: 'icon',
            value: options.icon,
            alt: true
        }),
        validationResult: unrefWithDefault(options.validationResult, {}),
        updateText: manager.buildOrFail({
            key: 'updateText',
            value: options.updateText,
            alt: 'Update'
        }),
        updateIconClass: manager.buildOrFail({
            key: 'updateIconClass',
            value: options.updateIconClass,
            alt: []
        }),
        updateButtonClass: manager.buildOrFail({
            key: 'updateButtonClass',
            value: options.updateButtonClass,
            alt: []
        }),
        createText: manager.buildOrFail({
            key: 'createText',
            value: options.createText,
            alt: 'Create'
        }),
        createIconClass: manager.buildOrFail({
            key: 'createIconClass',
            value: options.createIconClass,
            alt: []
        }),
        createButtonClass: manager.buildOrFail({
            key: 'createButtonClass',
            value: options.createButtonClass,
            alt: []
        }),
        busy: options.busy ?? false,
        valid: options.valid ?? true,
        isEditing: options.isEditing ?? false
    };
}
function buildFormSubmit(input) {
    const options = buildFormSubmitOptions(input);
    let icon = [];
    if (options.icon) {
        icon = [
            h('i', {
                class: [
                    ...options.isEditing ? [
                        options.updateIconClass
                    ] : [],
                    ...!options.isEditing ? [
                        options.createIconClass
                    ] : []
                ]
            })
        ];
    }
    return h(options.type, mergeProps({
        ...options.type === 'button' ? {
            type: 'submit'
        } : {},
        class: [
            ...options.isEditing ? [
                options.updateButtonClass
            ] : [],
            ...!options.isEditing ? [
                options.createButtonClass
            ] : []
        ],
        disabled: options.validationResult.$invalid || !options.valid || unref(options.busy),
        onClick ($event) {
            $event.preventDefault();
            setMaybeRefValue(options.busy, true);
            const promise = options.submit();
            if (isPromise(promise)) {
                promise.finally(()=>{
                    setMaybeRefValue(options.busy, false);
                });
            }
            return promise;
        }
    }, options.props), [
        icon,
        ' ',
        options.isEditing ? options.updateText : options.createText
    ]);
}

const VCFormSubmit = defineComponent({
    props: {
        modelValue: {
            type: Boolean,
            default: false
        },
        icon: {
            type: Boolean,
            default: true
        },
        isEditing: {
            type: Boolean,
            default: false
        },
        busy: {
            type: Boolean,
            default: false
        },
        createText: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        createIconClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        createButtonClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateText: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateIconClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateButtonClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        submit: {
            type: Function
        },
        validationResult: {
            type: Object,
            default: undefined
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormSubmit({
                icon: props.icon,
                busy: props.modelValue || props.busy,
                isEditing: props.isEditing,
                createText: props.createText,
                createIconClass: props.createIconClass,
                createButtonClass: props.createButtonClass,
                updateText: props.updateText,
                updateIconClass: props.updateIconClass,
                updateButtonClass: props.updateButtonClass,
                submit () {
                    if (!props.submit) {
                        return;
                    }
                    emit('update:modelValue', true);
                    Promise.resolve().then(props.submit).then(()=>{
                        emit('update:modelValue', false);
                    });
                },
                validationResult: props.validationResult,
                props: attrs
            });
    }
});

function buildFormTextareaOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormTextarea);
    return {
        ...options
    };
}
function buildFormTextarea(input) {
    const options = buildFormTextareaOptions(input);
    const rawValue = unref(options.value);
    return h('textarea', mergeProps({
        placeholder: '...',
        class: options.class,
        onInput ($event) {
            if ($event.target.composing) {
                return;
            }
            handleFormValueChanged(options, $event.target.value);
        },
        ...typeof rawValue !== 'undefined' ? {
            value: rawValue
        } : {}
    }, options.props));
}

const VCFormTextarea = defineComponent({
    props: {
        modelValue: {
            type: String,
            default: ''
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormTextarea({
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                props: attrs
            });
    }
});

function install(instance, options = {}) {
    const storeManager = installStoreManager(instance);
    if (options.storeManager) {
        applyStoreManagerOptions(storeManager, options.storeManager);
    }
    Object.entries({
        VCFormGroup,
        VCFormInputCheckbox,
        VCFormInput,
        VCFormRangeMultiSlider,
        VCFormSelect,
        VCFormSelectSearch,
        VCFormSubmit,
        VCFormTextarea
    }).forEach(([componentName, component])=>{
        instance.component(componentName, component);
    });
}
var index = {
    install
};

export { Component, SlotName, VCFormGroup, VCFormInput, VCFormInputCheckbox, VCFormRangeMultiSlider, VCFormSelect, VCFormSelectSearch, VCFormSubmit, VCFormTextarea, buildFormBaseOptions, buildFormGroup, buildFormGroupOptions, buildFormInput, buildFormInputCheckbox, buildFormInputCheckboxOptions, buildFormInputFromOptions, buildFormInputOptions, buildFormInputText, buildFormSelect, buildFormSelectOptions, buildFormSubmit, buildFormSubmitOptions, buildFormTextarea, buildFormTextareaOptions, buildValidationGroup, buildValidationGroupOptions, index as default, handleFormValueChanged, install };
//# sourceMappingURL=index.mjs.map
