@paragrav/rhf-utils 0.0.134 → 0.0.135

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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present paragrav.dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Integration and utility library for [react-hook-form](https://www.react-hook-form.com/).
6
6
 
7
- If you have multiple forms and would like a more declarative API to manage their behavior (via built-in and custom options), including transformation of backend errors, and debugging field errors.
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.
8
8
 
9
9
  ## Features
10
10
 
@@ -18,11 +18,11 @@ If you have multiple forms and would like a more declarative API to manage their
18
18
  - schema-typed Controller component
19
19
  - schema-typed FormSubmitError class
20
20
  - throw in submit handler to add errors to RHF context and fail submit
21
- - flatter `FieldErrors` structure (`FlatFieldErrors`)
22
- - grouped into `all`, `fields`, `roots`, and `orphans`
23
- - `FormErrorMessageByPath` for displaying error message (with `FormNonFieldErrorMarker`)
21
+ - simpler/flatter `FieldErrors` structure (`FlatFieldErrors`)
22
+ - context groups errors into `all`, `fields`, `roots`, and `orphans` (`useFlatFieldErrorsContext`)
23
+ - `FormErrorMessageByPath` for displaying error message
24
24
  - `zod` support
25
- - including `z.input` and `z.output` types for transformations
25
+ - including input/output types for transformations
26
26
  - safer `FieldValues` type (`SafeFieldValues`)
27
27
  - 3.3kB min+gzip core functionality (excluding [peer dependencies](#peer-dependencies))
28
28
 
@@ -221,12 +221,12 @@ Currently, only `zod` is supported.
221
221
  If you prefer to define your `Children` component as standalone:
222
222
 
223
223
  ```tsx
224
- const Children: RhfUtilsUseFormChildrenZodFC<typeof schema> = ({ ... }) => { };
224
+ const Children: RhfUtilsUseFormChildrenZodFC<typeof schema> = ({...}) => { };
225
225
 
226
226
  function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema>) { }
227
227
  ```
228
228
 
229
- ## Component Hierarchy
229
+ ## Form Component Hierarchy
230
230
 
231
231
  ```tsx
232
232
  <ReactHookForm.FormProvider>
@@ -242,7 +242,7 @@ function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema>) { }
242
242
 
243
243
  ## `FormSubmitError`
244
244
 
245
- This is an `Error`-based 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 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`.
246
246
 
247
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.
248
248
 
@@ -262,7 +262,7 @@ Example:
262
262
  />
263
263
  ```
264
264
 
265
- Any non-`FormSubmitError`s thrown from 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 in RHF's context errors.
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.
266
266
 
267
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.)
268
268
 
@@ -272,7 +272,7 @@ These options can be set globally and/or per form.
272
272
 
273
273
  ```ts
274
274
  type RhfUtilsFormOptions = {
275
- /** Stop propagation of submit event. Useful for portals. */
275
+ /** Stop propagation of submit event. */
276
276
  stopSubmitPropagation?: boolean;
277
277
 
278
278
  /** Request submit via listener on form change. */
@@ -293,7 +293,7 @@ type RhfUtilsFormOptions = {
293
293
  };
294
294
  ```
295
295
 
296
- If you need access to options deeper in component structure, use `useRhfUtilsContext` to receive `RhfUtilsContext` object, which includes `formId`, `formRef`, and `options` settings.
296
+ If you need access to options deeper in your component structure, use `useRhfUtilsContext` to receive `RhfUtilsContext` object, which includes `formId`, `formRef`, and `options` settings.
297
297
 
298
298
  Use `useRhfUtilsContextRequestSubmit` hook to get `requestSubmit` function for current form ref in context. This is useful when you need to trigger form submission programatically.
299
299
 
@@ -314,39 +314,56 @@ declare module '@paragrav/rhf-utils' {
314
314
  }
315
315
  ```
316
316
 
317
- ## Errors
317
+ ## Field Errors
318
318
 
319
- You can configure via `RhfUtilsClientConfig` (example at the top) when form context errors are outputted -- i.e., via console and/or thrown error.
319
+ ### FlatFieldErrors
320
+
321
+ `FlatFieldErrors` type is a flattened, simplified version of RHF's `FieldErrors`. Keys represent flattened, dot-notation field paths.
320
322
 
321
323
  Use `useFlatFieldErrorsContext()` hook, which returns an object with errors grouped by `all`, `fields`, `roots`, `orphans` records, and `hasErrors` and `hasErrors` and `hasOrphans` booleans.
322
324
 
323
- `FlatFieldErrors` type is a flattened, simplified version of RHF's `FieldErrors`. Keys represent flattened, dot-notation field paths.
325
+ ### Output
326
+
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).
324
328
 
325
329
  ### Orphan Errors
326
330
 
327
- The concept of orphan errors is any error that is not being shown to user. An example would be a stray field in a schema that is prohibiting users from successfully submitting a form.
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.)
328
332
 
329
- The criteria for an orphan is any form context error that meets all of the following criteria:
333
+ More technically, an "orphan" is any form state error that meets ALL of the following criteria:
330
334
 
331
- - not a root error -- e.g., `root` or `root.${string}`
332
- - has no `ref` -- RHF includes `ref` to the associated input on each error object (when applicable)
333
- - has no marker in DOM (e.g., `FormNonFieldErrorMarker`)
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
334
341
 
335
- To get accurate orphan analysis, you must either use `FormNonFieldErrorMarker` in any error you are displaying to user that is not "root" and doesn't have a `ref`. (There is no harm in using this consistently across all errors, even those expected to have a ref.)
342
+ Detected orphans can be accessed via any of the following:
336
343
 
337
- Alternatively, you can use `FormErrorMessageByPath` to display error message to user:
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
348
+ - `useFlatFieldErrorsContext()` hook
349
+ - returns an object with list of errors grouped by `all`, `fields` (with `ref`), `roots`, `orphans` records, and includes computed booleans `hasErrors` and `hasOrphans`
350
+ - boolean value from `useFlatFieldErrorsContextHasOnlyOrphans`
338
351
 
339
- ```tsx
340
- <FormErrorMessageByPath path="street.address" />
341
- ```
352
+ ### FormNonFieldErrorMarker
342
353
 
343
- Example use case: Field array with minimum items. When there are no items, the error is not associated with a field and is displayed separately.
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.)
344
355
 
345
- Orphans are exposed in a few places.
356
+ #### When is the marker required?
346
357
 
347
- - In errors outputted via console. (Configurable via `RhfUtilsClientConfig['errors']['output']`.)
348
- - And `useFlatFieldErrorsContext()` hook, which returns an object with errors grouped by `all`, `fields`, `roots`, `orphans` records, and `hasErrors` and `hasOrphans` boolean.
349
- - Boolean value from `useFlatFieldErrorsContextHasOnlyOrphans`.
358
+ For example, a field array with a minimum number of items -- e.g., `items: z.array(...).min(1)`.
359
+
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`.
361
+
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.
363
+
364
+ ```tsx
365
+ <FormErrorMessageByPath path="items" />
366
+ ```
350
367
 
351
368
  ## Form Groups
352
369
 
@@ -1,30 +1,39 @@
1
- const i = (l, ...t) => (
1
+ const u = (n, ...r) => (
2
2
  // sequentially merge each set of props into defaults
3
- t.reduce(
4
- (s, e) => {
5
- var f, o;
3
+ r.reduce(
4
+ (t, e) => {
5
+ var s, i, l, m, o, f;
6
6
  return {
7
7
  rhf: {
8
- ...s == null ? void 0 : s.rhf,
8
+ ...t == null ? void 0 : t.rhf,
9
9
  ...e.rhf
10
10
  },
11
11
  utils: {
12
- ...s == null ? void 0 : s.utils,
13
- ...e.utils
12
+ ...t == null ? void 0 : t.utils,
13
+ ...e.utils,
14
+ // manual merges
15
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- false positive
16
+ ...(((s = t == null ? void 0 : t.utils) == null ? void 0 : s.resetOnSubmitted) || ((i = e.utils) == null ? void 0 : i.resetOnSubmitted)) && {
17
+ resetOnSubmitted: {
18
+ ...(l = t == null ? void 0 : t.utils) == null ? void 0 : l.resetOnSubmitted,
19
+ ...(m = e.utils) == null ? void 0 : m.resetOnSubmitted
20
+ }
21
+ }
14
22
  },
15
23
  form: {
16
- ...s == null ? void 0 : s.form,
24
+ ...t == null ? void 0 : t.form,
17
25
  ...e.form,
18
- className: [(f = s == null ? void 0 : s.form) == null ? void 0 : f.className, (o = e.form) == null ? void 0 : o.className].filter(Boolean).join(" ")
19
- // stringify
26
+ // manual merges
27
+ className: [(o = t == null ? void 0 : t.form) == null ? void 0 : o.className, (f = e.form) == null ? void 0 : f.className].filter(Boolean).join(" ") || void 0
28
+ // stringify (replace empty string with undefined)
20
29
  }
21
30
  };
22
31
  },
23
32
  // start with defaults
24
- l
33
+ n
25
34
  )
26
35
  );
27
36
  export {
28
- i as mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps
37
+ u as mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps
29
38
  };
30
39
  //# sourceMappingURL=utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","sources":["../../../src/client/utils.ts"],"sourcesContent":["import type { RhfUtilsFormOptions } from '@/form/RhfUtilsFormOptions';\nimport type { SafeFieldValues } from '@/form/SafeFieldValues';\nimport type { UseRhfUtilsFormProps } from '@/form/UseRhfUtilsFormProps';\n\nimport type { RhfUtilsClientConfig } from './config/RhfUtilsClientConfig';\n\n/**\n * Merge {@link RhfUtilsClientConfig.defaults} with array of {@link UseRhfUtilsFormProps}'s overrides.\n */\nexport const mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps = <\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n>(\n defaults: RhfUtilsClientConfig['defaults'],\n ...props: Pick<\n UseRhfUtilsFormProps<TFieldValues, TTransformedValues>,\n 'rhf' | 'utils' | 'form'\n >[]\n) =>\n // sequentially merge each set of props into defaults\n props.reduce(\n (acc, curr) => ({\n rhf: {\n ...acc?.rhf,\n ...curr.rhf,\n },\n\n utils: {\n ...acc?.utils,\n ...curr.utils,\n } satisfies RhfUtilsFormOptions,\n\n form: {\n ...acc?.form,\n ...curr.form,\n className: [acc?.form?.className, curr.form?.className]\n .filter(Boolean) // filter out falsy values\n .join(' '), // stringify\n },\n }),\n\n // start with defaults\n defaults,\n );\n"],"names":["mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps","defaults","props","acc","curr","_a","_b"],"mappings":"AASa,MAAAA,IAA4D,CAIvEC,MACGC;AAAA;AAAA,EAMHA,EAAM;AAAA,IACJ,CAACC,GAAKC,MAAU;AAZP,UAAAC,GAAAC;AAYO;AAAA,QACd,KAAK;AAAA,UACH,GAAGH,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA,QACV;AAAA,QAEA,OAAO;AAAA,UACL,GAAGD,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA,QACV;AAAA,QAEA,MAAM;AAAA,UACJ,GAAGD,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA,UACR,WAAW,EAACC,IAAAF,KAAA,gBAAAA,EAAK,SAAL,gBAAAE,EAAW,YAAWC,IAAAF,EAAK,SAAL,gBAAAE,EAAW,SAAS,EACnD,OAAO,OAAO,EACd,KAAK,GAAG;AAAA;AAAA,QACb;AAAA,MAAA;AAAA;AAAA;AAAA,IAIFL;AAAA,EACF;AAAA;"}
1
+ {"version":3,"file":"utils.mjs","sources":["../../../src/client/utils.ts"],"sourcesContent":["import type { RhfUtilsFormOptions } from '@/form/RhfUtilsFormOptions';\nimport type { SafeFieldValues } from '@/form/SafeFieldValues';\nimport type { UseRhfUtilsFormProps } from '@/form/UseRhfUtilsFormProps';\n\nimport type { RhfUtilsClientConfig } from './config/RhfUtilsClientConfig';\n\n/**\n * Merge {@link RhfUtilsClientConfig.defaults} with array of {@link UseRhfUtilsFormProps}'s overrides.\n */\nexport const mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps = <\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n>(\n defaults: RhfUtilsClientConfig['defaults'],\n ...props: Pick<\n UseRhfUtilsFormProps<TFieldValues, TTransformedValues>,\n 'rhf' | 'utils' | 'form'\n >[]\n) =>\n // sequentially merge each set of props into defaults\n props.reduce(\n (acc, curr) => ({\n rhf: {\n ...acc?.rhf,\n ...curr.rhf,\n },\n\n utils: {\n ...acc?.utils,\n ...curr.utils,\n\n // manual merges\n\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- false positive\n ...((acc?.utils?.resetOnSubmitted || curr.utils?.resetOnSubmitted) && {\n resetOnSubmitted: {\n ...acc?.utils?.resetOnSubmitted,\n ...curr.utils?.resetOnSubmitted,\n },\n }),\n } satisfies RhfUtilsFormOptions,\n\n form: {\n ...acc?.form,\n ...curr.form,\n\n // manual merges\n\n className:\n [acc?.form?.className, curr.form?.className]\n .filter(Boolean) // filter out falsy values\n .join(' ') || undefined, // stringify (replace empty string with undefined)\n },\n }),\n\n // start with defaults\n defaults,\n );\n"],"names":["mergeRhfUtilsClientConfigDefaultsWithUseRhfUtilsFormProps","defaults","props","acc","curr","_a","_b","_c","_d","_e","_f"],"mappings":"AASa,MAAAA,IAA4D,CAIvEC,MACGC;AAAA;AAAA,EAMHA,EAAM;AAAA,IACJ,CAACC,GAAKC,MAAU;AAZP,UAAAC,GAAAC,GAAAC,GAAAC,GAAAC,GAAAC;AAYO;AAAA,QACd,KAAK;AAAA,UACH,GAAGP,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA,QACV;AAAA,QAEA,OAAO;AAAA,UACL,GAAGD,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA;AAAA;AAAA,UAKR,MAAKC,IAAAF,KAAA,gBAAAA,EAAK,UAAL,gBAAAE,EAAY,uBAAoBC,IAAAF,EAAK,UAAL,gBAAAE,EAAY,sBAAqB;AAAA,YACpE,kBAAkB;AAAA,cAChB,IAAGC,IAAAJ,KAAA,gBAAAA,EAAK,UAAL,gBAAAI,EAAY;AAAA,cACf,IAAGC,IAAAJ,EAAK,UAAL,gBAAAI,EAAY;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAAA,QAEA,MAAM;AAAA,UACJ,GAAGL,KAAA,gBAAAA,EAAK;AAAA,UACR,GAAGC,EAAK;AAAA;AAAA,UAIR,WACE,EAACK,IAAAN,KAAA,gBAAAA,EAAK,SAAL,gBAAAM,EAAW,YAAWC,IAAAN,EAAK,SAAL,gBAAAM,EAAW,SAAS,EACxC,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAAA;AAAA,QACpB;AAAA,MAAA;AAAA;AAAA;AAAA,IAIFT;AAAA,EACF;AAAA;"}
@@ -8,7 +8,7 @@ import { Register } from '../register';
8
8
  * Can be extended using {@link Register.RhfUtilsFormOptions}.
9
9
  */
10
10
  export type RhfUtilsFormOptions = {
11
- /** Stop propagation of submit event. Useful for portals. */
11
+ /** Stop propagation of submit event. */
12
12
  stopSubmitPropagation?: boolean;
13
13
  /** Request submit via listener on form change. */
14
14
  submitOnChange?: boolean;
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.134",
5
+ "version": "0.0.135",
6
6
  "description": "Integration utilities for react-hook-form.",
7
7
  "type": "module",
8
8
  "sideEffects": false,
@@ -30,6 +30,10 @@
30
30
  "react-hook-form": "7",
31
31
  "zod": "3"
32
32
  },
33
+ "resolutions": {
34
+ "@playwright/experimental-ct-react": "1.44.1",
35
+ "@playwright/test": "1.44.1"
36
+ },
33
37
  "repository": {
34
38
  "type": "git",
35
39
  "url": "git+https://github.com/paragrav/rhf-utils.git"