UNPKG

vue-formic-dynamic-forms

Version:

Powerful library for creating dynamic, validated forms in Vue 3 based on JSON schemas

1,568 lines 60.2 kB
var Te = Object.defineProperty; var Re = (a, e, i) => e in a ? Te(a, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : a[e] = i; var Z = (a, e, i) => Re(a, typeof e != "symbol" ? e + "" : e, i); import { ref as Q, computed as C, watch as $e, readonly as J, reactive as Le, defineComponent as _, createElementBlock as m, createCommentVNode as v, openBlock as c, normalizeClass as A, renderSlot as F, createElementVNode as $, createTextVNode as K, toDisplayString as S, mergeProps as X, onMounted as Se, onUnmounted as Ve, Fragment as Y, renderList as H, withDirectives as we, withModifiers as fe, vShow as Ee, useSlots as Oe, createBlock as ce, resolveDynamicComponent as Me, createSlots as me, withCtx as pe, normalizeProps as Ne, guardReactiveProps as He, unref as E } from "vue"; const le = { equals: (a, e) => a === e, notEquals: (a, e) => a !== e, contains: (a, e) => typeof a == "string" && typeof e == "string" || Array.isArray(a) ? a.includes(e) : !1, notContains: (a, e) => !le.contains(a, e), gt: (a, e) => { const i = Number(a), s = Number(e); return !isNaN(i) && !isNaN(s) && i > s; }, gte: (a, e) => { const i = Number(a), s = Number(e); return !isNaN(i) && !isNaN(s) && i >= s; }, lt: (a, e) => { const i = Number(a), s = Number(e); return !isNaN(i) && !isNaN(s) && i < s; }, lte: (a, e) => { const i = Number(a), s = Number(e); return !isNaN(i) && !isNaN(s) && i <= s; }, empty: (a) => a == null ? !0 : typeof a == "string" ? a.trim() === "" : Array.isArray(a) ? a.length === 0 : typeof a == "object" ? Object.keys(a).length === 0 : !1, notEmpty: (a) => !le.empty(a), in: (a, e) => Array.isArray(e) && e.includes(a), notIn: (a, e) => !le.in(a, e) }; function ze(a, e) { const i = Pe(e, a.field), s = le[a.operator]; return s ? a.operator === "in" || a.operator === "notIn" ? s(i, a.values || []) : a.operator === "empty" || a.operator === "notEmpty" ? s(i) : s(i, a.value) : (console.warn(`Unknown operator: ${a.operator}`), !1); } function se(a, e, i = "and") { if (!a || a.length === 0) return !0; const s = a.map((f) => ze(f, e)); return i === "and" ? s.every((f) => f) : s.some((f) => f); } function Ae(a, e) { const i = a.logic || "and"; let s = !0, f = !1, r = !1; return a.show && (s = se(a.show, e, i)), a.hide && se(a.hide, e, i) && (s = !1), a.required && (f = se(a.required, e, i)), a.disabled && (r = se(a.disabled, e, i)), { visible: s, required: f, disabled: r }; } function Pe(a, e) { return e.split(".").reduce((i, s) => i && typeof i == "object" ? i[s] : void 0, a); } class Ie { constructor(e = {}) { Z(this, "formData", {}); Z(this, "fieldConditions", /* @__PURE__ */ new Map()); Z(this, "cache", /* @__PURE__ */ new Map()); this.formData = { ...e }; } /** * Обновляет данные формы */ updateFormData(e) { this.formData = { ...e }, this.cache.clear(); } /** * Регистрирует условия для поля */ registerFieldConditions(e, i) { this.fieldConditions.set(e, i), this.cache.delete(e); } /** * Получает состояние поля на основе условий */ getFieldState(e) { const i = e; if (this.cache.has(i)) return this.cache.get(i); const s = this.fieldConditions.get(e); let f = { visible: !0, required: !1, disabled: !1 }; return s && (f = Ae(s, this.formData)), this.cache.set(i, f), f; } /** * Получает состояния всех зарегистрированных полей */ getAllFieldStates() { const e = {}; for (const i of this.fieldConditions.keys()) e[i] = this.getFieldState(i); return e; } /** * Проверяет, зависит ли поле от других полей */ getFieldDependencies(e) { const i = this.fieldConditions.get(e); if (!i) return []; const s = /* @__PURE__ */ new Set(), f = (r) => { r && r.forEach((l) => { s.add(l.field); }); }; return f(i.show), f(i.hide), f(i.required), f(i.disabled), Array.from(s); } /** * Получает все поля, которые зависят от указанного поля */ getDependentFields(e) { const i = []; for (const s of this.fieldConditions.keys()) this.getFieldDependencies(s).includes(e) && i.push(s); return i; } } function Ge(a, e) { var ie; const { formData: i, validationEngine: s, conditionsEngine: f, validateOnChange: r = !0, validateOnBlur: l = !0, debounceValidation: o = 300 } = e, t = Q({ value: a.defaultValue ?? "", error: null, touched: !1, dirty: !1, validating: !1, valid: !0, visible: !0, disabled: !1, required: ((ie = a.validation) == null ? void 0 : ie.required) ?? !1 }), b = Q([]), w = Q(!1), O = C({ get: () => t.value.value, set: (g) => { t.value.value = g, t.value.dirty = !0, i.value[a.name] = g, r && n(); } }), h = C(() => t.value.visible), q = C(() => { var g; return t.value.disabled || ((g = a.attributes) == null ? void 0 : g.disabled); }), I = C(() => t.value.required), M = C(() => !!t.value.error), G = C(() => t.value.validating), d = C(() => { var g, B; return a.conditions ? Ae(a.conditions, i.value) : { visible: !0, required: ((g = a.validation) == null ? void 0 : g.required) ?? !1, disabled: ((B = a.attributes) == null ? void 0 : B.disabled) ?? !1 }; }); $e(d, (g) => { t.value.visible = g.visible, t.value.required = g.required, t.value.disabled = g.disabled; }, { immediate: !0 }); async function n() { t.value.validating = !0; try { let g; return o > 0 ? g = await s.validateFieldDebounced( a, t.value.value, i.value, o ) : g = await s.validateField( a, t.value.value, i.value ), t.value.error = g.error || null, t.value.valid = g.isValid, g; } finally { t.value.validating = !1; } } function k() { } function y() { t.value.touched = !0, l && n(); } function D(g) { const B = g.target; let L = B.value; switch (a.type) { case "number": if (B.value === "") L = ""; else { const U = B.valueAsNumber; L = isNaN(U) ? B.value : U; } break; case "checkbox": L = B.checked; break; case "date": case "datetime-local": L = B.valueAsDate || B.value; break; case "file": L = B.files; break; default: L = B.value; } O.value = L; } function N(g) { D(g); } async function W() { if (Array.isArray(a.options)) { b.value = a.options; return; } if (typeof a.options == "function") { w.value = !0; try { b.value = await a.options(); } catch { b.value = []; } finally { w.value = !1; } } } function x() { t.value.value = a.defaultValue ?? "", t.value.error = null, t.value.touched = !1, t.value.dirty = !1, t.value.validating = !1, t.value.valid = !0, i.value[a.name] = t.value.value; } function re(g) { O.value = g; } function ae(g) { t.value.error = g, t.value.valid = !g; } function ne() { ae(null); } const te = C(() => { var B, L, U, u, p, V, j, z, De, ge, Ce, ke, Fe; const g = { id: `field-${a.name}`, name: a.name, type: a.type, value: O.value, required: I.value, disabled: q.value, readonly: (B = a.attributes) == null ? void 0 : B.readonly, placeholder: (L = a.attributes) == null ? void 0 : L.placeholder, autocomplete: (U = a.attributes) == null ? void 0 : U.autocomplete, pattern: (u = a.attributes) == null ? void 0 : u.pattern, min: (p = a.attributes) == null ? void 0 : p.min, max: (V = a.attributes) == null ? void 0 : V.max, step: (j = a.attributes) == null ? void 0 : j.step, multiple: (z = a.attributes) == null ? void 0 : z.multiple, accept: (De = a.attributes) == null ? void 0 : De.accept, rows: (ge = a.attributes) == null ? void 0 : ge.rows, cols: (Ce = a.attributes) == null ? void 0 : Ce.cols, maxlength: (ke = a.attributes) == null ? void 0 : ke.maxlength, minlength: (Fe = a.attributes) == null ? void 0 : Fe.minlength, "aria-invalid": M.value ? "true" : "false", "aria-describedby": M.value ? `field-${a.name}-error` : void 0 }; return Object.fromEntries( Object.entries(g).filter(([, je]) => je !== void 0) ); }), oe = C(() => { const g = []; return a.fieldClass && g.push(a.fieldClass), M.value && a.errorClass && g.push(a.errorClass), g.join(" "); }); function de() { i.value[a.name] = t.value.value, a.options && W(), a.conditions && f.registerFieldConditions(a.name, a.conditions); } return de(), { // Состояние fieldState: J(t), fieldValue: O, fieldOptions: J(b), loadingOptions: J(w), // Вычисляемые свойства isVisible: h, isDisabled: q, isRequired: I, hasError: M, isValidating: G, // Методы validateField: n, resetField: x, setValue: re, setError: ae, clearError: ne, loadOptions: W, // Обработчики событий handleFocus: k, handleBlur: y, handleInput: D, handleChange: N, // Атрибуты для привязки inputAttrs: te, inputClasses: oe, // Схема поля fieldSchema: J(a) }; } function R(a, e, i) { return (s) => ({ type: a, validate: e, message: s || i || `Validation failed for ${a}` }); } const We = R( "required", (a) => a == null ? !1 : typeof a == "string" ? a.trim().length > 0 : Array.isArray(a) ? a.length > 0 : typeof a == "boolean" ? !0 : typeof a == "number" ? !isNaN(a) : !0, "Это поле обязательно для заполнения" ), Ue = (a, e) => R( "minLength", (i) => i == null || i === "" ? !0 : String(i).length >= a, e || `Минимальная длина: ${a} символов` )(), Ye = (a, e) => R( "maxLength", (i) => i == null || i === "" ? !0 : String(i).length <= a, e || `Максимальная длина: ${a} символов` )(), Ke = (a, e) => R( "min", (i) => { if (i == null || i === "") return !0; const s = Number(i); return !isNaN(s) && s >= a; }, e || `Минимальное значение: ${a}` )(), Ze = (a, e) => R( "max", (i) => { if (i == null || i === "") return !0; const s = Number(i); return !isNaN(s) && s <= a; }, e || `Максимальное значение: ${a}` )(), Je = R( "email", (a) => a ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(a)) : !0, "Введите корректный email адрес" ), Qe = R( "url", (a) => { if (!a) return !0; try { return new URL(String(a)), !0; } catch { return !1; } }, "Введите корректный URL" ), Xe = (a, e) => R( "pattern", (i) => i ? (typeof a == "string" ? new RegExp(a) : a).test(String(i)) : !0, e || "Значение не соответствует требуемому формату" )(), _e = (a, e) => R( "oneOf", (i) => i == null ? !0 : a.includes(i), e || `Значение должно быть одним из: ${a.join(", ")}` )(), xe = (a, e) => R( "notOneOf", (i) => i == null ? !0 : !a.includes(i), e || `Значение не может быть одним из: ${a.join(", ")}` )(), ea = R( "number", (a) => a == null || a === "" ? !0 : !isNaN(Number(a)), "Значение должно быть числом" ), aa = R( "integer", (a) => { if (a == null || a === "") return !0; const e = Number(a); return !isNaN(e) && Number.isInteger(e); }, "Значение должно быть целым числом" ), ta = (a, e) => R( "custom", a, e || "Кастомная валидация не прошла" )(), ia = (a, e) => R( "sameAs", (i, s) => { const f = s[a]; return i === f; }, e || `Значение должно совпадать с полем ${a}` )(), sa = (a, e) => R( "differentFrom", (i, s) => { const f = s[a]; return i !== f; }, e || `Значение должно отличаться от поля ${a}` )(), P = { required: We, minLength: Ue, maxLength: Ye, min: Ke, max: Ze, email: Je, url: Qe, pattern: Xe, oneOf: _e, notOneOf: xe, number: ea, integer: aa, custom: ta, sameAs: ia, differentFrom: sa }; function ye(a) { if (typeof window < "u") switch (a) { case "yup": return !!window.yup; case "zod": return !!window.z; case "vee-validate": return !!window.VeeValidate; default: return !1; } return !1; } const la = { name: "yup", isAvailable() { return ye("yup"); }, async validate(a, e, i) { if (!this.isAvailable()) return [{ field: "unknown", message: "Yup library is not available", type: "error", value: e }]; try { return await a.validate(e, { context: i, abortEarly: !1 }), []; } catch (s) { return s.inner ? s.inner.map((f) => ({ field: f.path || "unknown", message: f.message, type: f.type || "validation", value: f.value })) : [{ field: s.path || "unknown", message: s.message, type: s.type || "validation", value: e }]; } } }, ra = { name: "zod", isAvailable() { return ye("zod"); }, async validate(a, e, i) { if (!this.isAvailable()) return [{ field: "unknown", message: "Zod library is not available", type: "error", value: e }]; try { return a.parse(e), []; } catch (s) { return s.errors ? s.errors.map((f) => { var r; return { field: ((r = f.path) == null ? void 0 : r.join(".")) || "unknown", message: f.message, type: f.code || "validation", value: e }; }) : [{ field: "unknown", message: s.message || "Validation failed", type: "validation", value: e }]; } } }, na = { name: "vee-validate", isAvailable() { return ye("vee-validate"); }, async validate(a, e, i) { if (!this.isAvailable()) return [{ field: "unknown", message: "VeeValidate library is not available", type: "error", value: e }]; try { let s; if (typeof a == "string") { if (s = window.VeeValidate[a], !s) throw new Error(`VeeValidate rule "${a}" not found`); } else s = a; const f = await s(e, [], { form: i }); return f === !0 || f === void 0 ? [] : [{ field: "unknown", message: typeof f == "string" ? f : "Validation failed", type: "vee-validate", value: e }]; } catch (s) { return [{ field: "unknown", message: s.message || "Validation failed", type: "vee-validate", value: e }]; } } }, qe = /* @__PURE__ */ new Map([ ["yup", la], ["zod", ra], ["vee-validate", na] ]); function ue(a) { const e = qe.get(a); return e && e.isAvailable() ? e : null; } function yt() { return Array.from(qe.values()).filter((a) => a.isAvailable()); } class oa { constructor() { Z(this, "abortControllers", /* @__PURE__ */ new Map()); Z(this, "validationCache", /* @__PURE__ */ new Map()); Z(this, "debounceTimers", /* @__PURE__ */ new Map()); } /** * Валидирует одно поле */ async validateField(e, i, s, f) { const r = e.name; this.cancelFieldValidation(r); const l = new AbortController(); this.abortControllers.set(r, l); const o = { fieldName: r, fieldValue: i, formData: s, formSchema: f == null ? void 0 : f.formSchema, abortSignal: l.signal, ...f }; try { const t = await this.validateWithBuiltinValidators( e, i, s, o ); if (t.length > 0) return { field: r, isValid: !1, error: t[0].message, pending: !1 }; const b = await this.validateWithExternalValidators( e, i, s, o ); return b.length > 0 ? { field: r, isValid: !1, error: b[0].message, pending: !1 } : { field: r, isValid: !0, pending: !1 }; } catch (t) { return t.name === "AbortError" ? { field: r, isValid: !1, pending: !0 } : { field: r, isValid: !1, error: t.message || "Ошибка валидации", pending: !1 }; } finally { this.abortControllers.delete(r); } } /** * Валидирует всю форму */ async validateForm(e, i) { const s = e.map( (o) => this.validateField(o, i[o.name], i) ), f = await Promise.allSettled(s), r = {}, l = []; return f.forEach((o, t) => { const b = e[t]; if (o.status === "fulfilled") { const w = o.value; !w.isValid && w.error && (r[b.name] = w.error, l.push({ field: b.name, message: w.error, type: "validation", value: i[b.name] })); } else r[b.name] = "Ошибка валидации", l.push({ field: b.name, message: "Ошибка валидации", type: "error", value: i[b.name] }); }), { isValid: Object.keys(r).length === 0, errors: r, fieldErrors: l }; } /** * Валидация с встроенными валидаторами */ async validateWithBuiltinValidators(e, i, s, f) { const r = [], l = e.validation; if (!l) return r; const o = []; l.required && o.push(P.required(l.message)), l.minLength !== void 0 && o.push(P.minLength(l.minLength, l.message)), l.maxLength !== void 0 && o.push(P.maxLength(l.maxLength, l.message)), l.min !== void 0 && o.push(P.min(l.min, l.message)), l.max !== void 0 && o.push(P.max(l.max, l.message)), l.email && o.push(P.email(l.message)), l.url && o.push(P.url(l.message)), l.pattern && o.push(P.pattern(l.pattern, l.message)), l.custom && o.push(P.custom(l.custom, l.message)); for (const t of o) try { const b = await t.validate(i, s, e.name); if (b !== !0) { r.push({ field: e.name, message: typeof b == "string" ? b : t.message || "Ошибка валидации", type: t.type, value: i }); break; } } catch (b) { r.push({ field: e.name, message: b.message || "Ошибка валидации", type: "error", value: i }); break; } return r; } /** * Валидация с внешними валидаторами */ async validateWithExternalValidators(e, i, s, f) { const r = e.externalValidation; if (!r) return []; const l = []; if (r.yup) { const o = ue("yup"); if (o) try { const t = await o.validate(r.yup, i, s); l.push(...t); } catch { } } if (r.zod) { const o = ue("zod"); if (o) try { const t = await o.validate(r.zod, i, s); l.push(...t); } catch { } } if (r.veeValidate) { const o = ue("vee-validate"); if (o) try { const t = await o.validate(r.veeValidate, i, s); l.push(...t); } catch { } } if (r.custom) try { const o = await r.custom(i, s); o !== !0 && l.push({ field: e.name, message: typeof o == "string" ? o : "Кастомная валидация не прошла", type: "custom", value: i }); } catch (o) { l.push({ field: e.name, message: o.message || "Ошибка кастомной валидации", type: "custom-error", value: i }); } return l; } /** * Отменяет валидацию поля */ cancelFieldValidation(e) { const i = this.abortControllers.get(e); i && (i.abort(), this.abortControllers.delete(e)); const s = this.debounceTimers.get(e); s && (clearTimeout(s), this.debounceTimers.delete(e)); } /** * Валидация с debounce */ validateFieldDebounced(e, i, s, f = 300) { return new Promise((r) => { const l = e.name, o = this.debounceTimers.get(l); o && clearTimeout(o); const t = setTimeout(() => { this.debounceTimers.delete(l), this.validateField(e, i, s).then(r); }, f); this.debounceTimers.set(l, t); }); } /** * Очистка ресурсов */ dispose() { for (const e of this.abortControllers.values()) e.abort(); this.abortControllers.clear(); for (const e of this.debounceTimers.values()) clearTimeout(e); this.debounceTimers.clear(), this.validationCache.clear(); } } function da(a, e) { var g, B, L, U; const { schema: i, initialData: s = {}, validateOnChange: f = ((g = i.config) == null ? void 0 : g.validateOnChange) ?? !0, validateOnBlur: r = ((B = i.config) == null ? void 0 : B.validateOnBlur) ?? !0, validateOnSubmit: l = ((L = i.config) == null ? void 0 : L.validateOnSubmit) ?? !0, resetOnSubmit: o = ((U = i.config) == null ? void 0 : U.resetOnSubmit) ?? !1, debounceValidation: t = 300 } = a, b = new oa(), w = new Ie(s), O = Q({}), h = Le({ values: {}, errors: {}, touched: {}, dirty: {}, isSubmitting: !1, isValidating: !1, isValid: !0, isDirty: !1, submitCount: 0, fields: {} }), q = /* @__PURE__ */ new Map(); function I() { const u = {}; i.fields.forEach((p) => { var z; const V = s[p.name] ?? p.defaultValue ?? M(p.type); u[p.name] = V; const j = Ge(p, { formData: O, validationEngine: b, conditionsEngine: w, validateOnChange: f, validateOnBlur: r, debounceValidation: t }); q.set(p.name, j), h.fields[p.name] = { value: V, error: null, touched: !1, dirty: !1, validating: !1, valid: !0, visible: !0, disabled: !1, required: ((z = p.validation) == null ? void 0 : z.required) ?? !1 }; }), O.value = { ...u }, h.values = { ...u }, w.updateFormData(O.value); } function M(u) { switch (u) { case "checkbox": return !1; case "number": case "range": return 0; case "multiselect": return []; case "file": return null; default: return ""; } } const G = C(() => i.fields.filter((u) => { const p = q.get(u.name); return (p == null ? void 0 : p.isVisible.value) ?? !0; })), d = C(() => Object.values(h.errors).every((u) => !u)), n = C(() => Object.values(h.dirty).some((u) => u)), k = C(() => Object.entries(h.errors).filter(([, u]) => u).map(([u, p]) => ({ field: u, message: p, type: "validation", value: O.value[u] }))); $e(O, (u) => { if (h.values = { ...u }, w.updateFormData(u), Object.keys(u).forEach((p) => { var j; const V = s[p] ?? ((j = i.fields.find((z) => z.name === p)) == null ? void 0 : j.defaultValue); h.dirty[p] = u[p] !== V; }), h.isDirty = n.value, e != null && e.change) { const p = Object.keys(u).find( (V) => u[V] !== h.values[V] ); p && e.change(p, u[p], u); } }, { deep: !0 }); async function y() { h.isValidating = !0; try { const u = await b.validateForm(i.fields, O.value); return h.errors = { ...u.errors }, h.isValid = u.isValid, Object.keys(h.fields).forEach((p) => { h.fields[p].error = u.errors[p] || null, h.fields[p].valid = !u.errors[p]; }), e != null && e.validate && e.validate(u.errors), u; } finally { h.isValidating = !1; } } async function D(u) { const p = q.get(u); if (!p) return !1; const V = await p.validateField(); return h.errors[u] = V.error || "", h.fields[u].error = V.error || null, h.fields[u].valid = V.isValid, h.fields[u].validating = V.pending || !1, V.isValid; } async function N() { if (!h.isSubmitting) { h.isSubmitting = !0, h.submitCount++; try { Object.keys(h.fields).forEach((p) => { h.touched[p] = !0, h.fields[p].touched = !0; }); let u = !0; l && (u = (await y()).isValid), e != null && e.submit && await e.submit(O.value, u), o && u && W(); } finally { h.isSubmitting = !1; } } } function W() { q.forEach((u) => { u.resetField(); }), h.errors = {}, h.touched = {}, h.dirty = {}, h.isDirty = !1, h.isValid = !0, h.submitCount = 0, Object.keys(h.fields).forEach((u) => { var j; const p = i.fields.find((z) => z.name === u), V = (p == null ? void 0 : p.defaultValue) ?? M((p == null ? void 0 : p.type) || "text"); h.fields[u] = { value: V, error: null, touched: !1, dirty: !1, validating: !1, valid: !0, visible: !0, disabled: !1, required: ((j = p == null ? void 0 : p.validation) == null ? void 0 : j.required) ?? !1 }; }), e != null && e.reset && e.reset(); } function x(u) { Object.entries(u).forEach(([p, V]) => { const j = q.get(p); j && j.setValue(V); }); } function re(u) { Object.entries(u).forEach(([p, V]) => { const j = q.get(p); j && j.setError(V), h.errors[p] = V, h.fields[p] && (h.fields[p].error = V, h.fields[p].valid = !V); }), h.isValid = d.value; } function ae() { q.forEach((u) => { u.clearError(); }), h.errors = {}, Object.keys(h.fields).forEach((u) => { h.fields[u].error = null, h.fields[u].valid = !0; }), h.isValid = !0; } function ne(u) { return q.get(u); } function te() { const u = {}; return q.forEach((p, V) => { u[V] = p; }), u; } function oe(u) { e != null && e.focus && e.focus(u, O.value[u]); } function de(u) { h.touched[u] = !0, h.fields[u] && (h.fields[u].touched = !0), e != null && e.blur && e.blur(u, O.value[u]); } function ie() { b.dispose(); } return I(), { // Данные formData: J(O), formState: J(h), schema: J(i), // Поля fields: te(), visibleFields: G, // Состояние isFormValid: d, isFormDirty: n, fieldErrors: k, // Методы валидации validateForm: y, validateField: D, // Методы управления формой submitForm: N, resetForm: W, setFormValues: x, setFormErrors: re, clearFormErrors: ae, // Получение данных getFieldData: ne, getAllFieldsData: te, // Обработчики событий handleFieldFocus: oe, handleFieldBlur: de, // Движки validationEngine: b, conditionsEngine: w, // Очистка dispose: ie }; } const ua = ["for"], fa = { key: 0, class: "field-required" }, ca = { key: 0, class: "field-description" }, ma = { class: "field-input-wrapper" }, pa = ["innerHTML"], ha = ["innerHTML"], va = { key: 0, class: "field-validating" }, ba = ["innerHTML"], ya = ["id"], Da = /* @__PURE__ */ _({ __name: "BaseField", props: { fieldData: {} }, setup(a) { const e = a, i = C(() => { const r = ["dynamic-field", `field-type-${e.fieldData.fieldSchema.type}`]; return e.fieldData.fieldSchema.wrapperClass && r.push(e.fieldData.fieldSchema.wrapperClass), e.fieldData.hasError.value && r.push("field-error"), e.fieldData.isDisabled.value && r.push("field-disabled"), e.fieldData.fieldState.value.touched && r.push("field-touched"), e.fieldData.fieldState.value.dirty && r.push("field-dirty"), r.join(" "); }), s = C(() => { const r = ["field-label"]; return e.fieldData.fieldSchema.labelClass && r.push(e.fieldData.fieldSchema.labelClass), r.join(" "); }), f = C(() => { const r = ["field-error-message"]; return e.fieldData.fieldSchema.errorClass && r.push(e.fieldData.fieldSchema.errorClass), r.join(" "); }); return (r, l) => r.fieldData.isVisible.value ? (c(), m("div", { key: 0, class: A(i.value) }, [ F(r.$slots, "label", { field: r.fieldData.fieldSchema, required: r.fieldData.isRequired.value }, () => [ r.fieldData.fieldSchema.label ? (c(), m("label", { key: 0, for: r.fieldData.inputAttrs.value.id, class: A(s.value) }, [ K(S(r.fieldData.fieldSchema.label) + " ", 1), r.fieldData.isRequired.value ? (c(), m("span", fa, "*")) : v("", !0) ], 10, ua)) : v("", !0) ], !0), F(r.$slots, "description", { field: r.fieldData.fieldSchema }, () => [ r.fieldData.fieldSchema.description ? (c(), m("div", ca, S(r.fieldData.fieldSchema.description), 1)) : v("", !0) ], !0), $("div", ma, [ F(r.$slots, "prefix", { field: r.fieldData.fieldSchema }, () => { var o; return [ (o = r.fieldData.fieldSchema.slots) != null && o.prefix ? (c(), m("div", { key: 0, class: "field-prefix", innerHTML: r.fieldData.fieldSchema.slots.prefix }, null, 8, pa)) : v("", !0) ]; }, !0), F(r.$slots, "input", { field: r.fieldData, attrs: r.fieldData.inputAttrs, classes: r.fieldData.inputClasses }, () => [ $("input", X(r.fieldData.inputAttrs, { class: [r.fieldData.inputClasses, "field-input"], onInput: l[0] || (l[0] = //@ts-ignore (...o) => r.fieldData.handleInput && r.fieldData.handleInput(...o)), onChange: l[1] || (l[1] = //@ts-ignore (...o) => r.fieldData.handleChange && r.fieldData.handleChange(...o)), onFocus: l[2] || (l[2] = //@ts-ignore (...o) => r.fieldData.handleFocus && r.fieldData.handleFocus(...o)), onBlur: l[3] || (l[3] = //@ts-ignore (...o) => r.fieldData.handleBlur && r.fieldData.handleBlur(...o)) }), null, 16) ], !0), F(r.$slots, "suffix", { field: r.fieldData.fieldSchema }, () => { var o; return [ (o = r.fieldData.fieldSchema.slots) != null && o.suffix ? (c(), m("div", { key: 0, class: "field-suffix", innerHTML: r.fieldData.fieldSchema.slots.suffix }, null, 8, ha)) : v("", !0) ]; }, !0), r.fieldData.isValidating.value ? (c(), m("div", va, [ F(r.$slots, "validating", {}, () => [ l[4] || (l[4] = $("span", { class: "validation-spinner" }, "⟳", -1)) ], !0) ])) : v("", !0) ]), F(r.$slots, "help", { field: r.fieldData.fieldSchema }, () => { var o; return [ (o = r.fieldData.fieldSchema.slots) != null && o.help ? (c(), m("div", { key: 0, class: "field-help", innerHTML: r.fieldData.fieldSchema.slots.help }, null, 8, ba)) : v("", !0) ]; }, !0), F(r.$slots, "error", { field: r.fieldData, error: r.fieldData.fieldState.value.error }, () => [ r.fieldData.hasError.value ? (c(), m("div", { key: 0, id: `field-${r.fieldData.fieldSchema.name}-error`, class: A(f.value) }, S(r.fieldData.fieldState.value.error), 11, ya)) : v("", !0) ], !0) ], 2)) : v("", !0); } }), ee = (a, e) => { const i = a.__vccOpts || a; for (const [s, f] of e) i[s] = f; return i; }, T = /* @__PURE__ */ ee(Da, [["__scopeId", "data-v-fbd766f5"]]), ga = ["for"], Ca = { key: 0, class: "field-required" }, ka = { key: 0, class: "field-description" }, Fa = { class: "field-input-wrapper" }, $a = { key: 0, value: "" }, Sa = ["value", "disabled", "title"], Va = { class: "selected-values" }, wa = ["onClick"], Ea = { key: 0, class: "placeholder" }, Oa = { class: "multiselect-dropdown" }, Aa = ["value", "checked", "disabled", "onChange"], qa = { key: 0, class: "option-description" }, Ba = { key: 0, class: "field-loading" }, ja = { key: 1, class: "field-validating" }, Ta = ["innerHTML"], Ra = ["id"], La = /* @__PURE__ */ _({ __name: "SelectField", props: { fieldData: {} }, setup(a) { const e = a, i = Q(!1), s = Q(null), f = C(() => { const d = { ...e.fieldData.inputAttrs.value }, { multiple: n, type: k, ...y } = d; return { ...y, multiple: e.fieldData.fieldSchema.type === "multiselect" }; }), r = C(() => e.fieldData.inputClasses), l = C(() => { if (e.fieldData.fieldSchema.type !== "multiselect") return []; const d = e.fieldData.fieldValue.value || []; return (e.fieldData.fieldOptions.value || []).filter( (k) => d.includes(k.value) ); }), o = C(() => { const d = ["dynamic-field", `field-type-${e.fieldData.fieldSchema.type}`]; return e.fieldData.fieldSchema.wrapperClass && d.push(e.fieldData.fieldSchema.wrapperClass), e.fieldData.hasError.value && d.push("field-error"), e.fieldData.isDisabled.value && d.push("field-disabled"), d.join(" "); }), t = C(() => { const d = ["field-label"]; return e.fieldData.fieldSchema.labelClass && d.push(e.fieldData.fieldSchema.labelClass), d.join(" "); }), b = C(() => { const d = ["field-error-message"]; return e.fieldData.fieldSchema.errorClass && d.push(e.fieldData.fieldSchema.errorClass), d.join(" "); }); function w(d) { const n = d.target; e.fieldData.fieldValue.value = n.value; } function O(d) { s.value = d; } function h() { e.fieldData.isDisabled.value || (i.value = !i.value); } function q(d) { return (e.fieldData.fieldValue.value || []).includes(d); } function I(d, n) { const k = n.target, y = e.fieldData.fieldValue.value || []; k.checked ? e.fieldData.fieldValue.value = [...y, d] : e.fieldData.fieldValue.value = y.filter((D) => D !== d); } function M(d) { const n = e.fieldData.fieldValue.value || []; e.fieldData.fieldValue.value = n.filter((k) => k !== d); } function G(d) { const n = d.target; s.value && !s.value.contains(n) && (i.value = !1); } return Se(() => { document.addEventListener("click", G); }), Ve(() => { document.removeEventListener("click", G); }), (d, n) => d.fieldData.isVisible.value ? (c(), m("div", { key: 0, class: A(o.value) }, [ F(d.$slots, "label", { field: d.fieldData.fieldSchema, required: d.fieldData.isRequired.value }, () => [ d.fieldData.fieldSchema.label ? (c(), m("label", { key: 0, for: d.fieldData.inputAttrs.value.id, class: A(t.value) }, [ K(S(d.fieldData.fieldSchema.label) + " ", 1), d.fieldData.isRequired.value ? (c(), m("span", Ca, "*")) : v("", !0) ], 10, ga)) : v("", !0) ], !0), F(d.$slots, "description", { field: d.fieldData.fieldSchema }, () => [ d.fieldData.fieldSchema.description ? (c(), m("div", ka, S(d.fieldData.fieldSchema.description), 1)) : v("", !0) ], !0), $("div", Fa, [ F(d.$slots, "input", { field: d.fieldData, attrs: f.value, classes: r.value, options: d.fieldData.fieldOptions, loading: d.fieldData.loadingOptions.value }, () => { var k, y; return [ d.fieldData.fieldSchema.type === "select" ? (c(), m("select", X({ key: 0 }, f.value, { class: [r.value, "field-select"], onChange: w, onFocus: n[0] || (n[0] = //@ts-ignore (...D) => d.fieldData.handleFocus && d.fieldData.handleFocus(...D)), onBlur: n[1] || (n[1] = //@ts-ignore (...D) => d.fieldData.handleBlur && d.fieldData.handleBlur(...D)) }), [ d.fieldData.isRequired.value ? v("", !0) : (c(), m("option", $a, S(((k = d.fieldData.fieldSchema.attributes) == null ? void 0 : k.placeholder) || "Выберите значение"), 1)), (c(!0), m(Y, null, H(d.fieldData.fieldOptions.value, (D) => (c(), m("option", { key: D.value, value: D.value, disabled: D.disabled, title: D.description }, S(D.label), 9, Sa))), 128)) ], 16)) : d.fieldData.fieldSchema.type === "multiselect" ? (c(), m("div", { key: 1, class: "multiselect-container", ref: O }, [ $("div", { class: A(["multiselect-input", [r.value, "field-multiselect"]]), onClick: h }, [ $("div", Va, [ (c(!0), m(Y, null, H(l.value, (D) => (c(), m("span", { key: D.value, class: "selected-tag" }, [ K(S(D.label) + " ", 1), $("button", { type: "button", onClick: fe((N) => M(D.value), ["stop"]), class: "tag-remove" }, " × ", 8, wa) ]))), 128)), l.value.length === 0 ? (c(), m("span", Ea, S(((y = d.fieldData.fieldSchema.attributes) == null ? void 0 : y.placeholder) || "Выберите значения"), 1)) : v("", !0) ]), n[2] || (n[2] = $("div", { class: "multiselect-arrow" }, "▼", -1)) ], 2), we($("div", Oa, [ (c(!0), m(Y, null, H(d.fieldData.fieldOptions.value, (D) => (c(), m("label", { key: D.value, class: A(["multiselect-option", { disabled: D.disabled }]) }, [ $("input", { type: "checkbox", value: D.value, checked: q(D.value), disabled: D.disabled, onChange: (N) => I(D.value, N) }, null, 40, Aa), $("span", null, S(D.label), 1), D.description ? (c(), m("div", qa, S(D.description), 1)) : v("", !0) ], 2))), 128)) ], 512), [ [Ee, i.value] ]) ])) : v("", !0) ]; }, !0), d.fieldData.loadingOptions.value ? (c(), m("div", Ba, [ F(d.$slots, "loading", {}, () => [ n[3] || (n[3] = $("span", { class: "loading-spinner" }, "⟳", -1)) ], !0) ])) : v("", !0), d.fieldData.isValidating.value ? (c(), m("div", ja, [ F(d.$slots, "validating", {}, () => [ n[4] || (n[4] = $("span", { class: "validation-spinner" }, "⟳", -1)) ], !0) ])) : v("", !0) ]), F(d.$slots, "help", { field: d.fieldData.fieldSchema }, () => { var k; return [ (k = d.fieldData.fieldSchema.slots) != null && k.help ? (c(), m("div", { key: 0, class: "field-help", innerHTML: d.fieldData.fieldSchema.slots.help }, null, 8, Ta)) : v("", !0) ]; }, !0), F(d.$slots, "error", { field: d.fieldData, error: d.fieldData.fieldState.value.error }, () => [ d.fieldData.hasError.value ? (c(), m("div", { key: 0, id: `field-${d.fieldData.fieldSchema.name}-error`, class: A(b.value) }, S(d.fieldData.fieldState.value.error), 11, Ra)) : v("", !0) ], !0) ], 2)) : v("", !0); } }), he = /* @__PURE__ */ ee(La, [["__scopeId", "data-v-043da355"]]), Ma = { class: "radio-fieldset" }, Na = { key: 0, class: "field-required" }, Ha = { key: 0, class: "field-description" }, za = { class: "radio-group" }, Pa = ["name", "value", "checked", "disabled", "required"], Ia = { class: "radio-label" }, Ga = { key: 0, class: "option-description" }, Wa = { key: 0, class: "field-loading" }, Ua = ["innerHTML"], Ya = ["id"], Ka = /* @__PURE__ */ _({ __name: "RadioField", props: { fieldData: {} }, setup(a) { const e = a, i = C(() => { const l = ["dynamic-field", "field-type-radio"]; return e.fieldData.fieldSchema.wrapperClass && l.push(e.fieldData.fieldSchema.wrapperClass), e.fieldData.hasError.value && l.push("field-error"), e.fieldData.isDisabled.value && l.push("field-disabled"), l.join(" "); }), s = C(() => { const l = ["field-label"]; return e.fieldData.fieldSchema.labelClass && l.push(e.fieldData.fieldSchema.labelClass), l.join(" "); }), f = C(() => { const l = ["field-error-message"]; return e.fieldData.fieldSchema.errorClass && l.push(e.fieldData.fieldSchema.errorClass), l.join(" "); }); function r(l) { const o = l.target; e.fieldData.fieldValue.value = o.value; } return (l, o) => l.fieldData.isVisible.value ? (c(), m("div", { key: 0, class: A(i.value) }, [ F(l.$slots, "label", { field: l.fieldData.fieldSchema, required: l.fieldData.isRequired.value }, () => [ $("fieldset", Ma, [ l.fieldData.fieldSchema.label ? (c(), m("legend", { key: 0, class: A(s.value) }, [ K(S(l.fieldData.fieldSchema.label) + " ", 1), l.fieldData.isRequired.value ? (c(), m("span", Na, "*")) : v("", !0) ], 2)) : v("", !0), F(l.$slots, "description", { field: l.fieldData.fieldSchema }, () => [ l.fieldData.fieldSchema.description ? (c(), m("div", Ha, S(l.fieldData.fieldSchema.description), 1)) : v("", !0) ], !0), $("div", za, [ F(l.$slots, "input", { field: l.fieldData, options: l.fieldData.fieldOptions, loading: l.fieldData.loadingOptions.value }, () => [ (c(!0), m(Y, null, H(l.fieldData.fieldOptions.value, (t) => (c(), m("label", { key: t.value, class: A(["radio-option", { disabled: t.disabled || l.fieldData.isDisabled.value }]) }, [ $("input", { type: "radio", name: l.fieldData.fieldSchema.name, value: t.value, checked: l.fieldData.fieldValue.value === t.value, disabled: t.disabled || l.fieldData.isDisabled.value, required: l.fieldData.isRequired.value, class: "radio-input", onChange: r, onFocus: o[0] || (o[0] = //@ts-ignore (...b) => l.fieldData.handleFocus && l.fieldData.handleFocus(...b)), onBlur: o[1] || (o[1] = //@ts-ignore (...b) => l.fieldData.handleBlur && l.fieldData.handleBlur(...b)) }, null, 40, Pa), $("span", Ia, S(t.label), 1), t.description ? (c(), m("div", Ga, S(t.description), 1)) : v("", !0) ], 2))), 128)) ], !0), l.fieldData.loadingOptions.value ? (c(), m("div", Wa, [ F(l.$slots, "loading", {}, () => [ o[2] || (o[2] = $("span", { class: "loading-spinner" }, "⟳", -1)) ], !0) ])) : v("", !0) ]) ]) ], !0), F(l.$slots, "help", { field: l.fieldData.fieldSchema }, () => { var t; return [ (t = l.fieldData.fieldSchema.slots) != null && t.help ? (c(), m("div", { key: 0, class: "field-help", innerHTML: l.fieldData.fieldSchema.slots.help }, null, 8, Ua)) : v("", !0) ]; }, !0), F(l.$slots, "error", { field: l.fieldData, error: l.fieldData.fieldState.value.error }, () => [ l.fieldData.hasError.value ? (c(), m("div", { key: 0, id: `field-${l.fieldData.fieldSchema.name}-error`, class: A(f.value) }, S(l.fieldData.fieldState.value.error), 11, Ya)) : v("", !0) ], !0) ], 2)) : v("", !0); } }), Be = /* @__PURE__ */ ee(Ka, [["__scopeId", "data-v-25e2da68"]]), Za = { class: "checkbox-container" }, Ja = { class: "checkbox-content" }, Qa = { key: 0, class: "field-required" }, Xa = { key: 0, class: "field-description" }, _a = ["innerHTML"], xa = ["id"], et = /* @__PURE__ */ _({ __name: "CheckboxField", props: { fieldData: {} }, setup(a) { const e = a, i = C(() => ({ ...{ ...e.fieldData.inputAttrs }, type: "checkbox", checked: !!e.fieldData.fieldValue.value })), s = C(() => e.fieldData.inputClasses), f = C(() => { const t = ["dynamic-field", "field-type-checkbox"]; return e.fieldData.fieldSchema.wrapperClass && t.push(e.fieldData.fieldSchema.wrapperClass), e.fieldData.hasError.value && t.push("field-error"), e.fieldData.isDisabled.value && t.push("field-disabled"), e.fieldData.fieldState.value.touched && t.push("field-touched"), e.fieldData.fieldState.value.dirty && t.push("field-dirty"), t.join(" "); }), r = C(() => { const t = ["field-label"]; return e.fieldData.fieldSchema.labelClass && t.push(e.fieldData.fieldSchema.labelClass), t.join(" "); }), l = C(() => { const t = ["field-error-message"]; return e.fieldData.fieldSchema.errorClass && t.push(e.fieldData.fieldSchema.errorClass), t.join(" "); }); function o(t) { const b = t.target; e.fieldData.fieldValue.value = b.checked; } return (t, b) => t.fieldData.isVisible.value ? (c(), m("div", { key: 0, class: A(f.value) }, [ F(t.$slots, "input", { field: t.fieldData, attrs: i.value, classes: s.value }, () => [ $("label", Za, [ $("input", X(i.value, { class: [s.value, "checkbox-input"], onChange: o, onFocus: b[0] || (b[0] = //@ts-ignore (...w) => t.fieldData.handleFocus && t.fieldData.handleFocus(...w)), onBlur: b[1] || (b[1] = //@ts-ignore (...w) => t.fieldData.handleBlur && t.fieldData.handleBlur(...w)) }), null, 16), b[2] || (b[2] = $("span", { class: "checkbox-checkmark" }, null, -1)), $("div", Ja, [ F(t.$slots, "label", { field: t.fieldData.fieldSchema, required: t.fieldData.isRequired.value }, () => [ t.fieldData.fieldSchema.label ? (c(), m("span", { key: 0, class: A(r.value) }, [ K(S(t.fieldData.fieldSchema.label) + " ", 1), t.fieldData.isRequired.value ? (c(), m("span", Qa, "*")) : v("", !0) ], 2)) : v("", !0) ], !0), F(t.$slots, "description", { field: t.fieldData.fieldSchema }, () => [ t.fieldData.fieldSchema.description ? (c(), m("div", Xa, S(t.fieldData.fieldSchema.description), 1)) : v("", !0) ], !0) ]) ]) ], !0), F(t.$slots, "help", { field: t.fieldData.fieldSchema }, () => { var w; return [ (w = t.fieldData.fieldSchema.slots) != null && w.help ? (c(), m("div", { key: 0, class: "field-help", innerHTML: t.fieldData.fieldSchema.slots.help }, null, 8, _a)) : v("", !0) ]; }, !0), F(t.$slots, "error", { field: t.fieldData, error: t.fieldData.fieldState.value.error }, () => [ t.fieldData.hasError.value ? (c(), m("div", { key: 0, id: `field-${t.fieldData.fieldSchema.name}-error`, class: A(l.value) }, S(t.fieldData.fieldState.value.error), 11, xa)) : v("", !0) ], !0) ], 2)) : v("", !0); } }), ve = /* @__PURE__ */ ee(et, [["__scopeId", "data-v-ed1081e8"]]), be = /* @__PURE__ */ _({ __name: "DynamicField", props: { fieldData: {}, customComponents: { default: () => ({}) } }, setup(a) { const e = a, i = Oe(), s = C(() => Object.keys(i).map((o) => ({ name: o, slot: i[o] }))), f = { // Текстовые поля text: T, email: T, password: T, url: T, tel: T, number: T, textarea: T, hidden: T, date: T, "datetime-local": T, time: T, file: T, range: T, color: T, // Выбор из списка select: he, multiselect: he, // Радио кнопки radio: Be, // Чекбоксы и переключатели checkbox: ve, switch: ve }, r = C(() => { const o = e.fieldData.fieldSchema; if (o.component) { if (e.customComponents[o.component]) return e.customComponents[o.component]; console.warn(`Custom component "${o.component}" not found for field "${o.name}"`); } const t = f[o.type]; return t || (console.warn(`No component found for field type "${o.type}", using BaseField`), T); }), l = C(() => ({ ...e.fieldData.fieldSchema.props || {} })); return (o, t) => (c(), ce(Me(r.value), X({ fieldData: o.fieldData }, l.value), me({ _: 2 }, [ H(s.value, (b, w) => ({ name: b.name, fn: pe((O) => [ F(o.$slots, b.name, Ne(He(O))) ]) })) ]), 1040, ["fieldData"])); } }), at = { key: 0, class: "form-header" }, tt = { key: 0, class: "form-title" }, it = { key: 1, class: "form-description" }, st = { key: 0, class: "form-errors" }, lt = { class: "form-errors-list" }, rt = { class: "form-body" }, nt = { class: "form-fieldset" }, ot = ["onClick"], dt = { key: 1, class: "form-group-description" }, ut = { class: "form-actions" }, ft = ["disabled"], ct = { key: 0, class: "submit-spinner" }, mt = ["disabled"], pt = /* @__PURE__ */ _({ __name: "DynamicForm", props: { schema: {}, initialData: { default: () => ({}) }, customComponents: { default: () => ({}) }, validateOnChange: { type: Boolean }, validateOnBlur: { type: Boolean }, validateOnSubmit: { type: Boolean }, reset