vue-formify
Version:
Build powerful, type-safe forms in Vue.
670 lines (669 loc) • 19.2 kB
JavaScript
import { computed as e, defineComponent as t, getCurrentInstance as n, h as r, inject as i, nextTick as a, onBeforeUnmount as o, onMounted as s, onUnmounted as c, provide as l, reactive as u, ref as d, resolveDynamicComponent as f, toValue as p, warn as m, watch as h } from "vue";
//#region src/utils/store.ts
var g = u({}), _ = (e) => typeof e == "object" && !!e, v = /^\[(.+?)\]$/gm, y = /(^.*\[|\].*$)/g, b = /\[(\d*)\]/gm, x = /\[(\d+)\]/, S = /\[\d+\]/, C = (e, t, n) => {
if (e && !(e in g[t].values)) {
let r = E(e, n);
g[t].values = B(g[t].values, r);
}
}, w = (e, t) => {
let n = e.as || "";
return !e.as && !t && (n = "input"), n;
}, T = (e, t, n) => t.default ? typeof e == "string" || !e ? t.default(n()) : { default: () => t.default?.(n()) } : t.default, E = (e, t) => {
let n = e.match(v);
return n ? { [n[0].replace(y, "")]: t } : e.split(".").reduceRight((e, t) => {
let n = t.match(b), r = t.replace(S, ""), i = t.match(x)?.[1];
return n ? { [r]: { value: { [`[${i}]`]: e } } } : { [t]: e };
}, t);
}, D = (e, t = "") => {
let n = {};
for (let r in e) {
let i = t ? `${t}.${r}` : r;
if (_(e[r]) && !Array.isArray(e[r])) {
let t = D(e[r], i);
n = {
...n,
...t
};
} else n[i] = e[r];
}
return n;
}, O = (e, t) => {
if (!t) return;
let n = t.match(v);
if (n) return e[n[0].replace(y, "")];
let r = e, i = t.split("."), a = i.pop();
for (let e of i) {
if (e.match(b)) {
let t = e.replace(S, ""), n = e.match(x)?.[1];
r = r?.[t]?.value?.[`[${n}]`];
} else r = r[e];
if (!r) return;
}
if (a && a.match(b)) {
let e = a.replace(S, ""), t = a.match(x)?.[1];
return a && r?.[e]?.value?.[`[${t}]`];
}
return a && r[a];
}, k = (e, t) => {
let n = t.match(v);
if (n) {
let t = n[0].replace(y, "");
delete e[t];
}
let r = e, i = t.split("."), a = i.pop();
for (let e of i) {
if (e.match(b)) {
let t = e.replace(S, ""), n = e.match(x)?.[1];
r = r?.[t]?.value?.[`[${n}]`];
} else r = r[e];
if (!r) return;
}
if (a) {
if (a.match(b)) {
let e = a.replace(S, ""), t = a.match(x)?.[1];
delete r?.[e]?.value?.[`[${t}]`], r?.[e]?.value && !Object.keys(r?.[e]?.value).length && (r[e].value = []);
} else delete r[a];
Object.keys(r).length === 0 && k(e, i.join("."));
}
}, A = (e) => {
if (!_(e)) return e;
try {
return JSON.parse(JSON.stringify(e));
} catch {
return e;
}
}, j = (e, t) => {
if (e === t) return !0;
if (typeof e != typeof t) return !1;
if (!_(e) || t === null) return e !== e && t !== t;
if (e instanceof Date || t instanceof Date) return e instanceof Date && t instanceof Date && e.getTime() === t.getTime();
if (typeof File < "u" && (e instanceof File || t instanceof File) || typeof Blob < "u" && (e instanceof Blob || t instanceof Blob)) return e === t;
let n = Array.isArray(e);
if (n !== Array.isArray(t)) return !1;
if (n) return e.length === t.length ? e.every((e, n) => j(e, t[n])) : !1;
let r = Object.keys(e).filter((t) => e[t] !== void 0), i = Object.keys(t).filter((e) => t[e] !== void 0);
return r.length === i.length ? r.every((n) => j(e[n], t[n])) : !1;
}, M = (e) => !!e && _(e) && "value" in e && !j(e.value, e.initialValue), N = (e) => {
if (!e || typeof e != "object") return !1;
for (let t in e) {
let n = e[t];
if (_(n)) {
if ("value" in n) {
if (n.ignore) continue;
if (M(n)) return !0;
} else if (N(n)) return !0;
}
}
return !1;
}, P = (e) => {
if (_(e)) for (let t in e) {
let n = e[t];
_(n) && ("value" in n ? (n.error = void 0, _(n.value) && P(n.value)) : P(n));
}
}, F = (e) => {
if (!_(e)) return !1;
for (let t in e) {
let n = e[t];
if (_(n)) {
if ("value" in n) {
if (n.ignore) continue;
if (n.isTouched || n.value && typeof n.value == "object" && F(n.value)) return !0;
} else if (F(n)) return !0;
}
}
return !1;
};
function I(e) {
return typeof e == "string" && e ? !0 : Array.isArray(e) ? e.some((e) => I(e)) : _(e) ? Object.values(e).some((e) => I(e)) : !1;
}
var L = (e, t) => O(e, t)?.error, R = (e, t = "value") => {
let n = {};
for (let r in e) if (_(e[r]) && "value" in e[r]) {
let { value: i, ignore: a } = e[r];
if (_(i)) if (Array.isArray(i) && (n[r] = []), Object.keys(i)[0]?.match?.(v)) for (let e in i) !n[r] && !a && (n[r] = []), t in i[e] ? i[e][t] && n[r].push(i[e][t]) : !a && n[r].push(R(i[e], t));
else !a && (n[r] = e[r][t]);
else !a && (n[r] = e[r][t]);
} else _(e[r]) && (n[r] = R(e[r], t));
return n;
}, z = (e) => {
let t = [];
if (!Array.isArray(e.value) && _(e.value) && !(e.value instanceof Date)) {
if ((Object.keys(e.value)?.[0])?.match?.(v)) {
for (let n in e.value) t.push(e.value[n].value);
return t;
}
return e.value;
}
return e.value || typeof e.value == "boolean" ? e.value : "";
}, B = (...e) => e.reduce((e, t) => (Object.keys(t).forEach((n) => {
let r = e[n], i = t[n];
Array.isArray(r) && Array.isArray(i) ? e[n] = r.concat(...i) : _(r) && _(i) ? e[n] = B(r, i) : e[n] = i;
}), e), {}), V = (e, t = "") => {
let n = new FormData();
return Object.keys(e).reduce((r, i) => {
let a = t ? `${t}.${i}` : i;
if (_(e[i]) && !Array.isArray(e[i]) && !(e[i] instanceof Date) && !(e[i] instanceof File) && !(e[i] instanceof Blob)) {
let t = V(e[i], a);
r += t;
} else Array.isArray(e[i]) ? e[i].forEach((e) => {
n.append(`${a}[]`, e);
}) : n.append(`${a}`, e[i]);
return r;
}, ""), n;
}, H = (e) => {
if (e.path?.length) {
let t = "";
for (let n of e.path) {
let e = typeof n == "object" ? n.key : n;
if (typeof e == "string") t ? t += `.${e}` : t += e;
else if (typeof e == "number") t += `[${e}]`;
else return null;
}
return t;
}
return null;
}, U = async (e) => {
try {
return await e;
} catch {
return;
}
}, W = class {
eventListeners = {};
on(e, t) {
this.eventListeners[e] || (this.eventListeners[e] = []), this.eventListeners[e].push(t);
}
off(e, t) {
let n = this.eventListeners[e];
n && (this.eventListeners[e] = n.filter((e) => e !== t));
}
emit(e, t) {
let n = this.eventListeners[e];
n && n.forEach((e) => e(t));
}
}, G = async (e, t, n, r) => {
let i = await e["~standard"].validate(t);
if (i.issues) {
for (let e of i.issues) n(r || H(e), e.message);
return !1;
}
return !0;
}, K = (e, t, n, r, i, a, o) => {
let s = (t, n) => {
let r = O(g[e].values, t);
r && (r.error = n);
};
return {
setError: s,
resetError: () => {
r.value?.error && (r.value.error = void 0);
let n = t.replace(/\[\d+\]/, ""), i = O(g[e].values, n);
i?.error && (i.error = void 0);
},
validateField: async () => {
if (n) return await G(n, i.value, s, t);
},
getError: () => M(r.value) || a.value || o === "onSubmit" ? r.value?.error : void 0
};
}, q = (e, t, n) => e ? t || !0 : n || !1, J = (e, t, n) => e.value === "on" ? q(e.checked, t, n) : e.checked ? e.value : void 0, Y = (e, t, n) => e.type === "checkbox" ? J(e, t, n) : e.type === "file" ? e.multiple ? e.files : e.files?.[0] : e.type === "select-multiple" ? Array.from(e.options).filter((e) => e.selected).map((e) => e.value) : e.value, X = (t, r = {
isArray: !1,
isComponent: !1
}) => {
let { uid: c, preserveForm: l, mode: u, isSubmitted: d } = i("formData", Object.create({})), f = n(), p = t.name, h = {
value: O(g[c].values, p)?.value ?? void 0,
initialValue: void 0,
error: void 0,
ignore: t.ignore,
isTouched: !1
}, _ = e(() => O(g[c].values, p)), v = e(() => M(_.value)), y = e(() => _.value?.isTouched), b = e(() => !_.value?.error), x = (e, t = p) => {
let n = O(g[c].values, t);
n && (n.value = B(n.value, e), n.error = void 0);
}, S = e({
get() {
if (_.value) return _.value.value;
},
set(e) {
if (_.value) {
if (r.isArray || Array.isArray(e)) {
_.value.value = [];
for (let t = 0; t < e.length; t++) x({ [`[${t}]`]: { value: e[t] } }, p);
return _.value.value;
}
_.value.value = e ?? "";
}
}
}), w = e(() => z(S)), { setError: T, resetError: E, validateField: D, getError: j } = K(c, p, t?.rule, _, S, d, u), N = (e) => S.value = e, P = async (e) => {
r.isComponent || (typeof e == "object" && e && "target" in e ? e.currentTarget != null && e.target !== e.currentTarget || N(Y(e.target, t.trueValue, t.falseValue)) : typeof e != "object" || !e ? N(e) : "value" in e && N(e.value)), _.value && (_.value && !_.value?.isTouched && (_.value.isTouched = !0), E(), u === "onChange" && D());
}, F = () => {
E();
}, I = async () => {
_.value && !_.value?.isTouched && (_.value.isTouched = !0), await D();
}, L = () => {
if (r.isArray || Array.isArray(O(g[c].initialValues, p))) {
if (O(g[c].initialValues, p)) {
let e = O(g[c].initialValues, p), t = {};
for (let n = 0; n < e.length; n++) t = {
...t,
[`[${n}]`]: {
value: e[n],
error: void 0
}
};
return t;
}
return [];
}
return O(g[c].values, p).value ?? t.modelValue ?? t.default ?? O(g[c].initialValues, p) ?? (r.isCheckbox ? t.falseValue ?? !1 : "");
};
if (C(p, c, JSON.parse(JSON.stringify(h))), !p) m("`name` prop is required");
else {
let e = L();
_.value.value = e, _.value.initialValue = A(e);
}
return o(() => {
t.preserve || l || k(g[c].values, p);
}), s(async () => {
await a(), f?.subTree?.el && "as" in t && t.as === "select" && Array.from(f.subTree.el.options).forEach((e) => {
h.value?.includes?.(e.value) && (e.selected = !0);
});
}), {
value: S,
isValid: b,
isTouched: y,
isDirty: v,
inputProps: e(() => ({
modelValue: w.value,
value: w.value,
"onUpdate:modelValue": (e) => {
S.value = e, u === "onChange" && D();
},
isTouched: y.value,
onInput: P,
onFocus: F,
onBlur: I
})),
getError: j,
setError: T,
setArrayValue: x,
setValue: N
};
}, Z = () => t((e, { slots: t, emit: n, attrs: o }) => {
let s = d([]), { getError: c, setArrayValue: l } = X(e, { isArray: !0 }), { uid: u } = i("formData", Object.create({})), f = () => {
!e.ignore && (O(g[u].values, e.name).error = void 0), s.value.push({
id: s.value.length,
name: e.name
});
}, m = async (t) => {
O(g[u].values, e.name).error = void 0;
let n = s.value.findIndex((e) => e.id === t);
for (let t = n + 1; t < s.value.length; t++) {
let n = `${e.name}[${t}]`, r = `${e.name}[${t - 1}]`;
O(g[u].values, n).error = void 0, O(g[u].values, r).error = void 0, O(g[u].values, r) && l({ [`[${t - 1}]`]: JSON.parse(JSON.stringify(O(g[u].values, n))) });
}
await a(), k(g[u].values, `${s.value[s.value.length - 1].name}[${s.value.length - 1}]`), s.value.splice(-1);
};
return (async () => {
s.value = [];
let t = g[u].initialValues?.[e.name] || g[u].values[e.name].value;
t && (t.forEach?.(() => {
s.value.push({
id: s.value.length,
name: e.name
});
}), await a(), t.forEach?.((e, t) => {
typeof e == "object" ? Object.keys(e).forEach((n) => {
l({ [`[${t}]`]: { [n]: { value: e[n] } } });
}) : l({ [`[${t}]`]: { value: e } });
}));
})(), () => r("div", {
...e,
...o,
...n
}, t.default?.({
fields: p(s),
add: f,
remove: m,
error: c
}));
}, {
name: "FieldArray",
props: {
name: {
type: String,
default: ""
},
default: {
type: [
String,
Array,
Boolean,
Number,
Object
],
default: void 0
},
preserve: {
type: Boolean,
default: !1
},
modelValue: {
type: [
String,
Array,
Boolean,
Number,
Object
],
default: void 0
},
as: {
type: String,
default: "input"
},
rule: {
type: Object,
default: void 0
}
},
emits: ["update:modelValue"],
slots: Object
}), Q = () => t((e, { slots: t, emit: n, attrs: a }) => {
let { uid: o, mode: s, isSubmitted: c } = i("formData", Object.create({})), l = () => {
if (s === "onSubmit" || c.value || M(O(g[o].values, e.errorFor))) return L(g[o].values, e.errorFor);
};
return () => r("span", {
...e,
...a,
...n
}, t.default ? t.default?.({ error: l() }) : Array.isArray(l()) ? l()?.[0] : l());
}, {
name: "FieldError",
props: { errorFor: {
type: String,
default: void 0
} },
slots: Object
}), $ = 0, ee = (i) => {
let u = i?.name || `form-${++$}`, f = d(!1), p = d(!1), m = d(!1), _ = d(0), v = new W(), y = Object.create({}), b = (e = !1) => {
m.value = !1, _.value = 0, e ? (g[u].initialValues = Object.create({}), g[u].values = Object.create({}), y = JSON.stringify(Object.create({}))) : g[u].values = JSON.parse(y), g[u].key++;
}, x = (e) => async () => {
await e?.(z.value);
}, S = (e, t) => {
if (O(g[u].values, e)) {
let n = O(g[u].values, e);
n.value = t, n.error = void 0;
} else {
let n = E(e, {
value: t,
error: void 0
});
g[u].values = B(g[u].values, n);
}
i?.schema && G(i.schema, R(g[u].values), T);
}, C = (e) => {
let t = D(e);
for (let e in t) if (O(g[u].values, e) && "value" in O(g[u].values, e)) {
let n = O(g[u].values, e);
n.value = t[e], n.error = void 0;
}
i?.schema && G(i.schema, R(g[u].values), T);
}, w = (e) => {
g[u].initialValues = e, g[u].key++;
}, T = (e, t) => {
O(g[u].values, e) && (O(g[u].values, e).error = t);
}, k = (e) => {
let t = O(g[u].values, e);
return {
value: t?.value,
error: t?.error,
isDirty: M(t),
isTouched: !!t?.isTouched,
isValid: !t?.error
};
}, A = async () => (m.value = !0, i?.schema ? await G(i.schema, R(g[u].values), T) : !0), j = (e) => {
if (e) {
let t = O(g[u].values, e);
t && (t.error = void 0);
return;
}
P(g[u].values);
}, z = e(() => R(g[u]?.values)), H = e(() => N(g[u]?.values)), K = e(() => F(g[u]?.values)), q = e(() => !I(R(g[u]?.values, "error")));
return g[u] || (g[u] = {
values: Object.create({}),
initialValues: i?.initialValues || Object.create({}),
key: 0
}), n() && !i?.preserve && c(() => {
delete g[u];
}), {
cmp: t((e, { slots: t, emit: n, attrs: c }) => {
l("formData", {
uid: u,
preserveForm: i?.preserve,
mode: i?.mode,
isSubmitted: m,
emitter: v
});
let d = (e) => L(g[u].values, e), b = async (t) => {
t.preventDefault(), m.value = !0, _.value++;
let n = z.value;
if (i?.schema && !await G(i.schema, R(g[u].values), T)) return t.preventDefault();
e?.enctype === "multipart/form-data" && (n = V(R(g[u].values))), !e.action && (t.preventDefault(), f.value = !0, await U(e.onSubmit?.(n, t)), f.value = !1);
}, x = () => {
let e = D(g[u].initialValues);
for (let t in e) if (!g[u].values[t]?.value) {
let n = O(g[u].values, t);
n ? n.value = e[t] : g[u].values = B(g[u].values, E(t, {
value: e[t],
error: void 0
}));
}
};
h(z, (t, n) => {
p.value && JSON.stringify(t) !== JSON.stringify(n) && e.onValueChange && v.emit("value-change", u), i?.mode === "onChange" && H.value && v.emit("validate");
}, { deep: !0 }), Object.keys(e.initialValues).length && (g[u].initialValues = B(g[u].initialValues, e.initialValues));
let S, C;
return s(async () => {
x(), y = JSON.stringify(g[u].values), e?.onValueChange && g[u] && (S = (e) => {
e === u && n("value-change", z.value);
}, v.on("value-change", S)), i?.mode === "onChange" && (C = async () => {
if (i?.schema) return await G(i.schema, R(g[u].values), T);
}, v.on("validate", C)), await a(), p.value = !0;
}), o(() => {
S && v.off("value-change", S), C && v.off("validate", C);
}), () => r("form", {
...e,
...c,
...n,
key: g[u].key,
onSubmit: b
}, t.default?.({
values: z.value,
getError: d,
getFieldState: k,
isDirty: H.value,
isValid: q.value,
isTouched: K.value,
isSubmitted: m.value,
submitCount: _.value
}));
}, {
name: "FormComponent",
props: {
enctype: {
type: String,
default: "application/x-www-form-urlencoded"
},
initialValues: {
type: Object,
default: Object.create({})
},
onValueChange: {
type: Function,
default: void 0
},
onSubmit: {
type: Function,
default: void 0
}
},
emits: ["submit", "value-change"],
slots: Object
}),
values: z,
isSubmitting: f,
isSubmitted: m,
isDirty: H,
isValid: q,
isTouched: K,
submitCount: _,
getFieldState: k,
reset: b,
setInitialValues: w,
setValue: S,
setValues: C,
setError: T,
validate: A,
clearErrors: j,
handleSubmit: x
};
}, te = () => t((t, { slots: n, attrs: i }) => {
let { value: a, isValid: o, isTouched: s, isDirty: c, inputProps: l, getError: u } = X(t, {
isComponent: !!t.custom,
isCheckbox: i.type === "checkbox"
}), d = e(() => {
let e = {
...i,
name: t.name,
error: u(),
onInput: (e) => {
l.value.onInput?.(e), typeof i.onInput == "function" && i.onInput();
},
onChange: (e) => {
l.value.onInput?.(e), typeof i.onChange == "function" && i.onChange();
},
onFocus: () => {
l.value.onFocus?.(), typeof i.onFocus == "function" && i.onFocus();
},
onBlur: async () => {
l.value.onBlur?.(), typeof i.onBlur == "function" && i.onBlur();
}
};
return e.type === "checkbox" && (e.checked = t.trueValue === void 0 ? !!a.value : a.value === t.trueValue), i.type !== "file" && i.type !== "checkbox" && t.as !== "select" && !e.multiple && (e.value = a.value), e;
}), p = () => ({ field: {
...l.value,
error: u(),
isValid: o.value,
isTouched: s.value,
isDirty: c.value,
onFocus: l.value.onFocus,
onBlur: l.value.onBlur
} });
return () => {
let e = f(w(t, !!n.default)), a = T(e, n, p);
if (e) {
let { value: n, modelValue: u, ...f } = l.value, p = i.type === "checkbox" ? f : l.value;
return r(e, {
...t,
...d.value,
...p,
isValid: o.value,
isTouched: s.value,
isDirty: c.value
}, a);
} else return a;
};
}, {
name: "Field",
inheritAttrs: !1,
props: {
name: {
type: String,
default: ""
},
default: {
type: [
String,
Array,
Boolean,
Number,
Object
],
default: void 0
},
preserve: {
type: Boolean,
default: !1
},
custom: {
type: Boolean,
default: !1
},
modelValue: {
type: [
String,
Array,
Boolean,
Number,
Object
],
default: void 0
},
as: {
type: String,
default: void 0
},
rule: {
type: [Object, Function],
default: void 0
},
ignore: {
type: Boolean,
default: void 0
},
trueValue: {
type: [
String,
Boolean,
Number,
Object
],
default: void 0
},
falseValue: {
type: [
String,
Boolean,
Number,
Object
],
default: void 0
}
},
emits: ["update:modelValue"]
}), ne = (e) => {
let t = ee(e), n = te(), r = Z(), i = Q();
return {
Form: t.cmp,
Field: n,
FieldArray: r,
Error: i,
reset: t.reset,
setInitialValues: t.setInitialValues,
setValue: t.setValue,
setValues: t.setValues,
setError: t.setError,
getFieldState: t.getFieldState,
validate: t.validate,
clearErrors: t.clearErrors,
handleSubmit: t.handleSubmit,
values: t.values,
isSubmitting: t.isSubmitting,
isSubmitted: t.isSubmitted,
isDirty: t.isDirty,
isValid: t.isValid,
isTouched: t.isTouched,
submitCount: t.submitCount
};
};
//#endregion
export { ne as useForm, X as useInput };