UNPKG

vue-formify

Version:

Build powerful, type-safe forms in Vue.

670 lines (669 loc) 19.2 kB
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 };