@paragrav/rhf-utils 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,20 +77,22 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
77
77
  // inject your own hooks and components
78
78
  // into all RhfUtilsZodForm instances
79
79
  FormChildren: (
80
- // RhfUtilsFormComponentProps
80
+ // RhfUtilsFormInjectorProps
81
81
  {
82
+ Outlet, // Form instance (RhfUtilsZodForm.Children) "outlet"
83
+
82
84
  formId, // unique id string
83
85
  formRef, // form element ref
84
86
  context, // rhf UseFormReturn (without proxy `formState`)
85
87
  options, // RhfUtilsFormOptions (with any custom props)
86
88
  Controller, // rhf controller (SafeFieldValues-typed; no schema at this level)
87
89
  FormSubmitError, // error class (SafeFieldValues-typed; no schema at this level)
88
- children, // RhfUtilsZodForm's Children instance
89
90
  },
90
91
  ) => {
92
+ // hook injected across all instances
91
93
  useMyGlobalFormHook();
92
94
 
93
- // form-level control of your own hooks/behaviors via custom option props
95
+ // hook injected across all instances with per-instance opt-in flag via custom option props
94
96
  // (see "Extend RhfUtilsFormOptions" section for more info)
95
97
  useMyOptionalFormHook({
96
98
  enabled: !!options.enableMyOptionalFormHook,
@@ -98,8 +100,8 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
98
100
 
99
101
  return (
100
102
  <>
101
- {/* RhfUtilsZodForm.Children "outlet" (see "Component Hierarchy" section) */}
102
- {children}
103
+ {/* Form instance (RhfUtilsZodForm.Children) "outlet" (see "Component Hierarchy" section). */}
104
+ <Outlet />
103
105
 
104
106
  {/* root errors list */}
105
107
  <RootErrorsList />
@@ -190,7 +192,7 @@ Currently, only `zod` schemas are supported.
190
192
  {
191
193
  field: 'passwordConfirm', // type safe
192
194
  message: 'Passwords must match.',
193
- valid: data.password === data.passwordConfirm,
195
+ validate: data.password === data.passwordConfirm,
194
196
  },
195
197
  ]}
196
198
  onBeforeSubmit={({ input, output, api }, context, event) => {
@@ -2,6 +2,6 @@ export { useRhfUtilsContext } from '../form/context/utils/useRhfUtilsContext';
2
2
  export type { RhfUtilsFormOptions } from '../form/options/RhfUtilsFormOptionsType';
3
3
  export type { SafeFieldValues } from '../form/rhf/SafeFieldValuesType';
4
4
  export type { RHF_UseFormReturnWithoutProxies as UseFormReturnWithoutProxies } from '../form/RHF_UseFormReturnWithoutProxiesType';
5
- export type { RhfUtilsFormComponentProps } from '../form/RhfUtilsFormComponentPropsType';
5
+ export type { RhfUtilsFormInjectorProps } from '../form/RhfUtilsFormInjectorProps';
6
6
  export type { UseRhfUtilsFormChildrenProps } from '../form/UseRhfUtilsFormChildrenPropsType';
7
7
  export { useFormRequestSubmit } from '../form/utils/useFormRequestSubmit';
@@ -1,6 +1,6 @@
1
1
  import { FlatFieldErrorsOutputConfig } from '../../errors/flat/context/FlatFieldErrorsOutputConfig';
2
2
  import { UseRhfUtilsFormGlobalDefaults } from '../../form/defaults/UseRhfUtilsFormGlobalDefaults';
3
- import { RhfUtilsFormComponentProps } from '../../form/RhfUtilsFormComponentPropsType';
3
+ import { RhfUtilsFormInjectorProps } from '../../form/RhfUtilsFormInjectorProps';
4
4
  import { FormSubmitFieldErrors } from '../../submit/error/FormSubmitFieldErrors';
5
5
  import { UseRhfUtilsFormOnSubmitContext } from '../../submit/UseRhfUtilsFormOnSubmitContextType';
6
6
  import { MaybePromise } from '../../utils/types';
@@ -26,8 +26,12 @@ export type RhfUtilsClientConfig = {
26
26
  * @description
27
27
  *
28
28
  * (NOTE: context params are not schema-typed as not possible at this level.)
29
+ *
30
+ * @example
31
+ *
32
+ * See README.
29
33
  */
30
- FormChildren?: React.FC<React.PropsWithChildren<RhfUtilsFormComponentProps>>;
34
+ FormInjector?: React.FC<RhfUtilsFormInjectorProps>;
31
35
  /**
32
36
  * A hook that returns a callback that determines whether form can be cancelled at event-time.
33
37
  *
@@ -1,13 +1,17 @@
1
1
  import { UseFormReturn } from 'react-hook-form';
2
2
  import { FormSubmitError } from '../submit/error/FormSubmitError';
3
+ import { Merge } from '../utils/types';
3
4
  import { _Controller } from './_Controller';
4
5
  import { RhfUtilsContext } from './context/utils/RhfUtilsContextType';
5
6
  import { SafeFieldValues } from './rhf/SafeFieldValuesType';
6
7
  /**
7
8
  * RhfUtilsClientConfig's FormComponent props.
8
9
  */
9
- export type RhfUtilsFormComponentProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = TFieldValues> = RhfUtilsContext & {
10
+ export type RhfUtilsFormInjectorProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = TFieldValues> = Merge<{
11
+ /** Form instance children (`RhfUtilsZodForm.Children`) to output amid globally-injected code. */
12
+ Outlet: React.FC;
13
+ }, RhfUtilsContext, {
10
14
  rhf: UseFormReturn<TFieldValues, unknown, TTransformedValues>;
11
15
  Controller: typeof _Controller<TFieldValues>;
12
16
  FormSubmitError: typeof FormSubmitError<TFieldValues>;
13
- };
17
+ }>;
@@ -4,16 +4,8 @@ import { UseRhfUtilsFormOnSubmitContext, UseRhfUtilsFormOnSubmitErrorContext } f
4
4
  import { UseRhfUtilsFormInstanceFormProps } from '../defaults/form/UseRhfUtilsFormInstanceFormProps';
5
5
  import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
6
6
  import { UseRhfUtilsFormChildrenProps } from '../UseRhfUtilsFormChildrenPropsType';
7
+ import { RhfUtilsFormPropsOnBeforeSubmitInvariants } from './RhfUtilsFormPropsOnBeforeSubmitInvariants';
7
8
  export type RhfUtilsFormPropsGetApiValues<TTransformedValues extends SafeFieldValues, TApiValues> = (data: TTransformedValues) => TApiValues;
8
- export type RhfUtilsFormPropsonBeforeSubmitInvariants<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TApiValues extends undefined | SafeFieldValues> = (data: {
9
- input: TFieldValues;
10
- output: TTransformedValues;
11
- api: TApiValues;
12
- }, context: UseRhfUtilsFormOnSubmitContext<TFieldValues, TTransformedValues, TApiValues>, event: React.BaseSyntheticEvent<SubmitEvent>) => MaybePromise<{
13
- field: keyof TFieldValues | keyof TApiValues;
14
- message: string;
15
- valid: boolean | undefined | null;
16
- }[]>;
17
9
  export type RhfUtilsFormProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TGetApiValues extends undefined | RhfUtilsFormPropsGetApiValues<TTransformedValues, SafeFieldValues>, TOnSubmitReturnType, TApiValues extends undefined | SafeFieldValues = TGetApiValues extends RhfUtilsFormPropsGetApiValues<TTransformedValues, infer U> ? U : undefined> = {
18
10
  getApiData?: TGetApiValues;
19
11
  /** Cancellation handler -- channeled through {@link RhfUtilsClientConfig.useCanFormBeCancelled} before propagating to `Children` component. */
@@ -24,7 +16,7 @@ export type RhfUtilsFormProps<TFieldValues extends SafeFieldValues, TTransformed
24
16
  * List of invariants to run against input/output/api data.
25
17
  * For any and all false-y values, a {@link FormSubmitFieldErrors} will be thrown.
26
18
  */
27
- onBeforeSubmitInvariants?: RhfUtilsFormPropsonBeforeSubmitInvariants<TFieldValues, TTransformedValues, TApiValues>;
19
+ onBeforeSubmitInvariants?: RhfUtilsFormPropsOnBeforeSubmitInvariants<TFieldValues, TTransformedValues, TApiValues>;
28
20
  onBeforeSubmit?: (data: {
29
21
  input: TFieldValues;
30
22
  output: TTransformedValues;
@@ -0,0 +1,12 @@
1
+ import { UseRhfUtilsFormOnSubmitContext } from '../../submit/UseRhfUtilsFormOnSubmitContextType';
2
+ import { MaybePromise } from '../../utils/types';
3
+ import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
4
+ export type RhfUtilsFormPropsOnBeforeSubmitInvariants<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TApiValues extends undefined | SafeFieldValues> = (data: {
5
+ input: TFieldValues;
6
+ output: TTransformedValues;
7
+ api: TApiValues;
8
+ }, context: UseRhfUtilsFormOnSubmitContext<TFieldValues, TTransformedValues, TApiValues>, event: React.BaseSyntheticEvent<SubmitEvent>) => MaybePromise<{
9
+ field: keyof TFieldValues | keyof TApiValues;
10
+ message: string;
11
+ validate: boolean | undefined | null;
12
+ }[]>;
@@ -1,4 +1,8 @@
1
+ import { Resolver } from 'react-hook-form';
2
+ import { Merge } from '../../utils/types';
1
3
  import { RhfUtilsFormProvidersProps } from '../providers/RhfUtilsFormProvidersPropsType';
2
4
  import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
3
5
  import { RhfUtilsFormProps, RhfUtilsFormPropsGetApiValues } from '../with-handlers-and-children/RhfUtilsFormProps';
4
- export type RhfUtilsFormWithProvidersProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TGetApiValues extends undefined | RhfUtilsFormPropsGetApiValues<TTransformedValues, SafeFieldValues>, TOnSubmitReturnType, TApiValues extends undefined | SafeFieldValues = TGetApiValues extends RhfUtilsFormPropsGetApiValues<TTransformedValues, infer U> ? U : undefined> = RhfUtilsFormProvidersProps<TFieldValues, TTransformedValues> & RhfUtilsFormProps<TFieldValues, TTransformedValues, TGetApiValues, TOnSubmitReturnType, TApiValues>;
6
+ export type RhfUtilsFormWithProvidersProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TGetApiValues extends undefined | RhfUtilsFormPropsGetApiValues<TTransformedValues, SafeFieldValues>, TOnSubmitReturnType, TApiValues extends undefined | SafeFieldValues = TGetApiValues extends RhfUtilsFormPropsGetApiValues<TTransformedValues, infer U> ? U : undefined> = Merge<RhfUtilsFormProps<TFieldValues, TTransformedValues, TGetApiValues, TOnSubmitReturnType, TApiValues>, RhfUtilsFormProvidersProps<TFieldValues, TTransformedValues>, {
7
+ resolver?: Resolver<TFieldValues, unknown, TTransformedValues>;
8
+ }>;
@@ -9,6 +9,6 @@ import { SafeFieldValues } from '../../form/rhf/SafeFieldValuesType';
9
9
  * - simplified `ErrorOption` value.
10
10
  */
11
11
  export type FormSubmitFieldErrors<TFieldValues extends SafeFieldValues = SafeFieldValues> = Record<FieldPath<TFieldValues> | `root.${string}`, {
12
- type?: string;
13
12
  message: string;
13
+ type?: string;
14
14
  }>;
@@ -1,140 +1,89 @@
1
- import { jsx as F } from "react/jsx-runtime";
2
- import s from "react";
3
- import { get as S, useFormState as R } from "react-hook-form";
4
- import { flatten as b } from "flat";
5
- function f() {
6
- const e = s.createContext(void 0), r = () => s.useContext(e), t = () => {
7
- const o = r();
8
- if (o === void 0) throw new Error();
9
- return o;
10
- };
11
- return {
12
- Provider: e.Provider,
13
- useMaybe: r,
14
- useRequired: t
15
- };
1
+ import e from "react";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { get as n, useFormState as r } from "react-hook-form";
4
+ import { flatten as i } from "flat";
5
+ //#region src/utils/createContext.ts
6
+ function a() {
7
+ let t = e.createContext(void 0), n = () => e.useContext(t);
8
+ return {
9
+ Provider: t.Provider,
10
+ useMaybe: n,
11
+ useRequired: () => {
12
+ let e = n();
13
+ if (e === void 0) throw Error();
14
+ return e;
15
+ }
16
+ };
16
17
  }
17
- const {
18
- Provider: x,
19
- useRequired: l
20
- } = f(), k = ({ children: e }) => {
21
- const [r, t] = s.useState({}), o = s.useCallback(
22
- (n, a, c) => {
23
- if (r[a.formId]) throw new Error("Form id already exists.");
24
- t((u) => ({
25
- ...u,
26
- [a.formId]: { state: n, utils: a, options: c }
27
- }));
28
- },
29
- [r]
30
- ), m = s.useCallback(
31
- (n, a) => {
32
- t((c) => {
33
- const u = c[n];
34
- if (!u) throw new Error("Form id doesn't exist");
35
- return {
36
- ...c,
37
- [n]: { ...u, state: a }
38
- };
39
- });
40
- },
41
- []
42
- ), i = s.useCallback((n) => {
43
- t(
44
- (a) => Object.fromEntries(
45
- Object.entries(a).filter(([c]) => c !== n)
46
- )
47
- );
48
- }, []);
49
- return /* @__PURE__ */ F(
50
- x,
51
- {
52
- value: {
53
- // set
54
- add: o,
55
- update: m,
56
- remove: i,
57
- // get
58
- state: r
59
- },
60
- children: e
61
- }
62
- );
63
- }, {
64
- Provider: I,
65
- useRequired: d,
66
- useMaybe: q
67
- } = f(), U = (e) => Object.keys(e).length === 0, E = (e) => b(e), p = (e) => {
68
- const r = E(e), t = Object.keys(r);
69
- return Object.fromEntries(
70
- t.reduce(
71
- (o, m) => {
72
- const i = m.replace(
73
- v,
74
- ""
75
- );
76
- if (i === m) return o;
77
- const n = S(e, i, void 0);
78
- return n && o.push([i, n]), o;
79
- },
80
- []
81
- // entries
82
- )
83
- );
84
- }, v = /\.(?:type|message)\b$/, C = (e) => Object.fromEntries(
85
- Object.entries(p(e)).map(([r, t]) => [
86
- r,
87
- {
88
- type: t.type,
89
- message: t.message,
90
- hasRef: !!t.ref
91
- // strip out actual ref, etc. (avoid circular JSON error)
92
- }
93
- ])
94
- ), O = (e) => {
95
- if (!e) return;
96
- const [r] = s.useState(e);
97
- g(r), h(r);
98
- }, g = (e) => {
99
- const r = d(), t = l(), o = y(e);
100
- s.useEffect(
101
- () => (t.add(o, r, e), () => {
102
- t.remove(r.formId);
103
- }),
104
- // eslint-disable-next-line react-hooks/exhaustive-deps
105
- []
106
- );
107
- }, h = (e) => {
108
- const r = d(), t = l(), o = y(e);
109
- s.useEffect(
110
- // when form state changes, publish to relay context
111
- () => {
112
- t.update(r.formId, o);
113
- },
114
- // eslint-disable-next-line react-hooks/exhaustive-deps
115
- [o]
116
- );
117
- }, y = (e) => {
118
- const r = R(), t = e.select(r), o = JSON.stringify({
119
- ...t,
120
- errors: t.errors && C(t.errors)
121
- });
122
- return s.useMemo(
123
- // when watch JSON changes, update memo
124
- () => t,
125
- // eslint-disable-next-line react-hooks/exhaustive-deps
126
- [o]
127
- );
128
- }, _ = ({ options: e }) => (O(e), null);
129
- export {
130
- k as F,
131
- I as _,
132
- _ as a,
133
- l as b,
134
- f as c,
135
- q as d,
136
- O as e,
137
- p as g,
138
- U as i,
139
- d as u
140
- };
18
+ //#endregion
19
+ //#region src/form/relay/context/useFormRelayContext.ts
20
+ var { Provider: o, useRequired: s } = a(), c = ({ children: n }) => {
21
+ let [r, i] = e.useState({});
22
+ return /* @__PURE__ */ t(o, {
23
+ value: {
24
+ add: e.useCallback((e, t, n) => {
25
+ if (r[t.formId]) throw Error("Form id already exists.");
26
+ i((r) => ({
27
+ ...r,
28
+ [t.formId]: {
29
+ state: e,
30
+ utils: t,
31
+ options: n
32
+ }
33
+ }));
34
+ }, [r]),
35
+ update: e.useCallback((e, t) => {
36
+ i((n) => {
37
+ let r = n[e];
38
+ if (!r) throw Error("Form id doesn't exist");
39
+ return {
40
+ ...n,
41
+ [e]: {
42
+ ...r,
43
+ state: t
44
+ }
45
+ };
46
+ });
47
+ }, []),
48
+ remove: e.useCallback((e) => {
49
+ i((t) => Object.fromEntries(Object.entries(t).filter(([t]) => t !== e)));
50
+ }, []),
51
+ state: r
52
+ },
53
+ children: n
54
+ });
55
+ }, { Provider: l, useRequired: u, useMaybe: d } = a(), f = (e) => Object.keys(e).length === 0, p = (e) => i(e), m = (e) => {
56
+ let t = p(e);
57
+ return Object.fromEntries(Object.keys(t).reduce((t, r) => {
58
+ let i = r.replace(h, "");
59
+ if (i === r) return t;
60
+ let a = n(e, i, void 0);
61
+ return a && t.push([i, a]), t;
62
+ }, []));
63
+ }, h = /\.(?:type|message)\b$/, g = (e) => Object.fromEntries(Object.entries(m(e)).map(([e, t]) => [e, {
64
+ type: t.type,
65
+ message: t.message,
66
+ hasRef: !!t.ref
67
+ }])), _ = (t) => {
68
+ if (!t) return;
69
+ let [n] = e.useState(t);
70
+ v(n), y(n);
71
+ }, v = (t) => {
72
+ let n = u(), r = s(), i = b(t);
73
+ e.useEffect(() => (r.add(i, n, t), () => {
74
+ r.remove(n.formId);
75
+ }), []);
76
+ }, y = (t) => {
77
+ let n = u(), r = s(), i = b(t);
78
+ e.useEffect(() => {
79
+ r.update(n.formId, i);
80
+ }, [i]);
81
+ }, b = (t) => {
82
+ let n = r(), i = t.select(n), a = JSON.stringify({
83
+ ...i,
84
+ errors: i.errors && g(i.errors)
85
+ });
86
+ return e.useMemo(() => i, [a]);
87
+ }, x = ({ options: e }) => (_(e), null);
88
+ //#endregion
89
+ export { l as a, c, f as i, s as l, _ as n, u as o, m as r, d as s, x as t, a as u };