@paragrav/rhf-utils 0.0.135 → 0.0.137

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 (163) hide show
  1. package/README.md +90 -65
  2. package/dist/esm/client/config/useRhfUtilsClientConfigContext.mjs +0 -1
  3. package/dist/esm/client/index.mjs +0 -1
  4. package/dist/esm/client/utils.mjs +0 -1
  5. package/dist/esm/client/zod/context/RhfUtilsClientForZodContextProvider.mjs +3 -2
  6. package/dist/esm/client/zod/context/RhfUtilsZodForm.mjs +0 -1
  7. package/dist/esm/client/zod/context/useRhfUtilsClientForZodContext.mjs +0 -1
  8. package/dist/esm/client/zod/context/useRhfUtilsZodForm.mjs +0 -1
  9. package/dist/esm/client/zod/createRhfUtilsClientForZod.mjs +0 -1
  10. package/dist/esm/devtool/LazyDevTool.mjs +0 -1
  11. package/dist/esm/errors/flat/FlatFieldErrorsList.mjs +0 -1
  12. package/dist/esm/errors/flat/context/FlatFieldErrorsContextProvider.mjs +0 -1
  13. package/dist/esm/errors/flat/context/useFlatFieldErrorsContext.mjs +0 -1
  14. package/dist/esm/errors/flat/context/useFlatFieldErrorsContextHasOnlyOrphans.mjs +0 -1
  15. package/dist/esm/errors/flat/context/useFlatFieldErrorsContextOutput.mjs +0 -1
  16. package/dist/esm/errors/flat/filterFlatFieldErrors.mjs +0 -1
  17. package/dist/esm/errors/flat/flattenFieldErrors.mjs +0 -1
  18. package/dist/esm/errors/flat/getFlatFieldErrors.mjs +10 -11
  19. package/dist/esm/errors/getRefdFromFlatFieldErrors.mjs +0 -1
  20. package/dist/esm/errors/isFieldErrorRefd.mjs +0 -1
  21. package/dist/esm/errors/isFlatFieldErrorEntryRefd.mjs +0 -1
  22. package/dist/esm/errors/message/FormErrorMessage.mjs +0 -1
  23. package/dist/esm/errors/message/RhfUtilsFieldErrorMessage.mjs +14 -0
  24. package/dist/esm/errors/nonfield/FormNonFieldErrorMarker.mjs +0 -1
  25. package/dist/esm/errors/nonfield/FormNonFieldErrorMarker.utils.mjs +0 -1
  26. package/dist/esm/errors/nonfield/FormNonFieldErrorMarkerHtmlAttribute.mjs +0 -1
  27. package/dist/esm/errors/nonfield/isNonFieldErrorMarkerInDOM.mjs +0 -1
  28. package/dist/esm/errors/orphan/getIsOrphanFormErrorWithParentElement.mjs +0 -1
  29. package/dist/esm/errors/orphan/getOrphansFromFlatFieldErrors.mjs +0 -1
  30. package/dist/esm/errors/orphan/isOrphanFormError.mjs +3 -4
  31. package/dist/esm/errors/output/consoleErrors.mjs +0 -1
  32. package/dist/esm/errors/root/RootErrorsListFromFlatFieldErrorsContext.mjs +0 -1
  33. package/dist/esm/errors/root/consts.mjs +0 -1
  34. package/dist/esm/errors/root/getRootsFromFlatFieldErrors.mjs +0 -1
  35. package/dist/esm/errors/root/isFlatFieldErrorEntryPathRoot.mjs +0 -1
  36. package/dist/esm/errors/root/isFormErrorPathRoot.mjs +0 -1
  37. package/dist/esm/exports.mjs +32 -37
  38. package/dist/esm/form/Form.mjs +14 -15
  39. package/dist/esm/form/FormWithProviders.mjs +0 -1
  40. package/dist/esm/form/RhfUtilsFormProviders.mjs +0 -1
  41. package/dist/esm/form/_Controller.mjs +0 -1
  42. package/dist/esm/form/context/group/FormGroupContextProvider.mjs +0 -1
  43. package/dist/esm/form/context/group/index.mjs +0 -1
  44. package/dist/esm/form/context/group/useFormGroupChildIsMountedTracker.mjs +0 -1
  45. package/dist/esm/form/context/group/useFormGroupChildIsSubmittingTracker.mjs +0 -1
  46. package/dist/esm/form/context/group/useFormGroupChildTracker.mjs +0 -1
  47. package/dist/esm/form/context/group/useFormGroupIsAnyBusy.mjs +0 -1
  48. package/dist/esm/form/context/group/useFormGroupIsChildBusy.mjs +0 -1
  49. package/dist/esm/form/context/group/useFormGroupIsParentBusy.mjs +0 -1
  50. package/dist/esm/form/context/group/useFormGroupParentTracker.mjs +0 -1
  51. package/dist/esm/form/context/group/useFormOrParentIsBusy.mjs +0 -1
  52. package/dist/esm/form/context/utils/RhfUtilsContextProvider.mjs +15 -14
  53. package/dist/esm/form/context/utils/useRhfUtilsContext.mjs +0 -1
  54. package/dist/esm/form/context/utils/useRhfUtilsContextRequestSubmit.mjs +0 -1
  55. package/dist/esm/form/useFormIsBusy.mjs +0 -1
  56. package/dist/esm/form/useRhfUtilsForm.mjs +0 -1
  57. package/dist/esm/form/utils/getSubmitterButtonData.mjs +0 -1
  58. package/dist/esm/form/utils/useFormRequestSubmit.mjs +9 -6
  59. package/dist/esm/submit/error/FormSubmitError.mjs +0 -1
  60. package/dist/esm/submit/error/setCtxErrorsByFormSubmitFieldErrors.mjs +12 -0
  61. package/dist/esm/submit/useFormOnSubmitted.mjs +0 -1
  62. package/dist/esm/submit/useResetFormOnSubmitted.mjs +0 -1
  63. package/dist/esm/submit/useSubmitFormOnChange.mjs +18 -12
  64. package/dist/esm/utils/PassthroughChildren.mjs +0 -1
  65. package/dist/esm/utils/createContext.mjs +0 -1
  66. package/dist/esm/utils/isEmptyObject.mjs +0 -1
  67. package/dist/esm/utils/useDebouncedOnChangeValue.mjs +26 -0
  68. package/dist/esm/utils/useRefIfValueWasTrue.mjs +0 -1
  69. package/dist/types/client/config/RhfUtilsClientConfig.d.ts +5 -5
  70. package/dist/types/client/zod/context/RhfUtilsClientForZodContextProvider.d.ts +1 -1
  71. package/dist/types/errors/flat/flattenFieldErrors.d.ts +3 -2
  72. package/dist/types/errors/message/{FormErrorMessageByPath.d.ts → RhfUtilsFieldErrorMessage.d.ts} +2 -2
  73. package/dist/types/errors/trpc/getOnSubmitTrpcClientErrorHandler.d.ts +2 -2
  74. package/dist/types/errors/trpc/trpcClientErrorToFormSubmitFieldErrorsSchemaTransformer.d.ts +28 -0
  75. package/dist/types/exports.d.ts +1 -3
  76. package/dist/types/form/RhfUtilsFormOptions.d.ts +7 -3
  77. package/dist/types/form/UseRhfUtilsFormProps.d.ts +1 -1
  78. package/dist/types/form/utils/useFormRequestSubmit.d.ts +5 -0
  79. package/dist/types/submit/error/FormSubmitError.d.ts +3 -3
  80. package/dist/types/submit/error/{FormSubmitErrors.d.ts → FormSubmitFieldErrors.d.ts} +1 -1
  81. package/dist/types/submit/error/setCtxErrorsByFormSubmitFieldErrors.d.ts +10 -0
  82. package/dist/types/submit/useFormOnSubmitSuccessfulAndReset.d.ts +1 -1
  83. package/dist/types/submit/useFormOnSubmitted.d.ts +1 -1
  84. package/dist/types/submit/useSubmitFormOnChange.d.ts +3 -1
  85. package/dist/types/utils/timeoutAsync.d.ts +6 -0
  86. package/dist/types/utils/useDebouncedOnChangeValue.d.ts +14 -0
  87. package/package.json +1 -1
  88. package/dist/esm/client/config/useRhfUtilsClientConfigContext.mjs.map +0 -1
  89. package/dist/esm/client/index.mjs.map +0 -1
  90. package/dist/esm/client/utils.mjs.map +0 -1
  91. package/dist/esm/client/zod/context/RhfUtilsClientForZodContextProvider.mjs.map +0 -1
  92. package/dist/esm/client/zod/context/RhfUtilsZodForm.mjs.map +0 -1
  93. package/dist/esm/client/zod/context/useRhfUtilsClientForZodContext.mjs.map +0 -1
  94. package/dist/esm/client/zod/context/useRhfUtilsZodForm.mjs.map +0 -1
  95. package/dist/esm/client/zod/createRhfUtilsClientForZod.mjs.map +0 -1
  96. package/dist/esm/devtool/LazyDevTool.mjs.map +0 -1
  97. package/dist/esm/errors/flat/FlatFieldErrorsList.mjs.map +0 -1
  98. package/dist/esm/errors/flat/context/FlatFieldErrorsContextProvider.mjs.map +0 -1
  99. package/dist/esm/errors/flat/context/useFlatFieldErrorsContext.mjs.map +0 -1
  100. package/dist/esm/errors/flat/context/useFlatFieldErrorsContextHasOnlyOrphans.mjs.map +0 -1
  101. package/dist/esm/errors/flat/context/useFlatFieldErrorsContextOutput.mjs.map +0 -1
  102. package/dist/esm/errors/flat/filterFlatFieldErrors.mjs.map +0 -1
  103. package/dist/esm/errors/flat/flattenFieldErrors.mjs.map +0 -1
  104. package/dist/esm/errors/flat/getFlatFieldErrors.mjs.map +0 -1
  105. package/dist/esm/errors/getRefdFromFlatFieldErrors.mjs.map +0 -1
  106. package/dist/esm/errors/isFieldErrorRefd.mjs.map +0 -1
  107. package/dist/esm/errors/isFlatFieldErrorEntryRefd.mjs.map +0 -1
  108. package/dist/esm/errors/message/FormErrorMessage.mjs.map +0 -1
  109. package/dist/esm/errors/message/FormErrorMessageByPath.mjs +0 -15
  110. package/dist/esm/errors/message/FormErrorMessageByPath.mjs.map +0 -1
  111. package/dist/esm/errors/nonfield/FormNonFieldErrorMarker.mjs.map +0 -1
  112. package/dist/esm/errors/nonfield/FormNonFieldErrorMarker.utils.mjs.map +0 -1
  113. package/dist/esm/errors/nonfield/FormNonFieldErrorMarkerHtmlAttribute.mjs.map +0 -1
  114. package/dist/esm/errors/nonfield/isNonFieldErrorMarkerInDOM.mjs.map +0 -1
  115. package/dist/esm/errors/orphan/getIsOrphanFormErrorWithParentElement.mjs.map +0 -1
  116. package/dist/esm/errors/orphan/getOrphansFromFlatFieldErrors.mjs.map +0 -1
  117. package/dist/esm/errors/orphan/isOrphanFormError.mjs.map +0 -1
  118. package/dist/esm/errors/output/consoleErrors.mjs.map +0 -1
  119. package/dist/esm/errors/root/RootErrorsListFromFlatFieldErrorsContext.mjs.map +0 -1
  120. package/dist/esm/errors/root/consts.mjs.map +0 -1
  121. package/dist/esm/errors/root/getRootsFromFlatFieldErrors.mjs.map +0 -1
  122. package/dist/esm/errors/root/isFlatFieldErrorEntryPathRoot.mjs.map +0 -1
  123. package/dist/esm/errors/root/isFormErrorPathRoot.mjs.map +0 -1
  124. package/dist/esm/errors/trpc/getOnSubmitTrpcClientErrorHandler.mjs +0 -7
  125. package/dist/esm/errors/trpc/getOnSubmitTrpcClientErrorHandler.mjs.map +0 -1
  126. package/dist/esm/errors/trpc/trpcClientErrorMessageSchema.mjs +0 -11
  127. package/dist/esm/errors/trpc/trpcClientErrorMessageSchema.mjs.map +0 -1
  128. package/dist/esm/errors/trpc/trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs +0 -35
  129. package/dist/esm/errors/trpc/trpcClientErrorToFormSubmitErrorsSchemaTransformer.mjs.map +0 -1
  130. package/dist/esm/exports.mjs.map +0 -1
  131. package/dist/esm/form/Form.mjs.map +0 -1
  132. package/dist/esm/form/FormWithProviders.mjs.map +0 -1
  133. package/dist/esm/form/RhfUtilsFormProviders.mjs.map +0 -1
  134. package/dist/esm/form/_Controller.mjs.map +0 -1
  135. package/dist/esm/form/context/group/FormGroupContextProvider.mjs.map +0 -1
  136. package/dist/esm/form/context/group/index.mjs.map +0 -1
  137. package/dist/esm/form/context/group/useFormGroupChildIsMountedTracker.mjs.map +0 -1
  138. package/dist/esm/form/context/group/useFormGroupChildIsSubmittingTracker.mjs.map +0 -1
  139. package/dist/esm/form/context/group/useFormGroupChildTracker.mjs.map +0 -1
  140. package/dist/esm/form/context/group/useFormGroupIsAnyBusy.mjs.map +0 -1
  141. package/dist/esm/form/context/group/useFormGroupIsChildBusy.mjs.map +0 -1
  142. package/dist/esm/form/context/group/useFormGroupIsParentBusy.mjs.map +0 -1
  143. package/dist/esm/form/context/group/useFormGroupParentTracker.mjs.map +0 -1
  144. package/dist/esm/form/context/group/useFormOrParentIsBusy.mjs.map +0 -1
  145. package/dist/esm/form/context/utils/RhfUtilsContextProvider.mjs.map +0 -1
  146. package/dist/esm/form/context/utils/useRhfUtilsContext.mjs.map +0 -1
  147. package/dist/esm/form/context/utils/useRhfUtilsContextRequestSubmit.mjs.map +0 -1
  148. package/dist/esm/form/useFormIsBusy.mjs.map +0 -1
  149. package/dist/esm/form/useRhfUtilsForm.mjs.map +0 -1
  150. package/dist/esm/form/utils/getSubmitterButtonData.mjs.map +0 -1
  151. package/dist/esm/form/utils/useFormRequestSubmit.mjs.map +0 -1
  152. package/dist/esm/submit/error/FormSubmitError.mjs.map +0 -1
  153. package/dist/esm/submit/error/setCtxErrorsByFormSubmitErrors.mjs +0 -13
  154. package/dist/esm/submit/error/setCtxErrorsByFormSubmitErrors.mjs.map +0 -1
  155. package/dist/esm/submit/useFormOnSubmitted.mjs.map +0 -1
  156. package/dist/esm/submit/useResetFormOnSubmitted.mjs.map +0 -1
  157. package/dist/esm/submit/useSubmitFormOnChange.mjs.map +0 -1
  158. package/dist/esm/utils/PassthroughChildren.mjs.map +0 -1
  159. package/dist/esm/utils/createContext.mjs.map +0 -1
  160. package/dist/esm/utils/isEmptyObject.mjs.map +0 -1
  161. package/dist/esm/utils/useRefIfValueWasTrue.mjs.map +0 -1
  162. package/dist/types/errors/trpc/trpcClientErrorToFormSubmitErrorsSchemaTransformer.d.ts +0 -28
  163. package/dist/types/submit/error/setCtxErrorsByFormSubmitErrors.d.ts +0 -10
package/README.md CHANGED
@@ -2,29 +2,30 @@
2
2
 
3
3
  ## About
4
4
 
5
- Integration and utility library for [react-hook-form](https://www.react-hook-form.com/).
6
-
7
- If you have multiple forms and would like a more declarative API to manage their behavior via global and form-level options, including transformation of backend errors, and debugging field errors.
5
+ Integration and utility library for [react-hook-form](https://www.react-hook-form.com/) and [zod](https://www.npmjs.com/package/zod). Declaratively configure your forms via global and form-level options.
8
6
 
9
7
  ## Features
10
8
 
11
- - built with and for [TypeScript](https://www.typescriptlang.org/)
12
- - global configuration, such as:
13
- - injecting your own hooks and UI (`FormChildrenWrapper`)
9
+ - TypeScript-first
10
+ - global configuration (`RhfUtilsClientConfig`)
11
+ - RHF (`UseFormProps`) and utilities (`RhfUtilsFormOptions`) options defaults
12
+ - inject your own hooks and UI (`FormChildrenWrapper`)
14
13
  - server error transformation (`onSubmitErrorUnknown`)
15
- - FieldErrors logging/throwing (`RhfUtilsClientConfig.FieldErrors`)
16
- - extendable options type (`RhfUtilsFormOptions`)
17
- - form-specific overrides
18
- - schema-typed Controller component
19
- - schema-typed FormSubmitError class
20
- - throw in submit handler to add errors to RHF context and fail submit
14
+ - RHF `FormState.errors` logging/throwing (`RhfUtilsClientConfig.fieldErrors`)
15
+ - form-level configuration (`RhfUtilsZodForm`)
16
+ - RHF and utilities options overrides
17
+ - extendable utilities options type (`RhfUtilsFormOptions`)
18
+ - throw error (`FormSubmitError`) in submit handler to add errors to RHF context and fail submit
19
+ - handle submit error (`onSubmitError`)
20
+ - dependency injection for children (`RhfUtilsZodForm.Children`), including:
21
+ - formId, formRef, RHF context, utilities options
22
+ - schema-typed Controller component and FormSubmitError class
21
23
  - simpler/flatter `FieldErrors` structure (`FlatFieldErrors`)
22
24
  - context groups errors into `all`, `fields`, `roots`, and `orphans` (`useFlatFieldErrorsContext`)
23
- - `FormErrorMessageByPath` for displaying error message
24
- - `zod` support
25
- - including input/output types for transformations
25
+ - `RhfUtilsFieldErrorMessage` for displaying error message
26
26
  - safer `FieldValues` type (`SafeFieldValues`)
27
- - 3.3kB min+gzip core functionality (excluding [peer dependencies](#peer-dependencies))
27
+ - `zod` support, including input/output types for transformations
28
+ - ~3.9kB min+gzip (excluding [peer dependencies](#peer-dependencies))
28
29
 
29
30
  ## Install
30
31
 
@@ -34,9 +35,15 @@ pnpm install @paragrav/rhf-utils # pnpm
34
35
  yarn add @paragrav/rhf-utils # yarn
35
36
  ```
36
37
 
38
+ ## Quick Start
39
+
40
+ - 🔗 [Config](#config) (`RhfUtilsClientConfig`): define your desired global config (optional)
41
+ - 🔗 [Provider](#provider) (`RhfUtilsClientForZodContextProvider`): add to your global stack
42
+ - 🔗 [Form](#form) (`RhfUtilsZodForm`): use for your forms
43
+
37
44
  ## Config
38
45
 
39
- To configure, create a file like `config.tsx` with desired configuration settings. This is global configuration across all forms, some of which can be overridden at the form level.
46
+ Create a config (`RhfUtilsClientConfig`) object with desired global and default options. This is global configuration across all forms, some of which can be overridden at the form level.
40
47
 
41
48
  ```tsx
42
49
  export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
@@ -77,10 +84,12 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
77
84
  children, // RhfUtilsZodForm's Children instance
78
85
  },
79
86
  ) => {
80
- // your own hooks/behaviors controlled via custom option props
87
+ useMyGlobalFormHook();
88
+
89
+ // form-level control of your own hooks/behaviors via custom option props
81
90
  // (see "Extend RhfUtilsFormOptions" section for more info)
82
- useMyFormNavigationPrompt({
83
- enabled: !!options?.enableMyFormNavigationPrompt,
91
+ useMyOptionalFormHook({
92
+ enabled: !!options?.enableMyOptionalFormHook,
84
93
  });
85
94
 
86
95
  return (
@@ -99,18 +108,13 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
99
108
  onSubmitErrorUnknown: (
100
109
  error, // unknown
101
110
  ) => {
102
- // return FormSubmitErrors object to be merged to RHF context errors
111
+ // return FormSubmitFieldErrors object to be merged to RHF context errors
103
112
  if (isMyServerError(error))
104
- return transformMyServerErrorToFormSubmitErrors(error);
105
-
106
- // if other error
107
- return {
108
- root: { type: 'server', message: 'There was a problem.' },
109
- } satisfies FormSubmitErrors;
113
+ return transformMyServerErrorToFormSubmitFieldErrors(error);
110
114
  },
111
115
 
112
- // rhfContext.formState.errors output for debugging
113
- FieldErrors: {
116
+ // RHF FormState.errors output for debugging
117
+ fieldErrors: {
114
118
  // callbacks to determine when to output information about field errors
115
119
  // provided `FlatFieldErrorsContext` (all, fields, roots, orphans, hasOrphans)
116
120
  // (See "Orphan Errors" section below for more info.)
@@ -133,7 +137,7 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
133
137
 
134
138
  ## Provider
135
139
 
136
- And add the context provider to your global provider stack:
140
+ Add the context provider to your global provider stack.
137
141
 
138
142
  ```tsx
139
143
  <RhfUtilsClientForZodContextProvider config={rhfUtilsClientConfig}>
@@ -185,7 +189,7 @@ Currently, only `zod` is supported.
185
189
  <label>
186
190
  Email
187
191
  <input {...field} disabled={isSubmitting} />
188
- <FormErrorMessageByPath path={field.name} />
192
+ <RhfUtilsFieldErrorMessage path={field.name} />
189
193
  </label>
190
194
  )}
191
195
  />
@@ -199,13 +203,9 @@ Currently, only `zod` is supported.
199
203
  }}
200
204
  utils={{
201
205
  submitOnChange: true,
202
- resetOnSubmitted: {
203
- onSuccess: { values: 'current' },
204
- onError: { values: 'defaults' },
205
- },
206
206
  // custom option props
207
207
  // (see "Extend RhfUtilsFormOptions" section)
208
- enableMyFormNavigationPrompt: true,
208
+ enableMyOptionalFormHook: true,
209
209
  }}
210
210
  form={{
211
211
  // class names are merged together with global defaults
@@ -242,18 +242,17 @@ function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema>) { }
242
242
 
243
243
  ## `FormSubmitError`
244
244
 
245
- This is an extended `Error` class that you can use to throw a structured error in your submit handler. It uses `FormSubmitErrors` (with an "s") type's structure, which is a flat, simplified version of RHF's `FieldErrors`.
245
+ This is an `Error`-based class that you can use to throw a schema-typed error in your submit handler.
246
246
 
247
- It differs from `FlatFieldError` only in that it is narrower. Namely, it is schema-typed, so it allows field names from your schema and `root.${string}` keys. And only `type` (optional) and `message` props for error.
247
+ (Internally, it uses `FormSubmitFieldErrors` type's structure, which is a flat, simplified version of RHF's `FieldErrors`. It differs from `FlatFieldError` only in that it is narrower. It allows field names from your schema and `root.${string}` keys. And only `type` (optional) and `message` props for error.)
248
248
 
249
- Example:
249
+ ### Example
250
250
 
251
251
  ```tsx
252
252
  <RhfUtilsZodForm
253
253
  onSubmit={async (data, { FormSubmitError }) => {
254
254
  if (isProblem(data))
255
255
  throw new FormSubmitError({
256
- root: { message: 'There was a problem with the form.' },
257
256
  'street.address': { message: 'Street address invalid.' },
258
257
  });
259
258
 
@@ -262,9 +261,9 @@ Example:
262
261
  />
263
262
  ```
264
263
 
265
- Any non-`FormSubmitError` error thrown from your submit handler (e.g., fetch/axios error) can be transformed by `RhfUtilsClientConfig`'s `onSubmitErrorUnknown` callback. This takes an `unknown` error and can return a `FormSubmitErrors` object, which is merged into RHF's form state errors.
264
+ Any non-`FormSubmitError` error thrown from your submit handler (e.g., fetch/axios error) can be transformed by `RhfUtilsClientConfig`'s `onSubmitErrorUnknown` callback. This takes an `unknown` error and can return a `FormSubmitFieldErrors` object, which is merged into RHF's form state errors.
266
265
 
267
- Most common use case will be transforming backend errors to frontend shape. (You can use `getOnSubmitTrpcClientErrorHandler` HOF provided by this library for TRPC backends.)
266
+ Most common use case will be transforming backend errors to frontend shape.
268
267
 
269
268
  ## `RhfUtilsFormOptions`
270
269
 
@@ -275,8 +274,12 @@ type RhfUtilsFormOptions = {
275
274
  /** Stop propagation of submit event. */
276
275
  stopSubmitPropagation?: boolean;
277
276
 
278
- /** Request submit via listener on form change. */
279
- submitOnChange?: boolean;
277
+ /**
278
+ * Request submit via listener on form change.
279
+ * - `true`: no debounce
280
+ * - number: milliseconds to debounce
281
+ */
282
+ submitOnChange?: boolean | number;
280
283
 
281
284
  /**
282
285
  * Reset form values and state (e.g., isDirty, etc.) after submit -- on success and/or error.
@@ -308,7 +311,7 @@ declare module '@paragrav/rhf-utils' {
308
311
  export interface Register {
309
312
  RhfUtilsFormOptions: {
310
313
  /** Enable user prompt to confirm navigating away from dirty form. */
311
- enableMyFormNavigationPrompt?: boolean;
314
+ enableMyOptionalFormHook?: boolean;
312
315
  };
313
316
  }
314
317
  }
@@ -324,47 +327,67 @@ Use `useFlatFieldErrorsContext()` hook, which returns an object with errors grou
324
327
 
325
328
  ### Output
326
329
 
327
- For the purposes of debugging and/or logging, you can configure when form state errors are outputted (i.e., console log and/or thrown) via `RhfUtilsClientConfig` (example at the top).
330
+ For the purposes of debugging and/or logging, you can configure when form state errors are outputted (i.e., console and/or thrown) via `RhfUtilsClientConfig.fieldErrors.output` (example at the top).
328
331
 
329
332
  ### Orphan Errors
330
333
 
331
- The concept of "orphan" errors is any field error that is not being shown to user. (For example, a field in a schema that is prohibiting users from submitting a valid form.)
334
+ The concept of an "orphan" error is any errant schema property that could prohibit users from submitting a valid form because its input is missing or non-existent.
335
+
336
+ Programatically, an "orphan" is any form state error that meets ALL of the following criteria:
337
+
338
+ - non-field -- i.e., no RHF-supplied `ref` on `FieldError` object
339
+ - non-root -- i.e., not `root` or `root.${string}` path
340
+ - no corresponding "marker" in DOM (i.e., `FormNonFieldErrorMarker`)
341
+
342
+ This is because:
332
343
 
333
- More technically, an "orphan" is any form state error that meets ALL of the following criteria:
344
+ - field errors (with `ref`s) are assumed to be displayed next to their respective input
345
+ - root errors (non-field, without `ref`s) are assumed to always be listed for display
346
+ - all other errors must be marked as displayed to distinguish from being an orphan
334
347
 
335
- - not a root error -- i.e., `root` and `root.${string}` paths
336
- - these are assumed to be listed for users somewhere
337
- - has no `ref` -- RHF includes `ref` to the associated input for each error (when applicable)
338
- - these are assumed to be shown next to their input fields
339
- - has no marker in DOM (i.e., `FormNonFieldErrorMarker`)
340
- - see section further below for more information
348
+ _See [FormNonFieldErrorMarker](#formnonfielderrormarker) section below for more information about when and why marker is needed._
349
+
350
+ #### Using orphan errors
341
351
 
342
352
  Detected orphans can be accessed via any of the following:
343
353
 
344
- - via `RhfUtilsClientConfig.FieldErrors.output`; e.g.:
345
- - console log to facilitate debugging on development
346
- - console error to facilitate reporting on production (via your own error reporting service)
347
- - throw error for developer during development
354
+ - `RhfUtilsClientConfig.fieldErrors.output` -- e.g., config per environment:
355
+ - _development_: `throw` to facilitate discovery and debugging
356
+ - _production_: `console.error` to facilitate reporting
348
357
  - `useFlatFieldErrorsContext()` hook
349
358
  - returns an object with list of errors grouped by `all`, `fields` (with `ref`), `roots`, `orphans` records, and includes computed booleans `hasErrors` and `hasOrphans`
350
359
  - boolean value from `useFlatFieldErrorsContextHasOnlyOrphans`
351
360
 
352
361
  ### FormNonFieldErrorMarker
353
362
 
354
- To get accurate orphan detection, you must use `FormNonFieldErrorMarker` in all errors you are displaying to user. (Technically, "root" errors and field errors with a `ref` do not need the marker, because those do not match the first two criteria of an orphan (as listed above). But there is no harm in including it consistently for all error displayed.)
363
+ _If you don't need orphan detection, you can skip this section. By default, orphan detection still occurs but doesn't otherwise do anything._
364
+
365
+ To get accurate orphan detection, you must use `FormNonFieldErrorMarker` when displaying any non-root non-field errors. (Example further below.)
366
+
367
+ There is little harm in including it consistently for all individual errors displayed. (DOM traversal to find marker only occurs if error is non-field AND non-root, which is not typical.)
368
+
369
+ #### When is the marker required? _(example of non-root non-field error)_
370
+
371
+ A typical example is a field array with a required minimum number of items -- e.g., `items: z.array(...).min(1)`.
355
372
 
356
- #### When is the marker required?
373
+ When there are zero items, the error is non-field and non-root. You would probably display this error (manually) near the field array, using something like RHF's [`ErrorMessage`](https://www.react-hook-form.com/api/useformstate/errormessage/) component.
357
374
 
358
- For example, a field array with a minimum number of items -- e.g., `items: z.array(...).min(1)`.
375
+ In order to NOT detect this as an orphan, it must be explicitly "marked" as displayed using `FormNonFieldErrorMarker`.
359
376
 
360
- When there are zero items, the error is not "root" and is not associated with a specific field. Therefore, in order to NOT detect this as an orphan, it must be "marked" as displayed using `FormNonFieldErrorMarker`.
377
+ You can incorporate `FormNonFieldErrorMarker` into your own component library, or use this library's `RhfUtilsFieldErrorMessage` to display error message to user, which includes this marker.
361
378
 
362
- You can incorporate `FormNonFieldErrorMarker` into your own component library, or use this library's `FormErrorMessageByPath` to display error message to user, which includes this marker.
379
+ ```tsx
380
+ <RhfUtilsFieldErrorMessage path="items" />
381
+ ```
382
+
383
+ Uncommon, but if you are ONLY listing a summary of all errors, without individual displays, you will need to use the marker manually.
363
384
 
364
385
  ```tsx
365
- <FormErrorMessageByPath path="items" />
386
+ <FormNonFieldErrorMarker path="items" />
366
387
  ```
367
388
 
389
+ _If you include the marker for error lists, it will defeat the purpose of the marker. Only use marker for individual errors._
390
+
368
391
  ## Form Groups
369
392
 
370
393
  Sometimes you need to group multiple forms together.
@@ -392,9 +415,11 @@ Both hooks return `boolean` value indicating whether parent form is busy.
392
415
 
393
416
  ## Other
394
417
 
418
+ ### SafeFieldValues
419
+
395
420
  This library uses `SafeFieldValues` type which uses `unknown` instead of `any`.
396
421
 
397
- #### Peer dependencies:
422
+ ### Peer dependencies
398
423
 
399
424
  - [react](https://www.npmjs.com/package/react)
400
425
  - [react-dom](https://www.npmjs.com/package/react-dom)
@@ -7,4 +7,3 @@ export {
7
7
  o as _RhfUtilsClientConfigContextProvider,
8
8
  i as default
9
9
  };
10
- //# sourceMappingURL=useRhfUtilsClientConfigContext.mjs.map
@@ -47,4 +47,3 @@ const c = (r) => (o) => {
47
47
  export {
48
48
  c as createRhfUtilsClient
49
49
  };
50
- //# sourceMappingURL=index.mjs.map
@@ -36,4 +36,3 @@ const u = (n, ...r) => (
36
36
  export {
37
37
  u as mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps
38
38
  };
39
- //# sourceMappingURL=utils.mjs.map
@@ -7,10 +7,11 @@ const d = ({
7
7
  config: r,
8
8
  children: i
9
9
  }) => {
10
- const [t] = e.useState(r), [n] = e.useState(() => f(t));
10
+ const [t] = e.useState(r), [n] = e.useState(
11
+ () => f(t ?? {})
12
+ );
11
13
  return /* @__PURE__ */ o(l, { value: t, children: /* @__PURE__ */ o(s, { value: n, children: i }) });
12
14
  }, p = d;
13
15
  export {
14
16
  p as default
15
17
  };
16
- //# sourceMappingURL=RhfUtilsClientForZodContextProvider.mjs.map
@@ -10,4 +10,3 @@ function m({
10
10
  export {
11
11
  m as default
12
12
  };
13
- //# sourceMappingURL=RhfUtilsZodForm.mjs.map
@@ -7,4 +7,3 @@ export {
7
7
  o as _RhfUtilsClientForZodContextProvider,
8
8
  r as default
9
9
  };
10
- //# sourceMappingURL=useRhfUtilsClientForZodContext.mjs.map
@@ -3,4 +3,3 @@ const e = (o, t) => s().useForm(o, t), f = e;
3
3
  export {
4
4
  f as default
5
5
  };
6
- //# sourceMappingURL=useRhfUtilsZodForm.mjs.map
@@ -4,4 +4,3 @@ const i = e(t);
4
4
  export {
5
5
  i as default
6
6
  };
7
- //# sourceMappingURL=createRhfUtilsClientForZod.mjs.map
@@ -13,4 +13,3 @@ const a = e.lazy(
13
13
  export {
14
14
  u as default
15
15
  };
16
- //# sourceMappingURL=LazyDevTool.mjs.map
@@ -15,4 +15,3 @@ const o = ({ errors: e }) => {
15
15
  export {
16
16
  o as default
17
17
  };
18
- //# sourceMappingURL=FlatFieldErrorsList.mjs.map
@@ -25,4 +25,3 @@ const C = ({
25
25
  export {
26
26
  C as default
27
27
  };
28
- //# sourceMappingURL=FlatFieldErrorsContextProvider.mjs.map
@@ -7,4 +7,3 @@ export {
7
7
  o as _FormErrorsFlatContextProvider,
8
8
  s as default
9
9
  };
10
- //# sourceMappingURL=useFlatFieldErrorsContext.mjs.map
@@ -7,4 +7,3 @@ const t = () => {
7
7
  export {
8
8
  l as default
9
9
  };
10
- //# sourceMappingURL=useFlatFieldErrorsContextHasOnlyOrphans.mjs.map
@@ -22,4 +22,3 @@ const C = (r) => {
22
22
  export {
23
23
  C as default
24
24
  };
25
- //# sourceMappingURL=useFlatFieldErrorsContextOutput.mjs.map
@@ -8,4 +8,3 @@ const r = (e) => (t) => (
8
8
  export {
9
9
  r as default
10
10
  };
11
- //# sourceMappingURL=filterFlatFieldErrors.mjs.map
@@ -3,4 +3,3 @@ const o = (t) => r(t);
3
3
  export {
4
4
  o as default
5
5
  };
6
- //# sourceMappingURL=flattenFieldErrors.mjs.map
@@ -1,25 +1,24 @@
1
- import { get as c } from "react-hook-form";
2
- import n from "./flattenFieldErrors.mjs";
3
- const u = (t) => {
4
- const s = n(t), a = Object.keys(s);
1
+ import { get as d } from "react-hook-form";
2
+ import a from "./flattenFieldErrors.mjs";
3
+ const b = (t) => {
4
+ const s = a(t), n = Object.keys(s);
5
5
  return Object.fromEntries(
6
- a.reduce(
6
+ n.reduce(
7
7
  (e, o) => {
8
8
  const r = o.replace(
9
- d,
9
+ i,
10
10
  ""
11
11
  );
12
12
  if (r === o) return e;
13
- const f = c(t, r, void 0);
13
+ const f = d(t, r, void 0);
14
14
  return f && e.push([r, f]), e;
15
15
  },
16
16
  []
17
17
  // entries
18
18
  )
19
19
  );
20
- }, d = /\.(?:type|message)\b$/;
20
+ }, i = /\.(?:type|message)\b$/;
21
21
  export {
22
- u as default,
23
- d as regexMaybeFieldErrorLeafNodeSuffix
22
+ b as default,
23
+ i as regexMaybeFieldErrorLeafNodeSuffix
24
24
  };
25
- //# sourceMappingURL=getFlatFieldErrors.mjs.map
@@ -6,4 +6,3 @@ const l = r(
6
6
  export {
7
7
  l as default
8
8
  };
9
- //# sourceMappingURL=getRefdFromFlatFieldErrors.mjs.map
@@ -2,4 +2,3 @@ const r = (e) => !!e.ref;
2
2
  export {
3
3
  r as default
4
4
  };
5
- //# sourceMappingURL=isFieldErrorRefd.mjs.map
@@ -3,4 +3,3 @@ const t = ([, r]) => e(r);
3
3
  export {
4
4
  t as default
5
5
  };
6
- //# sourceMappingURL=isFlatFieldErrorEntryRefd.mjs.map
@@ -12,4 +12,3 @@ const i = ({ message: r, className: e }) => /* @__PURE__ */ o(
12
12
  export {
13
13
  i as default
14
14
  };
15
- //# sourceMappingURL=FormErrorMessage.mjs.map
@@ -0,0 +1,14 @@
1
+ import { jsxs as n, Fragment as i, jsx as o } from "react/jsx-runtime";
2
+ import { useFormState as a, get as l } from "react-hook-form";
3
+ import f from "../nonfield/FormNonFieldErrorMarker.mjs";
4
+ import g from "./FormErrorMessage.mjs";
5
+ const F = ({ path: e, Component: s }) => {
6
+ const { errors: t } = a(), r = l(t, e, void 0), m = s ?? g;
7
+ return r != null && r.message ? /* @__PURE__ */ n(i, { children: [
8
+ /* @__PURE__ */ o(m, { message: r.message }),
9
+ /* @__PURE__ */ o(f, { path: e })
10
+ ] }) : null;
11
+ }, E = F;
12
+ export {
13
+ E as default
14
+ };
@@ -17,4 +17,3 @@ const a = ({ path: r }) => {
17
17
  export {
18
18
  d as default
19
19
  };
20
- //# sourceMappingURL=FormNonFieldErrorMarker.mjs.map
@@ -21,4 +21,3 @@ const m = (r, e) => (
21
21
  export {
22
22
  m as getFormNonFieldErrorMarkerQuerySelector
23
23
  };
24
- //# sourceMappingURL=FormNonFieldErrorMarker.utils.mjs.map
@@ -2,4 +2,3 @@ const r = "data-paragrav-rhf-utils-nonfield-error-marker-path";
2
2
  export {
3
3
  r as default
4
4
  };
5
- //# sourceMappingURL=FormNonFieldErrorMarkerHtmlAttribute.mjs.map
@@ -3,4 +3,3 @@ const l = (r, e) => !!e.querySelector(o(r));
3
3
  export {
4
4
  l as default
5
5
  };
6
- //# sourceMappingURL=isNonFieldErrorMarkerInDOM.mjs.map
@@ -3,4 +3,3 @@ const n = (r) => ([t, e]) => o(t, e, r);
3
3
  export {
4
4
  n as default
5
5
  };
6
- //# sourceMappingURL=getIsOrphanFormErrorWithParentElement.mjs.map
@@ -6,4 +6,3 @@ const F = (r, t) => e(
6
6
  export {
7
7
  F as default
8
8
  };
9
- //# sourceMappingURL=getOrphansFromFlatFieldErrors.mjs.map
@@ -2,12 +2,11 @@ import m from "../isFieldErrorRefd.mjs";
2
2
  import t from "../nonfield/isNonFieldErrorMarkerInDOM.mjs";
3
3
  import e from "../root/isFormErrorPathRoot.mjs";
4
4
  const d = (r, o, i) => (
5
- // not root path
6
- !e(r) && // non-field
7
- !m(o) && // not marked in DOM
5
+ // non-field
6
+ !m(o) && // non-root
7
+ !e(r) && // not marked in DOM
8
8
  !t(r, i)
9
9
  );
10
10
  export {
11
11
  d as default
12
12
  };
13
- //# sourceMappingURL=isOrphanFormError.mjs.map
@@ -4,4 +4,3 @@ const c = (o, e, s, r = "debug") => {
4
4
  export {
5
5
  c as default
6
6
  };
7
- //# sourceMappingURL=consoleErrors.mjs.map
@@ -8,4 +8,3 @@ const e = () => {
8
8
  export {
9
9
  m as default
10
10
  };
11
- //# sourceMappingURL=RootErrorsListFromFlatFieldErrorsContext.mjs.map
@@ -2,4 +2,3 @@ const o = "root";
2
2
  export {
3
3
  o as FormErrorPathRoot
4
4
  };
5
- //# sourceMappingURL=consts.mjs.map
@@ -6,4 +6,3 @@ const l = r(
6
6
  export {
7
7
  l as default
8
8
  };
9
- //# sourceMappingURL=getRootsFromFlatFieldErrors.mjs.map
@@ -3,4 +3,3 @@ const a = ([o]) => r(o);
3
3
  export {
4
4
  a as default
5
5
  };
6
- //# sourceMappingURL=isFlatFieldErrorEntryPathRoot.mjs.map
@@ -3,4 +3,3 @@ const s = (o) => o === r || o.startsWith(r + ".");
3
3
  export {
4
4
  s as default
5
5
  };
6
- //# sourceMappingURL=isFormErrorPathRoot.mjs.map