@paragrav/rhf-utils 0.0.106 → 0.0.108

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.
Files changed (91) hide show
  1. package/README.md +67 -15
  2. package/dist/esm/src/client/index.mjs +55 -0
  3. package/dist/esm/src/errors/flat/useFlatFieldErrorsOutput.mjs +30 -0
  4. package/dist/esm/src/errors/trpc/getOnSubmitTrpcClientErrorHandler.mjs +7 -0
  5. package/dist/esm/src/errors/trpc/trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs +35 -0
  6. package/dist/esm/src/form/Form.mjs +91 -0
  7. package/dist/esm/{form → src/form}/FormProviders.mjs +1 -1
  8. package/dist/esm/src/form/useForm.mjs +43 -0
  9. package/dist/types/client/config/RhfUtilsClientConfig.d.ts +10 -9
  10. package/dist/types/exports.d.ts +1 -1
  11. package/dist/types/form/Form.d.ts +2 -2
  12. package/dist/types/form/FormProviders.d.ts +3 -3
  13. package/dist/types/form/RhfUtilsFormOptions.d.ts +28 -0
  14. package/dist/types/form/context/utils/FormUtilsContextProvider.d.ts +2 -2
  15. package/dist/types/form/context/utils/useFormUtilsContext.d.ts +2 -2
  16. package/dist/types/form/useForm.d.ts +5 -4
  17. package/dist/types/register.d.ts +2 -1
  18. package/package.json +5 -3
  19. package/dist/esm/client/index.mjs +0 -55
  20. package/dist/esm/errors/flat/useFlatFieldErrorsOutput.mjs +0 -24
  21. package/dist/esm/errors/trpc/getOnSubmitTrpcClientErrorHandler.mjs +0 -6
  22. package/dist/esm/errors/trpc/trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs +0 -34
  23. package/dist/esm/form/Form.mjs +0 -91
  24. package/dist/esm/form/useForm.mjs +0 -42
  25. /package/dist/esm/{client → src/client}/config/useRhfUtilsClientConfigContext.mjs +0 -0
  26. /package/dist/esm/{client → src/client}/zod/RhfUtilsZodForm.mjs +0 -0
  27. /package/dist/esm/{client → src/client}/zod/context/RhfUtilsClientForZodContextProvider.mjs +0 -0
  28. /package/dist/esm/{client → src/client}/zod/context/useRhfUtilsClientForZodContext.mjs +0 -0
  29. /package/dist/esm/{client → src/client}/zod/context/useRhfUtilsZodForm.mjs +0 -0
  30. /package/dist/esm/{client → src/client}/zod/createRhfUtilsClientForZod.mjs +0 -0
  31. /package/dist/esm/{devtool → src/devtool}/LazyDevTool.mjs +0 -0
  32. /package/dist/esm/{errors → src/errors}/flat/FlatFieldErrorsList.mjs +0 -0
  33. /package/dist/esm/{errors → src/errors}/flat/context/FlatFieldErrorsContextProvider.mjs +0 -0
  34. /package/dist/esm/{errors → src/errors}/flat/context/useFlatFieldErrorsContext.mjs +0 -0
  35. /package/dist/esm/{errors → src/errors}/flat/filterFlatFieldErrors.mjs +0 -0
  36. /package/dist/esm/{errors → src/errors}/flat/flattenFieldErrors.mjs +0 -0
  37. /package/dist/esm/{errors → src/errors}/flat/getFlatFieldErrors.mjs +0 -0
  38. /package/dist/esm/{errors → src/errors}/flat/useFormFlatFieldErrorsMemo.mjs +0 -0
  39. /package/dist/esm/{errors → src/errors}/isFieldErrorRefd.mjs +0 -0
  40. /package/dist/esm/{errors → src/errors}/message/FormErrorMessage.mjs +0 -0
  41. /package/dist/esm/{errors → src/errors}/message/FormErrorMessageByPath.mjs +0 -0
  42. /package/dist/esm/{errors → src/errors}/nonfield/FormNonFieldErrorMarker.mjs +0 -0
  43. /package/dist/esm/{errors → src/errors}/nonfield/FormNonFieldErrorMarker.utils.mjs +0 -0
  44. /package/dist/esm/{errors → src/errors}/nonfield/FormNonFieldErrorMarkerHtmlAttribute.mjs +0 -0
  45. /package/dist/esm/{errors → src/errors}/nonfield/isNonFieldErrorMarkerInDOM.mjs +0 -0
  46. /package/dist/esm/{errors → src/errors}/orphan/getIsOrphanFormErrorWithParentElement.mjs +0 -0
  47. /package/dist/esm/{errors → src/errors}/orphan/getOrphansFromFieldErrors.mjs +0 -0
  48. /package/dist/esm/{errors → src/errors}/orphan/getOrphansFromFlatFieldErrors.mjs +0 -0
  49. /package/dist/esm/{errors → src/errors}/orphan/isOrphanFormError.mjs +0 -0
  50. /package/dist/esm/{errors → src/errors}/orphan/useFormHasOnlyOrphanFieldErrorsMemo.mjs +0 -0
  51. /package/dist/esm/{errors → src/errors}/orphan/useOrphanFormErrorsMemo.mjs +0 -0
  52. /package/dist/esm/{errors → src/errors}/output/consoleErrors.mjs +0 -0
  53. /package/dist/esm/{errors → src/errors}/root/RootErrorsListFromFlatFieldErrorsContext.mjs +0 -0
  54. /package/dist/esm/{errors → src/errors}/root/consts.mjs +0 -0
  55. /package/dist/esm/{errors → src/errors}/root/getRootsFromFieldErrors.mjs +0 -0
  56. /package/dist/esm/{errors → src/errors}/root/getRootsFromFlatFieldErrors.mjs +0 -0
  57. /package/dist/esm/{errors → src/errors}/root/isFlatFieldErrorEntryPathRoot.mjs +0 -0
  58. /package/dist/esm/{errors → src/errors}/root/isFormErrorPathRoot.mjs +0 -0
  59. /package/dist/esm/{errors → src/errors}/root/useRootFormFieldErrorsMemo.mjs +0 -0
  60. /package/dist/esm/{errors → src/errors}/trpc/trpcClientErrorMessageSchema.mjs +0 -0
  61. /package/dist/esm/{errors → src/errors}/useFormErrorsEffect.mjs +0 -0
  62. /package/dist/esm/{errors → src/errors}/useFormErrorsIfAny.mjs +0 -0
  63. /package/dist/esm/{errors → src/errors}/useFormErrorsTransformMemo.mjs +0 -0
  64. /package/dist/esm/{errors → src/errors}/useFormRequestSubmit.mjs +0 -0
  65. /package/dist/esm/{exports.mjs → src/exports.mjs} +0 -0
  66. /package/dist/esm/{form → src/form}/FormWithProviders.mjs +0 -0
  67. /package/dist/esm/{form → src/form}/_Controller.mjs +0 -0
  68. /package/dist/esm/{form → src/form}/_FormBase.mjs +0 -0
  69. /package/dist/esm/{form → src/form}/context/group/FormGroupContextProvider.mjs +0 -0
  70. /package/dist/esm/{form → src/form}/context/group/index.mjs +0 -0
  71. /package/dist/esm/{form → src/form}/context/group/useFormGroupChildIsMountedTracker.mjs +0 -0
  72. /package/dist/esm/{form → src/form}/context/group/useFormGroupChildIsSubmittingTracker.mjs +0 -0
  73. /package/dist/esm/{form → src/form}/context/group/useFormGroupChildTracker.mjs +0 -0
  74. /package/dist/esm/{form → src/form}/context/group/useFormGroupIsAnyBusy.mjs +0 -0
  75. /package/dist/esm/{form → src/form}/context/group/useFormGroupIsChildBusy.mjs +0 -0
  76. /package/dist/esm/{form → src/form}/context/group/useFormGroupIsParentBusy.mjs +0 -0
  77. /package/dist/esm/{form → src/form}/context/group/useFormGroupParentTracker.mjs +0 -0
  78. /package/dist/esm/{form → src/form}/context/group/useFormOrParentIsBusy.mjs +0 -0
  79. /package/dist/esm/{form → src/form}/context/utils/FormUtilsContextProvider.mjs +0 -0
  80. /package/dist/esm/{form → src/form}/context/utils/useFormUtilsContext.mjs +0 -0
  81. /package/dist/esm/{form → src/form}/useFormIsBusy.mjs +0 -0
  82. /package/dist/esm/{form → src/form}/utils/getSubmitterButtonData.mjs +0 -0
  83. /package/dist/esm/{submit → src/submit}/error/FormSubmitError.mjs +0 -0
  84. /package/dist/esm/{submit → src/submit}/error/setCtxErrorsByFormSubmitErrors.mjs +0 -0
  85. /package/dist/esm/{submit → src/submit}/useFormOnSubmitSuccessful.mjs +0 -0
  86. /package/dist/esm/{submit → src/submit}/useFormOnSubmitSuccessfulAndReset.mjs +0 -0
  87. /package/dist/esm/{submit → src/submit}/useResetFormOnSubmitError.mjs +0 -0
  88. /package/dist/esm/{submit → src/submit}/useResetFormOnSubmitSuccessful.mjs +0 -0
  89. /package/dist/esm/{submit → src/submit}/useSubmitFormOnChange.mjs +0 -0
  90. /package/dist/esm/{utils → src/utils}/createContext.mjs +0 -0
  91. /package/dist/esm/{utils → src/utils}/isEmptyObject.mjs +0 -0
package/README.md CHANGED
@@ -16,20 +16,21 @@ To configure, create a file like `src/integrations/paragrav-rhf-utils/config.tsx
16
16
  export const config: RhfUtilsClientConfig = {
17
17
  isDevelopment: import.meta.env.DEV,
18
18
 
19
- defaultOptions: {
20
- // UseFormProps
19
+ defaults: {
20
+ // globally relevant subset of RHF's `UseFormProps` options
21
21
  rhf: {
22
22
  mode: 'onBlur',
23
23
  },
24
24
 
25
- // UseFormOptions
26
- form: {
25
+ // RhfUtilsFormOptions (see further below)
26
+ utils: {
27
27
  devTool: {
28
28
  placement: 'top-right',
29
29
  },
30
30
  },
31
31
  },
32
32
 
33
+ // optional (defaults to primitive HTML form)
33
34
  FormComponent: Form.Root,
34
35
 
35
36
  // transform backend error
@@ -46,7 +47,13 @@ export const config: RhfUtilsClientConfig = {
46
47
 
47
48
  Children: {
48
49
  top: (
49
- { options }, // UseFormFieldsProps
50
+ {
51
+ formId, // unique id string
52
+ formRef, // ref
53
+ context, // rhf UseFormReturn
54
+ options, // RhfUtilsFormOptions
55
+ Controller, // strongly-typed controller
56
+ }, // UseFormFieldsProps
50
57
  ) => {
51
58
  // navigation blocker (using custom option)
52
59
  useFormRouterBlocker(!!options?.prompter);
@@ -61,6 +68,18 @@ export const config: RhfUtilsClientConfig = {
61
68
  </>
62
69
  ),
63
70
  },
71
+
72
+ errors: {
73
+ output: {
74
+ // callback to determine when to output form context errors to console ("debug" or "error")
75
+ console: ({ isDevelopment, hasOrphans }) =>
76
+ (hasOrphans && { type: 'error' }) || // report orphan errors early
77
+ (isDevelopment && { type: 'debug' }), // facilitate debugging on dev
78
+
79
+ // callback to determine when to throw an error based on context
80
+ throw: ({ isDevelopment, hasOrphans }) => isDevelopment && hasOrphans,
81
+ },
82
+ },
64
83
  };
65
84
  ```
66
85
 
@@ -96,13 +115,15 @@ And add the context provider to your stack:
96
115
  onError(error);
97
116
  }}
98
117
  // fields
99
- Fields={({
100
- formId, // unique id string
101
- formRef, // ref
102
- context, // rhf UseFormReturn
103
- options, // UseFormOptions
104
- Controller, // strongly-typed controlled
105
- }) => (
118
+ Fields={(
119
+ {
120
+ formId, // unique id string
121
+ formRef, // ref
122
+ context, // rhf UseFormReturn
123
+ options, // RhfUtilsFormOptions
124
+ Controller, // strongly-typed controller
125
+ }, // UseFormFieldsProps
126
+ ) => (
106
127
  <>
107
128
  <Controller
108
129
  name="email" // strongly-typed field name
@@ -125,16 +146,47 @@ And add the context provider to your stack:
125
146
 
126
147
  `Fields` is a component which is rendered as a child of the form. It receives `UseFormFieldsProps` as props, including type-safe `Controller`.
127
148
 
128
- ## Extend Options
149
+ ## `RhfUtilsFormOptions`
150
+
151
+ These options can be set globally and/or per form.
152
+
153
+ ```ts
154
+ type RhfUtilsFormOptions = {
155
+ /**
156
+ * Control visibility of certain items via your own classes and styles.
157
+ * (Defaults merged with individual class names.)
158
+ */
159
+ classNames?: string[];
160
+
161
+ /** Request submit via listener on form change. */
162
+ submitOnChange?: boolean;
163
+
164
+ /** Reset form values if submit throw errors. (Use case: optimistic UI toggle form that submits on each change.) */
165
+ resetValuesOnSubmitError?: boolean;
166
+
167
+ /** Stop propagation of submit event. Useful for portals. */
168
+ stopSubmitPropagation?: boolean;
169
+
170
+ /** Reset form after successful submit. */
171
+ resetFormAfterSubmitSuccessful?: Parameters<
172
+ typeof useResetFormAfterSubmitSuccessful
173
+ >[0];
174
+
175
+ /** Control dev tool options. */
176
+ devTool?: Pick<DevtoolUIProps, 'placement' | 'styles'> | 'disabled';
177
+ };
178
+ ```
179
+
180
+ ## Extend `RhfUtilsFormOptions`
129
181
 
130
- Extend `UseFormOptions` with custom options, which get passed to `Fields` component in `options` prop.
182
+ Extend `RhfUtilsFormOptions` with custom options, which get passed to `Fields` component in `options` prop.
131
183
 
132
184
  ```tsx
133
185
  import '@paragrav/rhf-utils';
134
186
 
135
187
  declare module '@paragrav/rhf-utils' {
136
188
  export interface Register {
137
- UseFormOptions: {
189
+ RhfUtilsFormOptions: {
138
190
  /** Enable user prompt to confirm navigating away from dirty form. */
139
191
  prompter?: boolean;
140
192
  };
@@ -0,0 +1,55 @@
1
+ import { jsx as h } from "react/jsx-runtime";
2
+ import F from "../form/FormWithProviders.mjs";
3
+ import f from "../form/useForm.mjs";
4
+ const W = (e) => (r) => {
5
+ const m = d(
6
+ e,
7
+ r
8
+ );
9
+ return {
10
+ useForm: (i, s) => {
11
+ const t = m(i, s);
12
+ return {
13
+ ...f(t),
14
+ FormWithProviders: ({
15
+ children: o
16
+ }) => /* @__PURE__ */ h(F, { ...t, children: o })
17
+ };
18
+ },
19
+ FormWithProviders: a(e, r)
20
+ };
21
+ }, d = (e, r) => function(i, s) {
22
+ var t, o, n, u, l;
23
+ return {
24
+ ...s,
25
+ rhf: {
26
+ ...(t = r.defaults) == null ? void 0 : t.rhf,
27
+ ...s.rhf,
28
+ resolver: e(i)
29
+ },
30
+ utils: {
31
+ ...(o = r.defaults) == null ? void 0 : o.utils,
32
+ ...s.utils,
33
+ classNames: [
34
+ ...((u = (n = r.defaults) == null ? void 0 : n.utils) == null ? void 0 : u.classNames) ?? [],
35
+ ...((l = s.utils) == null ? void 0 : l.classNames) ?? []
36
+ ]
37
+ }
38
+ };
39
+ }, a = (e, r) => function({
40
+ schema: i,
41
+ children: s,
42
+ ...t
43
+ }) {
44
+ const o = d(e, r);
45
+ return /* @__PURE__ */ h(
46
+ F,
47
+ {
48
+ ...o(i, t),
49
+ children: s
50
+ }
51
+ );
52
+ };
53
+ export {
54
+ W as createRhfUtilsClient
55
+ };
@@ -0,0 +1,30 @@
1
+ import h from "react";
2
+ import { useFormContext as E } from "react-hook-form";
3
+ import F from "../../client/config/useRhfUtilsClientConfigContext.mjs";
4
+ import i from "../../utils/isEmptyObject.mjs";
5
+ import x from "../output/consoleErrors.mjs";
6
+ import C from "./context/useFlatFieldErrorsContext.mjs";
7
+ const D = () => {
8
+ const c = E(), t = F(), r = C();
9
+ h.useEffect(() => {
10
+ var p, o, l, u, e, a;
11
+ if (i(r.all))
12
+ return;
13
+ const n = {
14
+ isDevelopment: t == null ? void 0 : t.isDevelopment,
15
+ hasOrphans: !i(r.orphans)
16
+ }, s = (l = (o = (p = t == null ? void 0 : t.errors) == null ? void 0 : p.output) == null ? void 0 : o.console) == null ? void 0 : l.call(o, n);
17
+ s && x(
18
+ s.message ?? f,
19
+ c.getValues(),
20
+ r,
21
+ s.type
22
+ );
23
+ const m = (a = (e = (u = t == null ? void 0 : t.errors) == null ? void 0 : u.output) == null ? void 0 : e.throw) == null ? void 0 : a.call(e, n);
24
+ if (m)
25
+ throw new Error(typeof m == "string" ? m : f);
26
+ }, [r]);
27
+ }, f = "Form errors";
28
+ export {
29
+ D as default
30
+ };
@@ -0,0 +1,7 @@
1
+ import { TRPCClientError as o } from "../../../node_modules/.pnpm/@trpc_client@11.0.0-rc.390_@trpc_server@11.0.0-rc.390/node_modules/@trpc/client/dist/TRPCClientError.mjs";
2
+ import "../../../node_modules/.pnpm/@trpc_server@11.0.0-rc.390/node_modules/@trpc/server/dist/unstable-core-do-not-import/rootConfig.mjs";
3
+ import { trpcClientErrorToFormSubmitErrorsSchemaTransformer as n } from "./trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs";
4
+ const p = (t) => (r) => r instanceof o ? n.parse(r) : t(r);
5
+ export {
6
+ p as getOnSubmitTrpcClientErrorHandler
7
+ };
@@ -0,0 +1,35 @@
1
+ import { TRPCClientError as e } from "../../../node_modules/.pnpm/@trpc_client@11.0.0-rc.390_@trpc_server@11.0.0-rc.390/node_modules/@trpc/client/dist/TRPCClientError.mjs";
2
+ import "../../../node_modules/.pnpm/@trpc_server@11.0.0-rc.390/node_modules/@trpc/server/dist/unstable-core-do-not-import/rootConfig.mjs";
3
+ import { z as o } from "zod";
4
+ import { trpcClientErrorMessageSchema as m } from "./trpcClientErrorMessageSchema.mjs";
5
+ const p = o.custom(
6
+ (r) => r instanceof e
7
+ // check instance type
8
+ ).transform((r) => r.message).transform((r) => {
9
+ try {
10
+ return JSON.parse(r);
11
+ } catch {
12
+ return [
13
+ {
14
+ validation: "root",
15
+ code: "server",
16
+ message: r,
17
+ path: ["root"]
18
+ }
19
+ ];
20
+ }
21
+ }).pipe(o.array(m)).transform(
22
+ (r) => r.map(
23
+ (t) => [
24
+ t.path.join("."),
25
+ // flatten path (e.g., "street.name")
26
+ {
27
+ type: t.code,
28
+ message: t.message
29
+ }
30
+ ]
31
+ )
32
+ ).transform((r) => Object.fromEntries(r));
33
+ export {
34
+ p as trpcClientErrorToFormSubmitErrorsSchemaTransformer
35
+ };
@@ -0,0 +1,91 @@
1
+ import { jsxs as F, jsx as d } from "react/jsx-runtime";
2
+ import "react";
3
+ import { useFormContext as _ } from "react-hook-form";
4
+ import j from "../client/config/useRhfUtilsClientConfigContext.mjs";
5
+ import D from "../devtool/LazyDevTool.mjs";
6
+ import { FormSubmitError as N } from "../submit/error/FormSubmitError.mjs";
7
+ import P from "../submit/error/setCtxErrorsByFormSubmitErrors.mjs";
8
+ import S from "./_Controller.mjs";
9
+ import T from "./_FormBase.mjs";
10
+ function A({
11
+ formId: x,
12
+ formRef: c,
13
+ //
14
+ onSubmit: p,
15
+ onSubmitError: s,
16
+ onSubmitInvalid: y,
17
+ Fields: C,
18
+ //
19
+ form: m,
20
+ utils: o,
21
+ //
22
+ children: f
23
+ }) {
24
+ const a = _(), e = j(), b = async (r) => {
25
+ o != null && o.stopSubmitPropagation && r.stopPropagation();
26
+ try {
27
+ await a.handleSubmit(v, y)(r);
28
+ } catch (t) {
29
+ B(t, r);
30
+ }
31
+ }, v = (r, t) => p == null ? void 0 : p(
32
+ r,
33
+ a,
34
+ t
35
+ ), B = (r, t) => {
36
+ var i;
37
+ const n = r instanceof N ? (
38
+ // consumer can manually throw FormSubmitError (e.g., manual validation)
39
+ r.errors
40
+ ) : (
41
+ // if error is not FormSubmitError, consumer can provide global handler
42
+ (i = e == null ? void 0 : e.onSubmitError) == null ? void 0 : i.call(e, r)
43
+ );
44
+ n && P(a, n), s == null || s(
45
+ r,
46
+ a,
47
+ t
48
+ );
49
+ }, h = {
50
+ formId: x,
51
+ formRef: c,
52
+ context: a,
53
+ utils: o,
54
+ Controller: S
55
+ }, l = (r) => {
56
+ var n;
57
+ const t = (n = e == null ? void 0 : e.Children) == null ? void 0 : n[r];
58
+ return t && /* @__PURE__ */ d(t, { ...h });
59
+ };
60
+ return /* @__PURE__ */ F(
61
+ T,
62
+ {
63
+ noValidate: !0,
64
+ style: {
65
+ position: "relative"
66
+ },
67
+ config: e,
68
+ formRef: c,
69
+ ...m,
70
+ className: [o == null ? void 0 : o.classNames, m == null ? void 0 : m.className].filter(Boolean).join(" "),
71
+ onSubmit: b,
72
+ children: [
73
+ l("top"),
74
+ (o == null ? void 0 : o.devTool) !== "disabled" && /* @__PURE__ */ d(
75
+ D,
76
+ {
77
+ placement: "top-right",
78
+ isDevelopment: e == null ? void 0 : e.isDevelopment,
79
+ ...o == null ? void 0 : o.devTool
80
+ }
81
+ ),
82
+ C && /* @__PURE__ */ d(C, { ...h }),
83
+ f,
84
+ l("bottom")
85
+ ]
86
+ }
87
+ );
88
+ }
89
+ export {
90
+ A as default
91
+ };
@@ -6,7 +6,7 @@ function v({
6
6
  formId: t,
7
7
  formRef: o,
8
8
  rhfForm: i,
9
- options: e,
9
+ utils: e,
10
10
  children: m
11
11
  }) {
12
12
  return /* @__PURE__ */ r(d, { ...i, children: /* @__PURE__ */ r(n, { formRef: o, children: /* @__PURE__ */ r(
@@ -0,0 +1,43 @@
1
+ import e from "react";
2
+ import { useForm as i } from "react-hook-form";
3
+ import { FormSubmitError as F } from "../submit/error/FormSubmitError.mjs";
4
+ const a = ({
5
+ onSubmit: t,
6
+ onSubmitError: f,
7
+ onSubmitInvalid: n,
8
+ defaultValues: p,
9
+ Fields: c,
10
+ rhf: u,
11
+ form: d,
12
+ utils: s
13
+ }) => {
14
+ const o = e.useId(), m = i({
15
+ ...u,
16
+ defaultValues: p
17
+ }), r = e.useRef(null);
18
+ return {
19
+ id: o,
20
+ ref: r,
21
+ context: m,
22
+ providerProps: {
23
+ formId: o,
24
+ formRef: r,
25
+ rhfForm: m,
26
+ utils: s
27
+ },
28
+ formProps: {
29
+ Fields: c,
30
+ onSubmit: t,
31
+ onSubmitError: f,
32
+ onSubmitInvalid: n,
33
+ formId: o,
34
+ formRef: r,
35
+ form: d,
36
+ utils: s
37
+ },
38
+ FormSubmitError: F
39
+ };
40
+ }, I = a;
41
+ export {
42
+ I as default
43
+ };
@@ -1,10 +1,15 @@
1
1
  import { UseFormProps } from 'react-hook-form';
2
2
  import { RhfUtilsErrorsOutputConfigContext, RhfUtilsErrorsOutputConsoleConfig } from '../../errors/output/types';
3
3
  import { FormChildrenSlots } from '../../form/Form';
4
+ import { RhfUtilsFormOptions } from '../../form/RhfUtilsFormOptions';
4
5
  import { UseFormFieldsProps } from '../../form/useForm';
5
- import { UseFormOptions } from '../../form/useFormOptions';
6
6
  import { FormSubmitErrors } from '../../submit/error/FormSubmitErrors';
7
7
 
8
+ /**
9
+ * Client configuration object.
10
+ *
11
+ * Options under `defaults` can be overridden at form level.
12
+ */
8
13
  export type RhfUtilsClientConfig = {
9
14
  /**
10
15
  * Some behavior is dependent on environment.
@@ -13,7 +18,7 @@ export type RhfUtilsClientConfig = {
13
18
  /**
14
19
  * Default options for all forms. (Are overridden by form-specific options.)
15
20
  */
16
- defaultOptions?: {
21
+ defaults?: {
17
22
  /**
18
23
  * Default RHF `useForm` settings.
19
24
  *
@@ -25,7 +30,7 @@ export type RhfUtilsClientConfig = {
25
30
  *
26
31
  * Extend this type to inject custom options/functionality via `Children` component.
27
32
  */
28
- form?: UseFormOptions;
33
+ utils?: RhfUtilsFormOptions;
29
34
  };
30
35
  /**
31
36
  * Supply your own `<form>` component.
@@ -66,18 +71,14 @@ export type RhfUtilsClientConfig = {
66
71
  * - console.debug errors in development environment.
67
72
  * - console.error certain errors in production environment.
68
73
  */
69
- console?: {
70
- getConfig?: (context: RhfUtilsErrorsOutputConfigContext) => RhfUtilsErrorsOutputConsoleConfig | null;
71
- };
74
+ console?: (context: RhfUtilsErrorsOutputConfigContext) => RhfUtilsErrorsOutputConsoleConfig | null | false | undefined;
72
75
  /**
73
76
  * Configure how/if errors should be thrown.
74
77
  *
75
78
  * Example use case:
76
79
  * - bring attention to certain errors in development environment.
77
80
  */
78
- throw?: {
79
- getConfig?: (context: RhfUtilsErrorsOutputConfigContext) => true | string | false;
80
- };
81
+ throw?: (context: RhfUtilsErrorsOutputConfigContext) => true | string | false | undefined;
81
82
  };
82
83
  };
83
84
  };
@@ -21,10 +21,10 @@ export { trpcClientErrorToFormSubmitErrorsSchemaTransformer } from './errors/trp
21
21
  export { default as useFormErrorsEffect } from './errors/useFormErrorsEffect';
22
22
  export { default as useFormErrorsIfAny } from './errors/useFormErrorsIfAny';
23
23
  export { default as FormWithProviders } from './form/FormWithProviders';
24
+ export type { RhfUtilsFormOptions } from './form/RhfUtilsFormOptions';
24
25
  export type { SafeFieldValues } from './form/SafeFieldValues';
25
26
  export type { UseFormFieldsProps } from './form/useForm';
26
27
  export { default as useForm } from './form/useForm';
27
- export type { UseFormOptions } from './form/useFormOptions';
28
28
  export { default as useFormUtilsContext } from './form/context/utils/useFormUtilsContext';
29
29
  export { default as FormGroupContextProvider } from './form/context/group/FormGroupContextProvider';
30
30
  export { default as useFormGroupChildIsMountedTracker } from './form/context/group/useFormGroupChildIsMountedTracker';
@@ -6,6 +6,6 @@ export type FormChildrenSlots = 'top' | 'bottom';
6
6
  export type FormProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = React.PropsWithChildren<{
7
7
  formId: string;
8
8
  formRef: React.RefObject<HTMLFormElement>;
9
- } & Pick<UseFormProps<TFieldValues, TTransformedValues>, 'onSubmit' | 'onSubmitError' | 'onSubmitInvalid' | 'Fields' | 'form' | 'options'>>;
10
- declare function _Form<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, formRef, onSubmit, onSubmitError, onSubmitInvalid, Fields, form, options, children, }: FormProps<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
9
+ } & Pick<UseFormProps<TFieldValues, TTransformedValues>, 'onSubmit' | 'onSubmitError' | 'onSubmitInvalid' | 'Fields' | 'form' | 'utils'>>;
10
+ declare function _Form<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, formRef, onSubmit, onSubmitError, onSubmitInvalid, Fields, form, utils, children, }: FormProps<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
11
11
  export default _Form;
@@ -1,12 +1,12 @@
1
1
  import { UseFormReturn } from 'react-hook-form';
2
+ import { RhfUtilsFormOptions } from './RhfUtilsFormOptions';
2
3
  import { SafeFieldValues } from './SafeFieldValues';
3
- import { UseFormOptions } from './useFormOptions';
4
4
 
5
5
  export type FormProvidersProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = React.PropsWithChildren<{
6
6
  formId: string;
7
7
  formRef: React.RefObject<HTMLFormElement>;
8
8
  rhfForm: UseFormReturn<TFieldValues, unknown, TTransformedValues>;
9
- options?: UseFormOptions;
9
+ utils?: RhfUtilsFormOptions;
10
10
  }>;
11
- declare function FormProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, formRef, rhfForm, options, children, }: FormProvidersProps<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
11
+ declare function FormProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, formRef, rhfForm, utils, children, }: FormProvidersProps<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
12
12
  export default FormProviders;
@@ -0,0 +1,28 @@
1
+ import { DevtoolUIProps } from '@hookform/devtools/dist/devToolUI';
2
+ import { default as useResetFormAfterSubmitSuccessful } from '../submit/useResetFormOnSubmitSuccessful';
3
+ import { Register } from '../register';
4
+
5
+ /**
6
+ * Options for enabling utils functionality provided by this library.
7
+ *
8
+ * Can be extended using {@link Register.RhfUtilsFormOptions}.
9
+ */
10
+ export type RhfUtilsFormOptions = {
11
+ /**
12
+ * Control visibility of certain items via your own classes and styles.
13
+ * (Defaults merged with individual class names.)
14
+ */
15
+ classNames?: string[];
16
+ /** Request submit via listener on form change. */
17
+ submitOnChange?: boolean;
18
+ /** Reset form values if submit throw errors. (Use case: optimistic UI toggle form that submits on each change.) */
19
+ resetValuesOnSubmitError?: boolean;
20
+ /** Stop propagation of submit event. Useful for portals. */
21
+ stopSubmitPropagation?: boolean;
22
+ /** Reset form after successful submit. */
23
+ resetFormAfterSubmitSuccessful?: Parameters<typeof useResetFormAfterSubmitSuccessful>[0];
24
+ /** Control dev tool options. */
25
+ devTool?: Pick<DevtoolUIProps, 'placement' | 'styles'> | 'disabled';
26
+ } & (Register extends {
27
+ RhfUtilsFormOptions: infer _RhfUtilsFormOptions;
28
+ } ? _RhfUtilsFormOptions : {});
@@ -1,11 +1,11 @@
1
- import { UseFormOptions } from '../../useFormOptions';
1
+ import { RhfUtilsFormOptions } from '../../RhfUtilsFormOptions';
2
2
 
3
3
  type Props = React.PropsWithChildren<{
4
4
  formId: string;
5
5
  formRef: React.RefObject<HTMLFormElement>;
6
6
  /** Callback after successful submit, and form reset. */
7
7
  onSubmitSuccessfulAndReset?: () => void;
8
- options?: UseFormOptions;
8
+ options?: RhfUtilsFormOptions;
9
9
  }>;
10
10
  declare function FormUtilsContextProvider({ formId, formRef, onSubmitSuccessfulAndReset, options, children, }: Props): import("react/jsx-runtime").JSX.Element;
11
11
  export default FormUtilsContextProvider;
@@ -1,9 +1,9 @@
1
- import { UseFormOptions } from '../../useFormOptions';
1
+ import { RhfUtilsFormOptions } from '../../RhfUtilsFormOptions';
2
2
 
3
3
  export type FormUtilsContext = {
4
4
  formId: string;
5
5
  formRef: React.RefObject<HTMLFormElement>;
6
- options: UseFormOptions | undefined;
6
+ options: RhfUtilsFormOptions | undefined;
7
7
  /** Callback to trigger submit manually -- e.g., on change. */
8
8
  requestSubmit: HTMLFormElement['requestSubmit'];
9
9
  };
@@ -4,14 +4,14 @@ import { FormSubmitError } from '../submit/error/FormSubmitError';
4
4
  import { default as _Controller } from './_Controller';
5
5
  import { FormProps } from './Form';
6
6
  import { FormProvidersProps } from './FormProviders';
7
+ import { RhfUtilsFormOptions } from './RhfUtilsFormOptions';
7
8
  import { SafeFieldValues } from './SafeFieldValues';
8
- import { UseFormOptions } from './useFormOptions';
9
9
 
10
10
  export type UseFormFieldsProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = SafeFieldValues> = {
11
11
  formId: string;
12
12
  formRef: React.RefObject<HTMLFormElement>;
13
13
  context: RhfUseFormReturn<TFieldValues, unknown, TTransformedValues>;
14
- options?: UseFormOptions;
14
+ utils?: RhfUtilsFormOptions;
15
15
  Controller: typeof _Controller<TFieldValues>;
16
16
  };
17
17
  export type UseFormProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = {
@@ -26,7 +26,8 @@ export type UseFormProps<TFieldValues extends SafeFieldValues, TTransformedValue
26
26
  rhf?: Omit<RhfUseFormProps<TFieldValues>, 'defaultValues'>;
27
27
  /** {@link FormProps} props for Form. */
28
28
  form?: React.PropsWithoutRef<JSX.IntrinsicElements['form']>;
29
- options?: UseFormOptions;
29
+ /** {@link RhfUtilsFormOptions} to enabled utils functionality. */
30
+ utils?: RhfUtilsFormOptions;
30
31
  };
31
32
  export type UseFormReturn<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = {
32
33
  id: string;
@@ -45,6 +46,6 @@ export type UseFormReturn<TFieldValues extends SafeFieldValues, TTransformedValu
45
46
  * see https://caniuse.com/?search=form%20attribute
46
47
  * @returns Form provider and form.
47
48
  */
48
- declare const useForm: <TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ onSubmit, onSubmitError, onSubmitInvalid, defaultValues, Fields, rhf, form, options, }: UseFormProps<TFieldValues, TTransformedValues>) => UseFormReturn<TFieldValues, TTransformedValues>;
49
+ declare const useForm: <TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ onSubmit, onSubmitError, onSubmitInvalid, defaultValues, Fields, rhf, form, utils, }: UseFormProps<TFieldValues, TTransformedValues>) => UseFormReturn<TFieldValues, TTransformedValues>;
49
50
  export default useForm;
50
51
  export type UseForm<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = typeof useForm<TFieldValues, TTransformedValues>;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Use this to extend internal types.
3
3
  *
4
- * For example, `UseFormOptions`.
4
+ * For example, `RhfUtilsFormOptions`.
5
5
  */
6
6
  export interface Register {
7
+ RhfUtilsFormOptions?: never;
7
8
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@paragrav/rhf-utils",
3
3
  "author": "paragrav.dev",
4
4
  "license": "MIT",
5
- "version": "0.0.106",
5
+ "version": "0.0.108",
6
6
  "description": "Integration utilities for react-hook-form.",
7
7
  "type": "module",
8
8
  "sideEffects": false,
@@ -22,14 +22,16 @@
22
22
  "peerDependencies": {
23
23
  "@hookform/devtools": "4",
24
24
  "@hookform/resolvers": "3",
25
- "@trpc/client": "next",
26
- "@trpc/server": "next",
27
25
  "flat": "6",
28
26
  "react": "18",
29
27
  "react-dom": "18",
30
28
  "react-hook-form": "7",
31
29
  "zod": "3"
32
30
  },
31
+ "optionalDependencies": {
32
+ "@trpc/client": "next",
33
+ "@trpc/server": "next"
34
+ },
33
35
  "repository": {
34
36
  "type": "git",
35
37
  "url": "git+https://github.com/paragrav/rhf-utils.git"
@@ -1,55 +0,0 @@
1
- import { jsx as h } from "react/jsx-runtime";
2
- import F from "../form/FormWithProviders.mjs";
3
- import a from "../form/useForm.mjs";
4
- const v = (s) => (r) => {
5
- const i = d(
6
- s,
7
- r
8
- );
9
- return {
10
- useForm: (n, o) => {
11
- const t = i(n, o);
12
- return {
13
- ...a(t),
14
- FormWithProviders: ({
15
- children: e
16
- }) => /* @__PURE__ */ h(F, { ...t, children: e })
17
- };
18
- },
19
- FormWithProviders: l(s, r)
20
- };
21
- }, d = (s, r) => function(n, o) {
22
- var t, e, m, f, u;
23
- return {
24
- ...o,
25
- rhf: {
26
- ...(t = r.defaultOptions) == null ? void 0 : t.rhf,
27
- ...o.rhf,
28
- resolver: s(n)
29
- },
30
- options: {
31
- ...(e = r.defaultOptions) == null ? void 0 : e.form,
32
- ...o.options,
33
- classNames: [
34
- ...((f = (m = r.defaultOptions) == null ? void 0 : m.form) == null ? void 0 : f.classNames) ?? [],
35
- ...((u = o.options) == null ? void 0 : u.classNames) ?? []
36
- ]
37
- }
38
- };
39
- }, l = (s, r) => function({
40
- schema: n,
41
- children: o,
42
- ...t
43
- }) {
44
- const e = d(s, r);
45
- return /* @__PURE__ */ h(
46
- F,
47
- {
48
- ...e(n, t),
49
- children: o
50
- }
51
- );
52
- };
53
- export {
54
- v as createRhfUtilsClient
55
- };
@@ -1,24 +0,0 @@
1
- import { useFormContext as C } from "react-hook-form";
2
- import F from "../../client/config/useRhfUtilsClientConfigContext.mjs";
3
- import x from "../../utils/isEmptyObject.mjs";
4
- import E from "../output/consoleErrors.mjs";
5
- import d from "./context/useFlatFieldErrorsContext.mjs";
6
- const v = () => {
7
- var p, l, t, i, u, a, r, f;
8
- const h = C(), o = F(), n = d(), m = {
9
- isDevelopment: o == null ? void 0 : o.isDevelopment,
10
- hasOrphans: !x(n.orphans)
11
- }, e = (i = (t = (l = (p = o == null ? void 0 : o.errors) == null ? void 0 : p.output) == null ? void 0 : l.console) == null ? void 0 : t.getConfig) == null ? void 0 : i.call(t, m);
12
- e && E(
13
- e.message ?? c,
14
- h.getValues(),
15
- n,
16
- e.type
17
- );
18
- const s = (f = (r = (a = (u = o == null ? void 0 : o.errors) == null ? void 0 : u.output) == null ? void 0 : a.throw) == null ? void 0 : r.getConfig) == null ? void 0 : f.call(r, m);
19
- if (s)
20
- throw new Error(typeof s == "string" ? s : c);
21
- }, c = "Form errors";
22
- export {
23
- v as default
24
- };
@@ -1,6 +0,0 @@
1
- import { TRPCClientError as o } from "@trpc/client";
2
- import { trpcClientErrorToFormSubmitErrorsSchemaTransformer as n } from "./trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs";
3
- const m = (t) => (r) => r instanceof o ? n.parse(r) : t(r);
4
- export {
5
- m as getOnSubmitTrpcClientErrorHandler
6
- };
@@ -1,34 +0,0 @@
1
- import { TRPCClientError as o } from "@trpc/client";
2
- import { z as e } from "zod";
3
- import { trpcClientErrorMessageSchema as a } from "./trpcClientErrorMessageSchema.mjs";
4
- const i = e.custom(
5
- (r) => r instanceof o
6
- // check instance type
7
- ).transform((r) => r.message).transform((r) => {
8
- try {
9
- return JSON.parse(r);
10
- } catch {
11
- return [
12
- {
13
- validation: "root",
14
- code: "server",
15
- message: r,
16
- path: ["root"]
17
- }
18
- ];
19
- }
20
- }).pipe(e.array(a)).transform(
21
- (r) => r.map(
22
- (t) => [
23
- t.path.join("."),
24
- // flatten path (e.g., "street.name")
25
- {
26
- type: t.code,
27
- message: t.message
28
- }
29
- ]
30
- )
31
- ).transform((r) => Object.fromEntries(r));
32
- export {
33
- i as trpcClientErrorToFormSubmitErrorsSchemaTransformer
34
- };
@@ -1,91 +0,0 @@
1
- import { jsxs as F, jsx as c } from "react/jsx-runtime";
2
- import "react";
3
- import { useFormContext as _ } from "react-hook-form";
4
- import j from "../client/config/useRhfUtilsClientConfigContext.mjs";
5
- import D from "../devtool/LazyDevTool.mjs";
6
- import { FormSubmitError as N } from "../submit/error/FormSubmitError.mjs";
7
- import P from "../submit/error/setCtxErrorsByFormSubmitErrors.mjs";
8
- import S from "./_Controller.mjs";
9
- import T from "./_FormBase.mjs";
10
- function q({
11
- formId: x,
12
- formRef: C,
13
- //
14
- onSubmit: o,
15
- onSubmitError: d,
16
- onSubmitInvalid: y,
17
- Fields: h,
18
- //
19
- form: s,
20
- options: e,
21
- //
22
- children: f
23
- }) {
24
- const l = _(), r = j(), b = async (t) => {
25
- e != null && e.stopSubmitPropagation && t.stopPropagation();
26
- try {
27
- await l.handleSubmit(v, y)(t);
28
- } catch (a) {
29
- B(a, t);
30
- }
31
- }, v = (t, a) => o == null ? void 0 : o(
32
- t,
33
- l,
34
- a
35
- ), B = (t, a) => {
36
- var n;
37
- const m = t instanceof N ? (
38
- // consumer can manually throw FormSubmitError (e.g., manual validation)
39
- t.errors
40
- ) : (
41
- // if error is not FormSubmitError, consumer can provide global handler
42
- (n = r == null ? void 0 : r.onSubmitError) == null ? void 0 : n.call(r, t)
43
- );
44
- m && P(l, m), d == null || d(
45
- t,
46
- l,
47
- a
48
- );
49
- }, u = {
50
- formId: x,
51
- formRef: C,
52
- context: l,
53
- options: e,
54
- Controller: S
55
- }, i = (t) => {
56
- var m;
57
- const a = (m = r == null ? void 0 : r.Children) == null ? void 0 : m[t];
58
- return a && /* @__PURE__ */ c(a, { ...u });
59
- };
60
- return /* @__PURE__ */ F(
61
- T,
62
- {
63
- noValidate: !0,
64
- style: {
65
- position: "relative"
66
- },
67
- config: r,
68
- formRef: C,
69
- ...s,
70
- className: [e == null ? void 0 : e.classNames, s == null ? void 0 : s.className].filter(Boolean).join(" "),
71
- onSubmit: b,
72
- children: [
73
- i("top"),
74
- (e == null ? void 0 : e.devTool) !== "disabled" && /* @__PURE__ */ c(
75
- D,
76
- {
77
- placement: "top-right",
78
- isDevelopment: r == null ? void 0 : r.isDevelopment,
79
- ...e == null ? void 0 : e.devTool
80
- }
81
- ),
82
- h && /* @__PURE__ */ c(h, { ...u }),
83
- f,
84
- i("bottom")
85
- ]
86
- }
87
- );
88
- }
89
- export {
90
- q as default
91
- };
@@ -1,42 +0,0 @@
1
- import m from "react";
2
- import { useForm as d } from "react-hook-form";
3
- import { FormSubmitError as F } from "../submit/error/FormSubmitError.mjs";
4
- const a = ({
5
- onSubmit: t,
6
- onSubmitError: e,
7
- onSubmitInvalid: f,
8
- defaultValues: n,
9
- Fields: p,
10
- rhf: u,
11
- form: c,
12
- options: i
13
- }) => {
14
- const o = m.useId(), s = d({
15
- ...u,
16
- defaultValues: n
17
- }), r = m.useRef(null);
18
- return {
19
- id: o,
20
- ref: r,
21
- context: s,
22
- providerProps: {
23
- formId: o,
24
- formRef: r,
25
- rhfForm: s,
26
- options: i
27
- },
28
- formProps: {
29
- Fields: p,
30
- onSubmit: t,
31
- onSubmitError: e,
32
- onSubmitInvalid: f,
33
- formId: o,
34
- formRef: r,
35
- form: c
36
- },
37
- FormSubmitError: F
38
- };
39
- }, I = a;
40
- export {
41
- I as default
42
- };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes