@volverjs/form-vue
Version:
Vue 3 Forms with @volverjs/ui-vue
629 lines (628 loc) • 18.6 kB
JavaScript
import { defineComponent as W, computed as g, onMounted as D, onBeforeUnmount as j, inject as I, toRefs as R, watch as E, unref as _, provide as M, readonly as p, resolveComponent as O, defineAsyncComponent as F, h as x, ref as $, toRaw as S, isProxy as ee, withModifiers as re, getCurrentInstance as te } from "vue";
import { watchThrottled as ae } from "@vueuse/core";
import { ZodObject as K, ZodDefault as ue, ZodNullable as ne, ZodSchema as le, ZodArray as se, ZodEffects as ie, ZodOptional as fe } from "zod";
function U(e) {
return Array.isArray(e);
}
function oe(e) {
return typeof e < "u";
}
function P(e) {
return e === null;
}
function H(e) {
return typeof e == "object";
}
function Q(e) {
return typeof e == "string";
}
function N(e) {
return typeof e > "u";
}
const de = /^[0-9]+$/, ve = ["__proto__", "prototype", "constructor"];
function G(e, l, t) {
const f = oe(t) ? t : void 0;
if (!H(e) || !Q(l))
return f;
const n = X(l);
if (n.length !== 0) {
for (const r of n) {
if (r === "*")
continue;
const u = function(i) {
return i.map((s) => N(s) || P(s) ? s : U(s) ? u(s) : s[r]);
};
if (U(e) && !de.test(r) ? e = u(e) : e = e[r], N(e) || P(e))
break;
}
return N(e) ? f : e;
}
}
function T(e, l, t) {
if (!H(e) || !Q(l))
return;
const f = X(l);
if (f.length === 0)
return;
const n = f.length;
for (let r = 0; r < n; r++) {
const u = f[r];
if (r === n - 1) {
e[u] = t;
return;
}
if (u === "*" && U(e)) {
const i = f.slice(r + 1).join(".");
for (const s of e)
T(s, i, t);
return;
}
N(e[u]) && (e[u] = {}), e = e[u];
}
}
function X(e) {
const l = e.split(/[.]|(?:\[(\d|\*)\])/).filter((t) => !!t);
return l.some((t) => ve.indexOf(t) !== -1) ? [] : l;
}
var v = /* @__PURE__ */ ((e) => (e.text = "text", e.number = "number", e.email = "email", e.password = "password", e.tel = "tel", e.url = "url", e.search = "search", e.date = "date", e.time = "time", e.datetimeLocal = "datetime-local", e.month = "month", e.week = "week", e.color = "color", e.select = "select", e.checkbox = "checkbox", e.radio = "radio", e.textarea = "textarea", e.radioGroup = "radioGroup", e.checkboxGroup = "checkboxGroup", e.combobox = "combobox", e.custom = "custom", e))(v || {}), B = /* @__PURE__ */ ((e) => (e.invalid = "invalid", e.valid = "valid", e))(B || {});
const ce = (e, l, t, f) => W({
name: "FieldComponent",
props: {
type: {
type: String,
validator: (n) => Object.values(v).includes(n),
default: v.custom
},
is: {
type: [Object, String],
default: void 0
},
name: {
type: [String, Number, Boolean, Symbol],
required: !0
},
props: {
type: [Object, Function],
default: () => ({})
},
showValid: {
type: Boolean,
default: !1
},
defaultValue: {
type: [String, Number, Boolean, Array, Object],
default: void 0
},
lazyLoad: {
type: Boolean,
default: !1
}
},
emits: ["invalid", "valid", "update:formData", "update:modelValue"],
expose: ["invalid", "invalidLabel", "errors"],
setup(n, { slots: r, emit: u }) {
const i = g({
get() {
if (a != null && a.formData)
return G(
Object(a.formData.value),
String(n.name)
);
},
set(d) {
a != null && a.formData && (T(
Object(a.formData.value),
String(n.name),
d
), u("update:modelValue", {
newValue: i.value,
formData: a == null ? void 0 : a.formData
}));
}
});
D(() => {
i.value === void 0 && n.defaultValue !== void 0 && (i.value = n.defaultValue);
}), j(() => {
w(), k();
});
const s = I(l, void 0);
s && s.fields.value.add(n.name);
const a = I(e), { props: o, name: h } = R(n), b = g(() => {
if (a != null && a.errors.value)
return G(a.errors.value, String(n.name));
}), c = g(() => {
var d;
return (d = b.value) == null ? void 0 : d._errors;
}), m = g(() => b.value !== void 0), w = E(m, () => {
m.value ? (u("invalid", c.value), s && s.errors.value.set(
n.name,
{
_errors: c.value
}
)) : (u("valid", i.value), s && s.errors.value.delete(
n.name
));
}), k = E(
() => a == null ? void 0 : a.formData,
() => {
u("update:formData", a == null ? void 0 : a.formData);
},
{ deep: !0 }
), y = (d) => {
i.value = d;
}, V = g(() => {
let d = o.value;
return typeof d == "function" && (d = d(a == null ? void 0 : a.formData)), Object.keys(d).reduce(
(A, C) => (A[C] = _(d[C]), A),
{}
);
}), z = g(() => ({
...V.value,
name: V.value.name ?? n.name,
invalid: m.value,
valid: n.showValid ? !!(!m.value && i.value) : void 0,
type: ((d) => {
if ([
v.text,
v.number,
v.email,
v.password,
v.tel,
v.url,
v.search,
v.date,
v.time,
v.datetimeLocal,
v.month,
v.week,
v.color
].includes(d))
return d;
})(n.type),
invalidLabel: c.value,
modelValue: i.value,
"onUpdate:modelValue": y
}));
return M(t, {
name: p(h),
errors: p(b)
}), { component: g(() => {
if (n.type === v.custom)
return {
render() {
var d;
return ((d = r.default) == null ? void 0 : d.call(r, {
modelValue: i.value,
onUpdate: y,
submit: a == null ? void 0 : a.submit,
validate: a == null ? void 0 : a.validate,
invalid: m.value,
invalidLabel: c.value,
formData: a == null ? void 0 : a.formData.value,
formErrors: a == null ? void 0 : a.errors.value,
errors: b.value
})) ?? r.defalut;
}
};
if (!((f == null ? void 0 : f.lazyLoad) ?? n.lazyLoad)) {
let d;
switch (n.type) {
case v.select:
d = O("VvSelect");
break;
case v.checkbox:
d = O("VvCheckbox");
break;
case v.radio:
d = O("VvRadio");
break;
case v.textarea:
d = O("VvTextarea");
break;
case v.radioGroup:
d = O("VvRadioGroup");
break;
case v.checkboxGroup:
d = O("VvCheckboxGroup");
break;
case v.combobox:
d = O("VvCombobox");
break;
default:
d = O("VvInputText");
}
if (typeof d != "string")
return d;
console.warn(
`[form-vue warn]: ${d} not found, the component will be loaded asynchronously. To avoid this warning, please set "lazyLoad" option.`
);
}
return F(async () => {
switch (f != null && f.sideEffects && await Promise.resolve(f.sideEffects(n.type)), n.type) {
case v.textarea:
return import("@volverjs/ui-vue/vv-textarea");
case v.radio:
return import("@volverjs/ui-vue/vv-radio");
case v.radioGroup:
return import("@volverjs/ui-vue/vv-radio-group");
case v.checkbox:
return import("@volverjs/ui-vue/vv-checkbox");
case v.checkboxGroup:
return import("@volverjs/ui-vue/vv-checkbox-group");
case v.select:
return import("@volverjs/ui-vue/vv-select");
case v.combobox:
return import("@volverjs/ui-vue/vv-combobox");
}
return import("@volverjs/ui-vue/vv-input-text");
});
}), hasProps: z, invalid: m };
},
render() {
return this.is ? x(this.is, this.hasProps, this.$slots) : this.type === v.custom ? x(this.component, null, this.$slots) : x(this.component, this.hasProps, this.$slots);
}
}), J = (e, l = {}) => {
const t = (r) => {
let u = r;
for (; u instanceof ie; )
u = u.innerType();
return u instanceof fe && (u = u._def.innerType), u;
}, f = t(e);
return {
...(f instanceof K ? f._def.unknownKeys === "passthrough" : !1) ? l : {},
...Object.fromEntries(
Object.entries(f.shape).map(
([r, u]) => {
const i = l[r];
let s = t(u), a;
if (s instanceof ue && (a = s._def.defaultValue(), s = s._def.innerType), i === null && s instanceof ne)
return [r, i];
if (s instanceof le) {
const o = u.safeParse(i);
if (o.success)
return [r, o.data ?? a];
}
if (s instanceof se && Array.isArray(i) && i.length) {
const o = t(s._def.type);
if (o instanceof K)
return [
r,
i.map(
(h) => J(
o,
h && typeof h == "object" ? h : void 0
)
) ?? a
];
}
return s instanceof K ? [
r,
J(
s,
i && typeof i == "object" ? i : a
)
] : [r, a];
}
)
)
};
}, me = (e, l, t, f) => {
const n = $(), r = $(), u = $(), i = W({
name: "FormComponent",
props: {
modelValue: {
type: Object,
default: () => ({})
},
updateThrottle: {
type: Number,
default: 500
},
continuosValidation: {
type: Boolean,
default: !1
},
template: {
type: [Array, Function],
default: void 0
}
},
emits: ["invalid", "valid", "submit", "update:modelValue"],
expose: ["submit", "validate", "errors", "status", "valid", "invalid"],
setup(s, { emit: a }) {
u.value = J(
e,
S(s.modelValue)
), E(
() => s.modelValue,
(c) => {
if (c) {
const m = ee(c) ? S(c) : c;
u.value = typeof (m == null ? void 0 : m.clone) == "function" ? m.clone() : JSON.parse(JSON.stringify(m));
}
},
{ deep: !0 }
), ae(
u,
(c) => {
var m;
((n.value || (t == null ? void 0 : t.continuosValidation)) ?? s.continuosValidation) && o(), (!c || !s.modelValue || JSON.stringify(c) !== JSON.stringify(s.modelValue)) && (a("update:modelValue", c), (m = t == null ? void 0 : t.onUpdate) == null || m.call(t, S(c)));
},
{
deep: !0,
throttle: (t == null ? void 0 : t.updateThrottle) ?? s.updateThrottle
}
);
const o = (c = u.value) => {
var w, k, y;
const m = e.safeParse(c);
return m.success ? (n.value = void 0, r.value = B.valid, u.value = m.data, a("update:modelValue", u.value), (k = t == null ? void 0 : t.onUpdate) == null || k.call(t, S(u.value)), a("valid", m.data), (y = t == null ? void 0 : t.onValid) == null || y.call(t, S(u.value)), !0) : (n.value = m.error.format(), r.value = B.invalid, a("invalid", n.value), (w = t == null ? void 0 : t.onInvalid) == null || w.call(t, S(n.value)), !1);
}, h = () => {
var c;
return o() ? (a("submit", u.value), (c = t == null ? void 0 : t.onSubmit) == null || c.call(t, S(u.value)), !0) : !1;
}, b = g(() => r.value === B.invalid);
return M(l, {
formData: u,
submit: h,
validate: o,
errors: p(n),
status: p(r),
invalid: b
}), {
formData: u,
submit: h,
validate: o,
errors: p(n),
status: p(r),
invalid: b
};
},
render() {
const s = () => {
var a, o;
return ((o = (a = this.$slots) == null ? void 0 : a.default) == null ? void 0 : o.call(a, {
formData: this.formData,
submit: this.submit,
validate: this.validate,
errors: this.errors,
status: this.status,
invalid: this.invalid
})) ?? this.$slots.default;
};
return x(
"form",
{
onSubmit: re(this.submit, ["prevent"])
},
(this.template ?? (t == null ? void 0 : t.template)) && f ? [
x(
f,
{
schema: this.template ?? (t == null ? void 0 : t.template)
},
{
default: s
}
)
] : {
default: s
}
);
}
});
return {
errors: n,
status: r,
formData: u,
/**
* An hack to add types to the default slot
*/
VvForm: i
};
}, he = (e, l) => W({
name: "WrapperComponent",
props: {
name: {
type: String,
required: !0
},
tag: {
type: String,
default: void 0
}
},
emits: ["invalid", "valid"],
expose: ["fields", "invalid"],
setup(f, { emit: n }) {
const r = I(e), u = I(l, void 0), i = $(/* @__PURE__ */ new Set()), s = $(/* @__PURE__ */ new Map()), { name: a } = R(f);
M(l, {
name: p(a),
errors: s,
fields: i
}), E(
i,
(h) => {
u != null && u.fields && h.forEach((b) => {
u == null || u.fields.value.add(b);
});
},
{ deep: !0 }
), E(
() => new Map(s.value),
(h, b) => {
u != null && u.errors && (Array.from(b.keys()).forEach((c) => {
u.errors.value.delete(c);
}), Array.from(h.keys()).forEach((c) => {
const m = h.get(c);
m && u.errors.value.set(c, m);
}));
},
{ deep: !0 }
);
const o = g(() => r != null && r.invalid.value ? s.value.size > 0 : !1);
return E(o, () => {
o.value ? n("invalid") : n("valid");
}), {
formData: r == null ? void 0 : r.formData,
errors: r == null ? void 0 : r.errors,
submit: r == null ? void 0 : r.submit,
validate: r == null ? void 0 : r.validate,
invalid: o,
fields: i,
fieldsErrors: s
};
},
render() {
var f, n;
return this.tag ? x(this.tag, null, {
default: () => {
var r, u;
return ((u = (r = this.$slots).default) == null ? void 0 : u.call(r, {
invalid: this.invalid,
formData: this.formData,
submit: this.submit,
validate: this.validate,
errors: this.errors,
fieldsErrors: this.fieldsErrors
})) ?? this.$slots.defalut;
}
}) : ((n = (f = this.$slots).default) == null ? void 0 : n.call(f, {
invalid: this.invalid,
formData: this.formData,
submit: this.submit,
validate: this.validate,
errors: this.errors,
fieldsErrors: this.fieldsErrors
})) ?? this.$slots.defalut;
}
}), be = (e, l) => {
const t = W({
props: {
schema: {
type: [Array, Function],
required: !0
}
},
setup(f, { slots: n }) {
const r = I(e);
if (r != null && r.formData)
return () => {
var a;
const u = typeof f.schema == "function" ? f.schema(r) : f.schema;
let i;
const s = u.reduce((o, h) => {
const b = typeof h == "function" ? h(r) : h, {
vvIs: c,
vvName: m,
vvSlots: w,
vvChildren: k,
vvIf: y,
vvElseIf: V,
vvType: z,
vvDefaultValue: q,
vvShowValid: d,
vvContent: A,
...C
} = b;
if (y !== void 0) {
if (typeof y == "string" ? i = !!G(
Object(r.formData.value),
y
) : typeof y == "function" ? i = _(y(r)) : i = _(y), !i)
return o;
} else if (V !== void 0 && i !== void 0) {
if (i || (typeof V == "string" ? i = !!G(
Object(r.formData.value),
V
) : typeof V == "function" ? i = _(V(r)) : i = _(V), !i))
return o;
} else
i = void 0;
const Z = k ? x(t, {
schema: k
}) : void 0;
return m ? (o.push(
x(
l,
{
name: m,
is: c,
type: z,
defaultValue: q,
showValid: d,
props: C
},
w ?? Z ?? A
)
), o) : c ? (o.push(
x(
c,
C,
w ?? Z ?? A
)
), o) : (k && o.push(Z), o);
}, []);
return s.push(
(a = n == null ? void 0 : n.default) == null ? void 0 : a.call(n, {
formData: r == null ? void 0 : r.formData.value,
submit: r == null ? void 0 : r.submit,
validate: r == null ? void 0 : r.validate,
errors: r == null ? void 0 : r.errors.value,
status: r == null ? void 0 : r.status.value,
invalid: r == null ? void 0 : r.invalid.value
})
), s;
};
}
});
return t;
}, L = (e, l = {}) => {
const t = Symbol(), f = Symbol(), n = Symbol(), r = he(
t,
f
), u = ce(
t,
f,
n,
l
), i = be(t, u), { VvForm: s, errors: a, status: o, formData: h } = me(
e,
t,
l,
i
);
return {
VvForm: s,
VvFormWrapper: r,
VvFormField: u,
VvFormTemplate: i,
formInjectionKey: t,
formWrapperInjectionKey: f,
formFieldInjectionKey: n,
errors: a,
status: o,
formData: h
};
}, Y = Symbol(), xe = (e) => {
let l = {};
return e.schema && (l = L(e.schema, e)), {
...l,
install(t, { global: f = !1 } = {}) {
t.provide(Y, e), f && (t.config.globalProperties.$vvForm = e, l != null && l.VvForm && t.component("VvForm", l.VvForm), l != null && l.VvFormWrapper && t.component("VvFormWrapper", l.VvFormWrapper), l != null && l.VvFormField && t.component("VvFormField", l.VvFormField), l != null && l.VvFormTemplate && t.component("VvFormTemplate", l.VvFormTemplate));
}
};
}, ke = (e, l = {}) => te() ? L(
e,
{
...I(Y, {}),
...l
}
) : L(e, l), Oe = (e, l = {}) => L(e, l);
export {
v as FormFieldType,
xe as createForm,
J as defaultObjectBySchema,
Oe as formFactory,
Y as pluginInjectionKey,
ke as useForm
};