UNPKG

houseform

Version:

Simple to use React forms, where your validation and UI code live together in harmony.

993 lines (992 loc) 21.6 kB
import { createContext as He, useContext as Me, memo as Ve, forwardRef as ge, useRef as z, useState as $, useCallback as a, useMemo as G, useImperativeHandle as ye, useLayoutEffect as xe, useEffect as Pe } from "react"; import { jsx as Le } from "react/jsx-runtime"; const ze = { formFieldsRef: { current: [] }, recomputeErrors: () => { }, recomputeIsDirty: () => { }, recomputeIsTouched: () => { }, recomputeIsValidating: () => { }, errors: [], errorsMap: {}, submit: async () => !0, getFieldValue: () => { }, deleteField: () => { }, setIsSubmitted: () => { }, reset: () => { }, onChangeListenerRefs: { current: {} }, onBlurListenerRefs: { current: {} }, onMountListenerRefs: { current: {} }, setIsTouched: () => { }, setIsDirty: () => { }, isValid: !1, isDirty: !1, isTouched: !1, isValidating: !1, isSubmitted: !1, value: {}, recomputeFormValue: () => { } }, Ae = He(ze), oe = () => Me(Ae); function ne(e, n, i) { return ((u) => u instanceof Object && u.parseAsync)(i) ? i.parseAsync(e) : i(e, n); } function se(e) { return ((i) => i instanceof Object && i.errors)(e) ? e.errors.map((i) => i.message) : [e]; } const Se = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g, Oe = /\\(\\)?/g, N = (e) => { const n = []; return e.replace(Se, (i, l, u, o) => { const r = u ? o.replace(Oe, "$1") : l || i; r && n.push(r); }), n; }, ve = (e, n, i) => { const l = N(n); let u = e; for (let o = 0; o < l.length; o++) { const r = l[o]; o === l.length - 1 ? u[r] = i : (u[r] || (u[r] = {}), u = u[r]); } return e; }, je = (e, n) => { const i = N(n); let l = e; for (let u = 0; u < i.length; u++) { const o = i[u]; if (u === i.length - 1) return l[o]; l = l[o]; } }; function Ge(e, n) { const { onSubmit: i, children: l, memoChild: u, submitWhenInvalid: o = !1 } = e, r = z([]), [_, d] = $(!1), s = a( (t) => { const h = r.current, g = N(t).join("."); return h.find( (Z) => Z._normalizedDotName === g ); }, [r] ), C = a( (t) => { const h = r.current, g = N(t).join("."), Z = h.find( (Y) => Y._normalizedDotName === g ); Z && h.splice(h.indexOf(Z), 1); }, [r] ), R = z({}), b = z({}), S = z({}), k = a((t) => { r.current.forEach((h) => { h.setIsTouched(t); }); }, []), M = a((t) => { r.current.forEach((h) => { h.setIsDirty(t); }); }, []), [O, I] = $(null), [L, E] = $(null), [p, B] = $(null), [F, T] = $(null), [x, w] = $(null), [P, H] = $(null), [m, j] = $(null), f = z(!1), D = z(!1), X = z(!1), y = z(!1), c = z(!1), v = z(!1), V = a(() => r.current.reduce((t, h) => t.concat(h.errors), []), [r]), K = a(() => { const t = {}; return r.current.forEach((h) => { const g = h.props.name; t[g] = h.errors; }), t; }, [r]), q = a(() => r.current.length === 0 ? !0 : r.current.every((t) => t.errors.length === 0), [r]), A = a( (t) => r.current.some((h) => !!h[t]), [r] ), J = a(() => r.current.reduce((t, h) => (ve(t, h.props.name, h.value), t), {}), [r]), ie = a(() => { if (f.current) { const t = V(), h = K(); I(t), E(h); } if (D.current) { const t = q(); B(t); } }, [V, K, q]), Te = a(() => { if (X.current) { const t = A("isDirty"); T(t); } }, [A]), Fe = a(() => { if (y.current) { const t = A("isTouched"); w(t); } }, [A]), De = a(() => { if (c.current) { const t = J(); H(t); } }, [J]), Ee = a(() => { if (v.current) { const t = A("isValidating"); j(t); } }, [A]), ue = a(() => { if (f.current = !0, O === null) { const t = V(); return I(t), t; } return O; }, [O, V]), ae = a(() => { if (f.current = !0, L === null) { const t = K(); return E(t), t; } return L; }, [L, K]), ce = a(() => { if (D.current = !0, p === null) { const t = q(); return B(t), t; } return p; }, [p, q]), le = a(() => { if (F === null) { X.current = !0; const t = A("isDirty"); return T(t), t; } return F; }, [F, A]), de = a(() => { if (x === null) { y.current = !0; const t = A("isTouched"); return w(t), t; } return x; }, [x, A]), me = a(() => { if (P === null) { c.current = !0; const t = J(); return H(t), t; } return P; }, [P, J]), he = a(() => { r.current.sort((t, h) => N(h.props.name).length - N(t.props.name).length).forEach((t) => { const h = t.props.resetWithValue ?? t.props.initialValue, g = (Y) => !!Y.setValues, Z = (Y) => !Y.setValues; t.setErrors([]), t.setIsTouched(!1), t.setIsDirty(!1), g(t) ? t.setValues({ __value: h || [], __isResetting: !0 }) : Z(t) && t.setValue({ __value: h || "", __isResetting: !0 }); }), I([]), B(!1), T(!1), w(!1); }, [w, T, I]), fe = a(() => { if (m === null) { v.current = !0; const t = A("isValidating"); return j(t), t; } return m; }, [m, A]), Q = G(() => ({ getFieldValue: s, deleteField: C, onChangeListenerRefs: R, onBlurListenerRefs: b, onMountListenerRefs: S, isSubmitted: _, setIsSubmitted: d, formFieldsRef: r, setIsTouched: k, setIsDirty: M, recomputeErrors: ie, recomputeIsDirty: Te, recomputeIsTouched: Fe, recomputeFormValue: De, recomputeIsValidating: Ee, reset: he, get errors() { return ue(); }, get errorsMap() { return ae(); }, get isValid() { return ce(); }, get isDirty() { return le(); }, get isTouched() { return de(); }, get value() { return me(); }, get isValidating() { return fe(); }, submit: () => Promise.resolve(!0) }), [ s, C, _, k, M, ie, Te, Fe, De, Ee, ue, ae, ce, le, de, me, fe, he ]), we = a(async () => { d(!0); const t = {}, h = await Promise.all( r.current.map(async (g) => { const Z = async (U) => { const ee = g.props[U]; if (!ee) return !0; try { return U === "onSubmitValidate" && g._setIsValidating(!0), await ne(g.value, Q, ee), !0; } catch (_e) { return g.setErrors(se(_e)), !1; } finally { U === "onSubmitValidate" && g._setIsValidating(!1); } }, Y = async (U) => { const ee = g.props[U]; if (!ee) return !0; try { return await ne(g.value, Q, ee), !0; } catch (_e) { return g.setHints(se(_e)), !1; } }; if (g.setHints([]), await Y("onMountHint"), await Y("onChangeHint"), await Y("onBlurHint"), await Y("onSubmitHint"), g.setErrors([]), !await Z("onMountValidate") || !await Z("onChangeValidate") || !await Z("onBlurValidate") || !await Z("onSubmitValidate")) return !1; const ke = await (async () => { const U = g.props.onSubmitTransform; if (!U) return g.value; try { return await ne(g.value, Q, U); } catch (ee) { g.setErrors(se(ee)); } })(); return g.errors.length > 0 ? !1 : (ve(t, g.props.name, ke), !0); }) ); return !o && !h.every((g) => !!g) ? !1 : (i == null || i(t, Q), !0); }, [Q, i, o]), te = G(() => { const t = [ "errors", "errorsMap", "isValid", "isDirty", "isTouched", "isValidating", "submit", "value", "reset" ], h = { reset: he, submit: we, get errors() { return ue(); }, get errorsMap() { return ae(); }, get isValid() { return ce(); }, get isDirty() { return le(); }, get isTouched() { return de(); }, get value() { return me(); }, get isValidating() { return fe(); } }; for (const g of Object.keys(Q)) { if (t.includes(g)) continue; const Z = g; h[Z] = Q[Z]; } return h; }, [ he, Q, ue, ae, le, de, ce, me, fe, we ]); ye(n, () => te, [te]); const be = G( () => l(te), // eslint-disable-next-line react-hooks/exhaustive-deps u ? u.concat(te) : [l, te] ); return /* @__PURE__ */ Le(Ae.Provider, { value: te, children: be }); } const tt = Ve(ge(Ge)), pe = typeof window < "u", W = pe ? xe : Pe, re = (e) => !Array.isArray(e) && e !== null && typeof e == "object" && "__isResetting" in e; function Ce({ listenTo: e, runFieldValidation: n, valueRef: i }) { const l = oe(); W(() => { if (!e || e.length === 0) return; function u() { n("onChangeValidate", i.current); } function o() { n("onBlurValidate", i.current); } function r() { n("onMountValidate", i.current); } function _(s, C, R) { return l[s].current[C] = l[s].current[C] ?? [], l[s].current[C].push(R), () => { l[s].current[C].splice( l[s].current[C].indexOf(R), 1 ); }; } const d = e.flatMap((s) => { const C = _( "onChangeListenerRefs", s, u ), R = _( "onBlurListenerRefs", s, o ), b = _( "onMountListenerRefs", s, r ); return [C, R, b]; }); return () => d.forEach((s) => s()); }, [l, e, n, i]); } const Re = ({ initialValue: e, props: n }) => { const { name: i } = n, l = G(() => N(i).join("."), [i]), u = oe(), o = u.formFieldsRef.current.find( (m) => m._normalizedDotName === l ), [r, _] = $((o == null ? void 0 : o.errors) ?? []), [d, s] = $((o == null ? void 0 : o.hints) ?? []), [C, R] = $( (o == null ? void 0 : o.isTouched) ?? !1 ), [b, S] = $( (o == null ? void 0 : o.isDirty) ?? !1 ), [k, M] = $( (o == null ? void 0 : o.isValidating) ?? !1 ), O = u.isSubmitted, I = a( (m, j) => { let f = n.onChangeValidate; m === "onBlurValidate" && (f = n == null ? void 0 : n.onBlurValidate), m === "onMountValidate" && (f = n == null ? void 0 : n.onMountValidate), f && (M(!0), ne(j, u, f).then(() => { _([]); }).catch((D) => { _(se(D)); }).finally(() => { M(!1); })); }, [u, n] ), L = a( (m, j) => { let f = n.onChangeHint; m === "onBlurHint" && (f = n == null ? void 0 : n.onBlurHint), m === "onMountHint" && (f = n == null ? void 0 : n.onMountHint), f && (M(!0), ne(j, u, f).then(() => { s([]); }).catch((D) => { s(se(D)); }).finally(() => { M(!1); })); }, [u, n] ), E = n.initialValue ?? e, p = z(!1), [B, F] = $((o == null ? void 0 : o.value) ?? E); W(() => { p.current || (p.current = !0, L("onMountHint", E), I("onMountValidate", E)); }); const T = z(B); T.current = B; const x = a( (m) => { F((j) => { const f = re(m) && m.__isResetting, D = re(m) ? m.__value : m, y = ((c) => typeof c == "function")(D) ? D(j) : D; return f || (S(y !== E), setTimeout(() => { var c; (c = u.onChangeListenerRefs.current[n.name]) == null || c.forEach( (v) => v() ); }, 0), L("onChangeHint", y), I("onChangeValidate", y)), y; }); }, [ E, I, L, u.onChangeListenerRefs, n.name ] ), w = G(() => r.length === 0, [r]), P = a( (m) => { I(m, T.current); }, [I, T] ), H = a( (m) => { L(m, T.current); }, [L, T] ); return { value: B, setErrors: _, errors: r, hints: d, setHints: s, setIsDirty: S, setIsTouched: R, setValue: x, isTouched: C, isDirty: b, isValid: w, isValidating: k, isSubmitted: O, runFieldValidation: I, runFieldHintCheck: L, valueRef: T, validate: P, checkHint: H, _normalizedDotName: l, _setIsValidating: M }; }, Ie = ({ fieldInstanceRef: e, props: n, value: i, errors: l, isDirty: u, isValid: o, isTouched: r, isValidating: _, preserveValue: d }) => { const s = oe(); W(() => { e.current.props = n; const C = e.current, R = s.formFieldsRef.current; if (s.deleteField(n.name), R.push(C), !d) return () => { s.deleteField(n.name); }; }, [ s.deleteField, s.formFieldsRef, e, n, d ]), W(() => { e.current.value = i; }, [e, i]), W(() => { e.current.errors = l; }, [l, e]), W(() => { e.current.isDirty = u; }, [u, e]), W(() => { e.current.isValid = o; }, [o, e]), W(() => { e.current.isTouched = r; }, [r, e]), W(() => { e.current.isValidating = _; }, [_, e]), W(() => (s.recomputeErrors(), () => { s.recomputeErrors(); }), [l, s.recomputeErrors]), W(() => (s.recomputeIsTouched(), () => { s.recomputeIsTouched(); }), [r, s.recomputeIsTouched]), W(() => (s.recomputeIsDirty(), () => { s.recomputeIsDirty(); }), [u, s.recomputeIsDirty]), W(() => (s.recomputeIsValidating(), () => { s.recomputeIsValidating(); }), [_, s.recomputeIsValidating]), W(() => (s.recomputeFormValue(), () => { s.recomputeFormValue(); }), [i, s.recomputeFormValue]); }; function Ze(e, n) { const i = oe(), { children: l, memoChild: u, preserveValue: o } = e, { value: r, setErrors: _, errors: d, hints: s, setHints: C, setIsDirty: R, setIsTouched: b, setValue: S, isTouched: k, isDirty: M, isValid: O, isValidating: I, isSubmitted: L, runFieldValidation: E, runFieldHintCheck: p, valueRef: B, _normalizedDotName: F, _setIsValidating: T, validate: x, checkHint: w } = Re({ props: e, initialValue: "" }); Ce({ listenTo: e.listenTo, runFieldValidation: E, valueRef: B }); const P = a(() => { b(!0), setTimeout(() => { var f; (f = i.onBlurListenerRefs.current[e.name]) == null || f.forEach((D) => D()); }, 0), p("onBlurHint", B.current), E("onBlurValidate", B.current); }, [ i.onBlurListenerRefs, e.name, E, b, B ]), H = G(() => ({ value: r, props: e, setErrors: _, errors: d, setIsDirty: R, setIsTouched: b, setValue: S, isTouched: k, isDirty: M, isValid: O, isValidating: I, isSubmitted: L, onBlur: P, _normalizedDotName: F, _setIsValidating: T, validate: x, hints: s, setHints: C, checkHint: w }), [ e, r, _, d, R, b, S, k, M, O, I, L, P, F, T, x, s, C, w ]), m = z(H); return Ie({ fieldInstanceRef: m, props: e, value: r, errors: d, isValid: O, isDirty: M, isTouched: k, isValidating: I, preserveValue: o }), ye(n, () => H, [H]), G( () => l(H), u ? u.concat(H) : [l, H] ); } const rt = Ve(ge(Ze)), We = { value: [], setValue: () => { }, setValues: () => { }, props: { name: "" }, errors: [], setErrors: () => { }, setIsDirty: () => { }, isValid: !1, isValidating: !1, setIsTouched: () => { }, isDirty: !1, isTouched: !1, _normalizedDotName: "", add: () => { }, remove: () => { }, insert: () => { }, move: () => { }, swap: () => { }, replace: () => { }, validate: () => { }, _setIsValidating: () => { }, hints: [], setHints: () => { }, checkHint: () => { } }, Be = He(We), $e = () => Me(Be); function Ke(e, n) { const { children: i, memoChild: l, preserveValue: u } = e, { value: o, errors: r, setErrors: _, setValue: d, hints: s, setHints: C, isTouched: R, isDirty: b, isValid: S, isValidating: k, _normalizedDotName: M, _setIsValidating: O, runFieldValidation: I, valueRef: L, setIsDirty: E, setIsTouched: p, validate: B, checkHint: F } = Re({ props: e, initialValue: [] }); Ce({ listenTo: e.listenTo, runFieldValidation: I, valueRef: L }); const T = a( (y, c) => { const v = re(c) && c.__isResetting, V = re(c) ? c.__value : c, K = (q) => { const A = [...q]; return A[y] = V, A; }; if (v) { d({ __value: K, __isResetting: !0 }); return; } d(K); }, [d] ), x = a( (y) => { d((c) => [...c, y]); }, [d] ), w = a( (y) => { d((c) => { const v = [...c]; return v.splice(y, 1), v; }); }, [d] ), P = a( (y, c) => { d((v) => { const V = [...v]; return V.splice(y, 0, c), V; }); }, [d] ), H = a( (y, c) => { d((v) => { const V = [...v], K = V[y]; return V.splice(y, 1), V.splice(c, 0, K), V; }); }, [d] ), m = a( (y, c) => { d((v) => { const V = [...v]; return V[y] = c, V; }); }, [d] ), j = a( (y, c) => { d((v) => { const V = [...v], K = V[y]; return V[y] = V[c], V[c] = K, V; }); }, [d] ), f = G(() => ({ value: o, add: x, move: H, insert: P, remove: w, swap: j, replace: m, setValue: T, props: e, _normalizedDotName: M, _setIsValidating: O, errors: r, setErrors: _, hints: s, setHints: C, isValid: S, isValidating: k, setIsDirty: E, isDirty: b, setIsTouched: p, isTouched: R, setValues: d, validate: B, checkHint: F }), [ o, x, H, P, w, j, m, T, e, M, O, r, _, s, C, S, k, E, b, p, R, d, B, F ]), D = z(f); Ie({ value: o, fieldInstanceRef: D, isValid: S, isValidating: k, isDirty: b, isTouched: R, props: e, errors: r, preserveValue: u }), ye(n, () => f, [f]); const X = G( () => i(f), l ? l.concat(f) : [i, f] ); return /* @__PURE__ */ Le(Be.Provider, { value: f, children: X }); } const nt = Ve(ge(Ke)); function Ye(e, n) { const { children: i, memoChild: l, preserveValue: u } = e, { _normalizedDotName: o, _setIsValidating: r, errors: _, setErrors: d, hints: s, setHints: C, runFieldValidation: R, runFieldHintCheck: b, isValid: S, isValidating: k, isTouched: M, isSubmitted: O, setIsTouched: I, isDirty: L, setIsDirty: E, validate: p, checkHint: B } = Re({ props: e, initialValue: "" }), F = $e(), T = oe(), x = G(() => { const c = N(F.props.name), v = N(e.name); for (const V of c) if (V !== v.shift()) throw new Error( "You must prepend the FieldArrayItem name with the name of the parent FieldArray" ); return v; }, [F.props.name, e.name]), w = G(() => parseInt(x[0]), [x]), P = G(() => x.slice(1), [x]), H = G(() => je(F.value[w], P.join(".")), [P, F.value, w]), m = z(H); m.current = H, Ce({ listenTo: e.listenTo, runFieldValidation: R, valueRef: m }); const j = a( (c) => { const v = re(c) && c.__isResetting, V = re(c) ? c.__value : c, q = ((J) => typeof J == "function")(V) ? V(F.value[w]) : V, A = { ...F.value[w] }; if (ve(A, P.join("."), q), v) { F.setValue(w, { __value: A, __isResetting: !0 }); return; } F.setValue(w, A), E(!0), setTimeout(() => { var J; (J = T.onChangeListenerRefs.current[e.name]) == null || J.forEach( (ie) => ie() ); }, 0), R("onChangeValidate", q); }, [ P, F, T.onChangeListenerRefs, w, e.name, R, E ] ), f = a(() => { I(!0), setTimeout(() => { var c; (c = T.onBlurListenerRefs.current[e.name]) == null || c.forEach((v) => v()); }, 0), b("onBlurHint", m.current), R("onBlurValidate", m.current); }, [ T.onBlurListenerRefs, e.name, b, R, I ]), D = G(() => ({ setValue: j, errors: _, value: H, _normalizedDotName: o, _setIsValidating: r, onBlur: f, props: e, isTouched: M, isValid: S, isDirty: L, isValidating: k, setIsDirty: E, setErrors: d, setIsTouched: I, validate: p, isSubmitted: O, hints: s, setHints: C, checkHint: B }), [ j, _, H, o, r, f, e, M, S, L, k, E, d, I, p, O, s, C, B ]), X = z(D); return Ie({ fieldInstanceRef: X, props: e, value: H, errors: _, isValid: S, isDirty: L, isTouched: M, isValidating: k, preserveValue: u }), ye(n, () => D, [D]), G( () => i(D), l ? l.concat(D) : [i, D] ); } const st = Ve(ge(Ye)); export { rt as Field, nt as FieldArray, Be as FieldArrayContext, st as FieldArrayItem, Ye as FieldArrayItemComp, tt as Form, Ae as FormContext, ve as fillPath, je as getPath, se as getValidationError, We as initialFieldArrayContext, ze as initialFormContext, re as isInternal, N as stringToPath, $e as useFieldArrayContext, Re as useFieldLike, Ie as useFieldLikeSync, oe as useFormContext, Ce as useListenToListenToArray, ne as validate };