@paragrav/rhf-utils 0.0.132 → 0.0.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,29 @@
2
2
 
3
3
  ## About
4
4
 
5
- Integration and utility library for react-hook-form.
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 built-in and custom options), including transformation of backend errors, and debugging field errors.
8
+
9
+ ## Features
10
+
11
+ - built with and for [TypeScript](https://www.typescriptlang.org/)
12
+ - global configuration, such as:
13
+ - injecting your own hooks and UI (`FormChildrenWrapper`)
14
+ - 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
21
+ - flatter `FieldErrors` structure (`FlatFieldErrors`)
22
+ - grouped into `all`, `fields`, `roots`, and `orphans`
23
+ - `FormErrorMessageByPath` for displaying error message (with `FormNonFieldErrorMarker`)
24
+ - `zod` support
25
+ - including `z.input` and `z.output` types for transformations
26
+ - safer `FieldValues` type (`SafeFieldValues`)
27
+ - 3.3kB min+gzip core functionality (excluding [peer dependencies](#peer-dependencies))
6
28
 
7
29
  ## Install
8
30
 
@@ -14,7 +36,7 @@ yarn add @paragrav/rhf-utils # yarn
14
36
 
15
37
  ## Config
16
38
 
17
- To configure, create a file `config.tsx` with desired configuration settings. This is global configuration across all forms.
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.
18
40
 
19
41
  ```tsx
20
42
  export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
@@ -50,8 +72,8 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
50
72
  formRef, // ref
51
73
  context, // rhf UseFormReturn
52
74
  options, // RhfUtilsFormOptions (with any custom props)
53
- Controller, // strictly-typed rhf controller
54
- FormSubmitError, // strictly-typed error class
75
+ Controller, // rhf controller (SafeFieldValues-typed; no schema at this level)
76
+ FormSubmitError, // error class (SafeFieldValues-typed; no schema at this level)
55
77
  children, // RhfUtilsZodForm's Children instance
56
78
  },
57
79
  ) => {
@@ -132,7 +154,7 @@ Currently, only `zod` is supported.
132
154
  // submit handler
133
155
  onSubmit={async (
134
156
  data, // schema output
135
- context, // UseRhfUtilsFormOnSubmitContext (id, ref, rhf context, utils options, strictly-typed FormSubmitError class)
157
+ context, // UseRhfUtilsFormOnSubmitContext (id, ref, rhf context, utils options, schema-typed FormSubmitError class)
136
158
  event, // SubmitEvent
137
159
  ) => {
138
160
  await loginService(data);
@@ -153,12 +175,12 @@ Currently, only `zod` is supported.
153
175
  formRef, // ref
154
176
  context, // rhf UseFormReturn
155
177
  options, // RhfUtilsFormOptions
156
- Controller, // strictly-typed rhf controller
157
- FormSubmitError, // strictly-typed error class
178
+ Controller, // schema-typed rhf controller
179
+ FormSubmitError, // schema-typed error class
158
180
  }) => (
159
181
  <>
160
182
  <Controller
161
- name="email" // strictly-typed field name
183
+ name="email" // schema-typed field name
162
184
  render={({ field, formState: { isSubmitting } }) => (
163
185
  <label>
164
186
  Email
@@ -220,16 +242,16 @@ function Children({...}: RhfUtilsUseFormChildrenZodProps<typeof schema>) { }
220
242
 
221
243
  ## `FormSubmitError`
222
244
 
223
- This is an `Error`-based class you can use to throw a structured error in your submit handler. It is strictly-typed, so it only allows field names from your schema and `root`/`root.{string}` keys.
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`.
224
246
 
225
- It uses `FormSubmitErrors` type's structure, which is a flat, simplified version of RHF's `FieldErrors`.
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.
226
248
 
227
249
  Example:
228
250
 
229
251
  ```tsx
230
252
  <RhfUtilsZodForm
231
- onSubmit={async ({ FormSubmitError }) => {
232
- if (isProblem())
253
+ onSubmit={async (data, { FormSubmitError }) => {
254
+ if (isProblem(data))
233
255
  throw new FormSubmitError({
234
256
  root: { message: 'There was a problem with the form.' },
235
257
  'street.address': { message: 'Street address invalid.' },
@@ -298,6 +320,8 @@ You can configure via `RhfUtilsClientConfig` (example at the top) when form cont
298
320
 
299
321
  Use `useFlatFieldErrorsContext()` hook, which returns an object with errors grouped by `all`, `fields`, `roots`, `orphans` records, and `hasErrors` and `hasErrors` and `hasOrphans` booleans.
300
322
 
323
+ `FlatFieldErrors` type is a flattened, simplified version of RHF's `FieldErrors`. Keys represent flattened, dot-notation field paths.
324
+
301
325
  ### Orphan Errors
302
326
 
303
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.
@@ -324,8 +348,6 @@ Orphans are exposed in a few places.
324
348
  - And `useFlatFieldErrorsContext()` hook, which returns an object with errors grouped by `all`, `fields`, `roots`, `orphans` records, and `hasErrors` and `hasOrphans` boolean.
325
349
  - Boolean value from `useFlatFieldErrorsContextHasOnlyOrphans`.
326
350
 
327
- `FlatFieldErrors` is a flattened, simplified version of RHF's `FieldErrors`. Keys represent field paths flattened to dot notation.
328
-
329
351
  ## Form Groups
330
352
 
331
353
  Sometimes you need to group multiple forms together.
@@ -350,3 +372,17 @@ In children forms, there are two options. You can choose to consider form "busy"
350
372
  - it is mounted by using `useFormGroupChildIsMountedTracker` hook
351
373
 
352
374
  Both hooks return `boolean` value indicating whether parent form is busy.
375
+
376
+ ## Other
377
+
378
+ This library uses `SafeFieldValues` type which uses `unknown` instead of `any`.
379
+
380
+ #### Peer dependencies:
381
+
382
+ - [react](https://www.npmjs.com/package/react)
383
+ - [react-dom](https://www.npmjs.com/package/react-dom)
384
+ - [react-hook-form](https://www.npmjs.com/package/react-hook-form)
385
+ - [zod](https://www.npmjs.com/package/zod)
386
+ - [flat](https://www.npmjs.com/package/flat)
387
+ - [@hookform/resolvers](https://www.npmjs.com/package/@hookform/resolvers)
388
+ - [@hookform/devtools](https://www.npmjs.com/package/@hookform/devtools) (optional)
@@ -5,8 +5,8 @@ import c from "./FormErrorMessage.mjs";
5
5
  const f = ({ path: o, Component: s }) => {
6
6
  const { errors: t } = g(), r = i(t, o, void 0), m = s ?? c;
7
7
  return r != null && r.message ? /* @__PURE__ */ n(a, { children: [
8
- /* @__PURE__ */ e(F, { path: o }),
9
- /* @__PURE__ */ e(m, { message: r.message })
8
+ /* @__PURE__ */ e(m, { message: r.message }),
9
+ /* @__PURE__ */ e(F, { path: o })
10
10
  ] }) : null;
11
11
  }, E = f;
12
12
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"FormErrorMessageByPath.mjs","sources":["../../../../src/errors/message/FormErrorMessageByPath.tsx"],"sourcesContent":["import type { FieldError } from 'react-hook-form';\nimport { get, useFormState } from 'react-hook-form';\n\nimport FormNonFieldErrorMarker from '../nonfield/FormNonFieldErrorMarker';\n\nimport FormErrorMessage from './FormErrorMessage';\n\ntype Props = {\n /** Field name as flat path. (e.g., \"address.street\") */\n path: string;\n /** Optional component to use to display message. (Defaults to {@link FormErrorMessage}) */\n Component?: React.FC<{ message: string }>;\n};\n\nconst FormErrorMessageByPath: React.FC<Props> = ({ path, Component }) => {\n const { errors } = useFormState();\n\n const error = get(errors, path, undefined) as FieldError | undefined;\n\n const _Component = Component ?? FormErrorMessage;\n\n if (!error?.message) return null;\n\n return (\n <>\n {/* marker (only required for non-root non-field errors) */}\n <FormNonFieldErrorMarker path={path} />\n\n {/* error message */}\n <_Component message={error.message} />\n </>\n );\n};\n\nexport default FormErrorMessageByPath;\n"],"names":["FormErrorMessageByPath","path","Component","errors","useFormState","error","get","_Component","FormErrorMessage","jsxs","Fragment","jsx","FormNonFieldErrorMarker","FormErrorMessageByPath$1"],"mappings":";;;;AAcA,MAAMA,IAA0C,CAAC,EAAE,MAAAC,GAAM,WAAAC,QAAgB;AACjE,QAAA,EAAE,QAAAC,MAAWC,KAEbC,IAAQC,EAAIH,GAAQF,GAAM,MAAS,GAEnCM,IAAaL,KAAaM;AAE5B,SAACH,KAAA,QAAAA,EAAO,UAKR,gBAAAI,EAAAC,GAAA,EAAA,UAAA;AAAA,IAAA,gBAAAC,EAACC,KAAwB,MAAAX,GAAY;AAAA,IAGpC,gBAAAU,EAAAJ,GAAA,EAAW,SAASF,EAAM,QAAS,CAAA;AAAA,EACtC,EAAA,CAAA,IAT0B;AAW9B,GAEAQ,IAAeb;"}
1
+ {"version":3,"file":"FormErrorMessageByPath.mjs","sources":["../../../../src/errors/message/FormErrorMessageByPath.tsx"],"sourcesContent":["import type { FieldError } from 'react-hook-form';\nimport { get, useFormState } from 'react-hook-form';\n\nimport FormNonFieldErrorMarker from '../nonfield/FormNonFieldErrorMarker';\n\nimport FormErrorMessage from './FormErrorMessage';\n\ntype Props = {\n /** Field name as flat path. (e.g., \"address.street\") */\n path: string;\n /** Optional component to use to display message. (Defaults to {@link FormErrorMessage}) */\n Component?: React.FC<{ message: string }>;\n};\n\nconst FormErrorMessageByPath: React.FC<Props> = ({ path, Component }) => {\n const { errors } = useFormState();\n\n const error = get(errors, path, undefined) as FieldError | undefined;\n\n const _Component = Component ?? FormErrorMessage;\n\n if (!error?.message) return null;\n\n return (\n <>\n {/* error message */}\n <_Component message={error.message} />\n\n {/* marker (only required for non-root non-field errors) */}\n <FormNonFieldErrorMarker path={path} />\n </>\n );\n};\n\nexport default FormErrorMessageByPath;\n"],"names":["FormErrorMessageByPath","path","Component","errors","useFormState","error","get","_Component","FormErrorMessage","jsxs","Fragment","jsx","FormNonFieldErrorMarker","FormErrorMessageByPath$1"],"mappings":";;;;AAcA,MAAMA,IAA0C,CAAC,EAAE,MAAAC,GAAM,WAAAC,QAAgB;AACjE,QAAA,EAAE,QAAAC,MAAWC,KAEbC,IAAQC,EAAIH,GAAQF,GAAM,MAAS,GAEnCM,IAAaL,KAAaM;AAE5B,SAACH,KAAA,QAAAA,EAAO,UAKR,gBAAAI,EAAAC,GAAA,EAAA,UAAA;AAAA,IAAC,gBAAAC,EAAAJ,GAAA,EAAW,SAASF,EAAM,QAAS,CAAA;AAAA,IAGpC,gBAAAM,EAACC,KAAwB,MAAAX,GAAY;AAAA,EACvC,EAAA,CAAA,IAT0B;AAW9B,GAEAY,IAAeb;"}
@@ -1,87 +1,87 @@
1
- import { jsx as h, jsxs as T } from "react/jsx-runtime";
1
+ import { jsx as c, jsxs as j } from "react/jsx-runtime";
2
2
  import "react";
3
- import { useFormContext as j } from "react-hook-form";
3
+ import { useFormContext as W } from "react-hook-form";
4
4
  import w from "../client/config/useRhfUtilsClientConfigContext.mjs";
5
5
  import E from "../devtool/LazyDevTool.mjs";
6
- import { FormSubmitError as s } from "../submit/error/FormSubmitError.mjs";
6
+ import { FormSubmitError as d } from "../submit/error/FormSubmitError.mjs";
7
7
  import S from "../submit/error/setCtxErrorsByFormSubmitErrors.mjs";
8
8
  import U from "../utils/PassthroughChildren.mjs";
9
- import W from "./_Controller.mjs";
10
- function A({
11
- formId: p,
12
- formRef: m,
9
+ import _ from "./_Controller.mjs";
10
+ function G({
11
+ formId: m,
12
+ formRef: p,
13
13
  //
14
14
  onSubmit: a,
15
- onSubmitError: d,
16
- onSubmitInvalid: i,
15
+ onSubmitError: s,
16
+ onSubmitInvalid: x,
17
17
  Children: l,
18
18
  //
19
19
  form: F,
20
20
  utils: r
21
21
  }) {
22
- const e = j(), t = w(), y = async (o) => {
22
+ const e = W(), t = w(), y = async (o) => {
23
23
  r != null && r.stopSubmitPropagation && o.stopPropagation();
24
24
  try {
25
- await e.handleSubmit(f, i)(o);
25
+ await e.handleSubmit(f, x)(o);
26
26
  } catch (n) {
27
- b(n, o);
27
+ P(n, o);
28
28
  }
29
29
  }, f = (o, n) => a == null ? void 0 : a(
30
30
  o,
31
31
  {
32
- formId: p,
33
- formRef: m,
32
+ formId: m,
33
+ formRef: p,
34
34
  context: e,
35
35
  utils: r,
36
- FormSubmitError: s
36
+ FormSubmitError: d
37
37
  },
38
38
  n
39
- ), b = (o, n) => {
40
- var x;
41
- const C = o instanceof s ? (
39
+ ), P = (o, n) => {
40
+ var i;
41
+ const C = o instanceof d ? (
42
42
  // consumer can manually throw FormSubmitError (e.g., manual validation)
43
43
  o.errors
44
44
  ) : (
45
45
  // if error is not FormSubmitError, consumer can provide global handler
46
- (x = t == null ? void 0 : t.onSubmitErrorUnknown) == null ? void 0 : x.call(t, o)
46
+ (i = t == null ? void 0 : t.onSubmitErrorUnknown) == null ? void 0 : i.call(t, o)
47
47
  );
48
- C && S(e, C), d == null || d(
48
+ C && S(e, C), s == null || s(
49
49
  o,
50
50
  {
51
- formId: p,
52
- formRef: m,
51
+ formId: m,
52
+ formRef: p,
53
53
  context: e,
54
54
  utils: r
55
55
  },
56
56
  n
57
57
  );
58
- }, c = {
59
- formId: p,
60
- formRef: m,
58
+ }, h = {
59
+ formId: m,
60
+ formRef: p,
61
61
  context: e,
62
62
  utils: r,
63
- Controller: W,
64
- FormSubmitError: s
65
- }, v = (t == null ? void 0 : t.FormComponent) ?? "form", P = (t == null ? void 0 : t.FormChildrenWrapper) ?? U;
66
- return /* @__PURE__ */ h(
63
+ Controller: _,
64
+ FormSubmitError: d
65
+ }, b = h, v = (t == null ? void 0 : t.FormComponent) ?? "form", T = (t == null ? void 0 : t.FormChildrenWrapper) ?? U;
66
+ return /* @__PURE__ */ c(
67
67
  v,
68
68
  {
69
69
  ...F,
70
- ref: m,
70
+ ref: p,
71
71
  onSubmit: (o) => void y(o),
72
- children: /* @__PURE__ */ T(P, { ...c, children: [
73
- (r == null ? void 0 : r.devTool) && /* @__PURE__ */ h(
72
+ children: /* @__PURE__ */ j(T, { ...b, children: [
73
+ (r == null ? void 0 : r.devTool) && /* @__PURE__ */ c(
74
74
  E,
75
75
  {
76
76
  props: typeof r.devTool == "object" ? r.devTool : void 0
77
77
  }
78
78
  ),
79
- /* @__PURE__ */ h(l, { ...c })
79
+ /* @__PURE__ */ c(l, { ...h })
80
80
  ] })
81
81
  }
82
82
  );
83
83
  }
84
84
  export {
85
- A as default
85
+ G as default
86
86
  };
87
87
  //# sourceMappingURL=Form.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Form.mjs","sources":["../../../src/form/Form.tsx"],"sourcesContent":["import React from 'react';\nimport type { UseFormHandleSubmit } from 'react-hook-form';\nimport { useFormContext } from 'react-hook-form';\n\nimport useRhfUtilsClientConfigMaybeContext from '@/client/config/useRhfUtilsClientConfigContext';\n\nimport LazyDevTool from '@/devtool/LazyDevTool';\n\nimport { FormSubmitError } from '@/submit/error/FormSubmitError';\nimport setCtxErrorsByFormSubmitErrors from '@/submit/error/setCtxErrorsByFormSubmitErrors';\n\nimport PassthroughChildren from '@/utils/PassthroughChildren';\n\nimport _Controller from './_Controller';\nimport type { SafeFieldValues } from './SafeFieldValues';\nimport type { UseRhfUtilsFormChildrenProps } from './UseRhfUtilsFormChildrenProps';\nimport type {\n UseRhfUtilsFormOnSubmitContext,\n UseRhfUtilsFormOnSubmitErrorContext,\n} from './UseRhfUtilsFormOnSubmitContext';\nimport type { UseRhfUtilsFormProps } from './UseRhfUtilsFormProps';\n\nexport type FormChildrenSlots = 'top' | 'bottom';\n\nexport type FormProps<\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n> = {\n formId: string;\n formRef: React.RefObject<HTMLFormElement>;\n} & Pick<\n UseRhfUtilsFormProps<TFieldValues, TTransformedValues>,\n | 'onSubmit'\n | 'onSubmitError'\n | 'onSubmitInvalid'\n //\n | 'Children'\n //\n | 'form'\n | 'utils'\n>;\n\nfunction _Form<\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n>({\n formId,\n formRef,\n //\n onSubmit,\n onSubmitError,\n onSubmitInvalid,\n Children,\n //\n form,\n utils,\n}: FormProps<TFieldValues, TTransformedValues>) {\n const rhfContext = useFormContext<\n TFieldValues,\n unknown,\n TTransformedValues\n >();\n\n const config = useRhfUtilsClientConfigMaybeContext();\n\n // handlers\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n // cannot stop propagation in handleSubmitValid, b/c it receives a different event object\n if (utils?.stopSubmitPropagation) event.stopPropagation();\n\n try {\n await rhfContext.handleSubmit(handleSubmitValid, onSubmitInvalid)(event);\n } catch (error) {\n handleSubmitError(error, event);\n }\n };\n\n const handleSubmitValid = ((\n data: TTransformedValues,\n event?: React.BaseSyntheticEvent,\n ) => {\n return onSubmit?.(\n data,\n {\n formId,\n formRef,\n context: rhfContext,\n utils,\n FormSubmitError: FormSubmitError<TFieldValues>,\n } satisfies UseRhfUtilsFormOnSubmitContext<\n TFieldValues,\n TTransformedValues\n >,\n event as React.BaseSyntheticEvent<SubmitEvent>, // `as` required due to conditional generic\n );\n }) as Parameters<UseFormHandleSubmit<TFieldValues, TTransformedValues>>[0];\n\n const handleSubmitError = (\n error: unknown,\n event: React.BaseSyntheticEvent,\n ) => {\n // get `FormSubmitErrors`, if possible\n const formSubmitErrors =\n error instanceof FormSubmitError\n ? // consumer can manually throw FormSubmitError (e.g., manual validation)\n (error as FormSubmitError).errors // `as` to avoid `<any>`\n : // if error is not FormSubmitError, consumer can provide global handler\n config?.onSubmitErrorUnknown?.(error);\n\n if (formSubmitErrors)\n setCtxErrorsByFormSubmitErrors(rhfContext, formSubmitErrors);\n\n onSubmitError?.(\n error,\n {\n formId,\n formRef,\n context: rhfContext,\n utils,\n } satisfies UseRhfUtilsFormOnSubmitErrorContext<\n TFieldValues,\n TTransformedValues\n >,\n event as React.BaseSyntheticEvent<SubmitEvent>, // `as` required due to conditional generic\n );\n };\n\n const childrenProps: UseRhfUtilsFormChildrenProps<\n TFieldValues,\n TTransformedValues\n > = {\n formId,\n formRef,\n context: rhfContext,\n utils,\n Controller: _Controller<TFieldValues>,\n FormSubmitError: FormSubmitError<TFieldValues>,\n };\n\n const FormComponent = config?.FormComponent ?? 'form';\n\n const FormChildrenWrapper =\n config?.FormChildrenWrapper ?? PassthroughChildren;\n\n return (\n <FormComponent\n {...form}\n ref={formRef}\n onSubmit={(e) => void handleSubmit(e)}\n >\n <FormChildrenWrapper {...childrenProps}>\n {utils?.devTool && (\n <LazyDevTool\n props={\n typeof utils.devTool === 'object' ? utils.devTool : undefined\n }\n />\n )}\n\n <Children {...childrenProps} />\n </FormChildrenWrapper>\n </FormComponent>\n );\n}\n\nexport default _Form;\n"],"names":["_Form","formId","formRef","onSubmit","onSubmitError","onSubmitInvalid","Children","form","utils","rhfContext","useFormContext","config","useRhfUtilsClientConfigMaybeContext","handleSubmit","event","handleSubmitValid","error","handleSubmitError","data","FormSubmitError","formSubmitErrors","_a","setCtxErrorsByFormSubmitErrors","childrenProps","_Controller","FormComponent","FormChildrenWrapper","PassthroughChildren","jsx","e","jsxs","LazyDevTool"],"mappings":";;;;;;;;;AA0CA,SAASA,EAGP;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA;AAAA,EAEA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,UAAAC;AAAA;AAAA,EAEA,MAAAC;AAAA,EACA,OAAAC;AACF,GAAgD;AAC9C,QAAMC,IAAaC,KAMbC,IAASC,KAITC,IAAe,OAAOC,MAA4C;AAElE,IAAAN,KAAA,QAAAA,EAAO,yBAAuBM,EAAM,gBAAgB;AAEpD,QAAA;AACF,YAAML,EAAW,aAAaM,GAAmBV,CAAe,EAAES,CAAK;AAAA,aAChEE,GAAO;AACd,MAAAC,EAAkBD,GAAOF,CAAK;AAAA,IAChC;AAAA,EAAA,GAGIC,IAAqB,CACzBG,GACAJ,MAEOX,KAAA,gBAAAA;AAAA,IACLe;AAAA,IACA;AAAA,MACE,QAAAjB;AAAA,MACA,SAAAC;AAAA,MACA,SAASO;AAAA,MACT,OAAAD;AAAA,MACA,iBAAAW;AAAA,IACF;AAAA,IAIAL;AAAA,KAIEG,IAAoB,CACxBD,GACAF,MACG;;AAEH,UAAMM,IACJJ,aAAiBG;AAAA;AAAA,MAEZH,EAA0B;AAAA;AAAA;AAAA,OAE3BK,IAAAV,KAAA,gBAAAA,EAAQ,yBAAR,gBAAAU,EAAA,KAAAV,GAA+BK;AAAA;AAEjC,IAAAI,KACFE,EAA+Bb,GAAYW,CAAgB,GAE7DhB,KAAA,QAAAA;AAAA,MACEY;AAAA,MACA;AAAA,QACE,QAAAf;AAAA,QACA,SAAAC;AAAA,QACA,SAASO;AAAA,QACT,OAAAD;AAAA,MACF;AAAA,MAIAM;AAAA;AAAA,EACF,GAGIS,IAGF;AAAA,IACF,QAAAtB;AAAA,IACA,SAAAC;AAAA,IACA,SAASO;AAAA,IACT,OAAAD;AAAA,IACA,YAAYgB;AAAA,IACZ,iBAAAL;AAAA,EAAA,GAGIM,KAAgBd,KAAA,gBAAAA,EAAQ,kBAAiB,QAEzCe,KACJf,KAAA,gBAAAA,EAAQ,wBAAuBgB;AAG/B,SAAA,gBAAAC;AAAA,IAACH;AAAA,IAAA;AAAA,MACE,GAAGlB;AAAA,MACJ,KAAKL;AAAA,MACL,UAAU,CAAC2B,MAAM,KAAKhB,EAAagB,CAAC;AAAA,MAEpC,UAAA,gBAAAC,EAACJ,GAAqB,EAAA,GAAGH,GACtB,UAAA;AAAA,SAAAf,KAAA,gBAAAA,EAAO,YACN,gBAAAoB;AAAA,UAACG;AAAA,UAAA;AAAA,YACC,OACE,OAAOvB,EAAM,WAAY,WAAWA,EAAM,UAAU;AAAA,UAAA;AAAA,QAExD;AAAA,QAGF,gBAAAoB,EAACtB,GAAU,EAAA,GAAGiB,GAAe;AAAA,MAAA,GAC/B;AAAA,IAAA;AAAA,EAAA;AAGN;"}
1
+ {"version":3,"file":"Form.mjs","sources":["../../../src/form/Form.tsx"],"sourcesContent":["import React from 'react';\nimport type { UseFormHandleSubmit } from 'react-hook-form';\nimport { useFormContext } from 'react-hook-form';\n\nimport type { RhfUtilsFormChildrenWrapperProps } from '@/client/config/RhfUtilsClientConfig';\nimport useRhfUtilsClientConfigMaybeContext from '@/client/config/useRhfUtilsClientConfigContext';\n\nimport LazyDevTool from '@/devtool/LazyDevTool';\n\nimport { FormSubmitError } from '@/submit/error/FormSubmitError';\nimport setCtxErrorsByFormSubmitErrors from '@/submit/error/setCtxErrorsByFormSubmitErrors';\n\nimport PassthroughChildren from '@/utils/PassthroughChildren';\n\nimport _Controller from './_Controller';\nimport type { SafeFieldValues } from './SafeFieldValues';\nimport type { UseRhfUtilsFormChildrenProps } from './UseRhfUtilsFormChildrenProps';\nimport type {\n UseRhfUtilsFormOnSubmitContext,\n UseRhfUtilsFormOnSubmitErrorContext,\n} from './UseRhfUtilsFormOnSubmitContext';\nimport type { UseRhfUtilsFormProps } from './UseRhfUtilsFormProps';\n\nexport type FormChildrenSlots = 'top' | 'bottom';\n\nexport type FormProps<\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n> = {\n formId: string;\n formRef: React.RefObject<HTMLFormElement>;\n} & Pick<\n UseRhfUtilsFormProps<TFieldValues, TTransformedValues>,\n | 'onSubmit'\n | 'onSubmitError'\n | 'onSubmitInvalid'\n //\n | 'Children'\n //\n | 'form'\n | 'utils'\n>;\n\nfunction _Form<\n TFieldValues extends SafeFieldValues,\n TTransformedValues extends SafeFieldValues,\n>({\n formId,\n formRef,\n //\n onSubmit,\n onSubmitError,\n onSubmitInvalid,\n Children,\n //\n form,\n utils,\n}: FormProps<TFieldValues, TTransformedValues>) {\n const rhfContext = useFormContext<\n TFieldValues,\n unknown,\n TTransformedValues\n >();\n\n const config = useRhfUtilsClientConfigMaybeContext();\n\n // handlers\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n // cannot stop propagation in handleSubmitValid, b/c it receives a different event object\n if (utils?.stopSubmitPropagation) event.stopPropagation();\n\n try {\n await rhfContext.handleSubmit(handleSubmitValid, onSubmitInvalid)(event);\n } catch (error) {\n handleSubmitError(error, event);\n }\n };\n\n const handleSubmitValid = ((\n data: TTransformedValues,\n event?: React.BaseSyntheticEvent,\n ) => {\n return onSubmit?.(\n data,\n {\n formId,\n formRef,\n context: rhfContext,\n utils,\n FormSubmitError: FormSubmitError<TFieldValues>,\n } satisfies UseRhfUtilsFormOnSubmitContext<\n TFieldValues,\n TTransformedValues\n >,\n event as React.BaseSyntheticEvent<SubmitEvent>, // `as` required due to conditional generic\n );\n }) as Parameters<UseFormHandleSubmit<TFieldValues, TTransformedValues>>[0];\n\n const handleSubmitError = (\n error: unknown,\n event: React.BaseSyntheticEvent,\n ) => {\n // get `FormSubmitErrors`, if possible\n const formSubmitErrors =\n error instanceof FormSubmitError\n ? // consumer can manually throw FormSubmitError (e.g., manual validation)\n (error as FormSubmitError).errors // `as` to avoid `<any>`\n : // if error is not FormSubmitError, consumer can provide global handler\n config?.onSubmitErrorUnknown?.(error);\n\n if (formSubmitErrors)\n setCtxErrorsByFormSubmitErrors(rhfContext, formSubmitErrors);\n\n onSubmitError?.(\n error,\n {\n formId,\n formRef,\n context: rhfContext,\n utils,\n } satisfies UseRhfUtilsFormOnSubmitErrorContext<\n TFieldValues,\n TTransformedValues\n >,\n event as React.BaseSyntheticEvent<SubmitEvent>, // `as` required due to conditional generic\n );\n };\n\n const childrenProps: UseRhfUtilsFormChildrenProps<\n TFieldValues,\n TTransformedValues\n > = {\n formId,\n formRef,\n context: rhfContext,\n utils,\n Controller: _Controller<TFieldValues>,\n FormSubmitError: FormSubmitError<TFieldValues>,\n };\n\n // children wrapper is not specific to schema (not possible)\n const childrenWrapperProps =\n childrenProps as RhfUtilsFormChildrenWrapperProps;\n\n const FormComponent = config?.FormComponent ?? 'form';\n\n const FormChildrenWrapper =\n config?.FormChildrenWrapper ?? PassthroughChildren;\n\n return (\n <FormComponent\n {...form}\n ref={formRef}\n onSubmit={(e) => void handleSubmit(e)}\n >\n <FormChildrenWrapper {...childrenWrapperProps}>\n {utils?.devTool && (\n <LazyDevTool\n props={\n typeof utils.devTool === 'object' ? utils.devTool : undefined\n }\n />\n )}\n\n <Children {...childrenProps} />\n </FormChildrenWrapper>\n </FormComponent>\n );\n}\n\nexport default _Form;\n"],"names":["_Form","formId","formRef","onSubmit","onSubmitError","onSubmitInvalid","Children","form","utils","rhfContext","useFormContext","config","useRhfUtilsClientConfigMaybeContext","handleSubmit","event","handleSubmitValid","error","handleSubmitError","data","FormSubmitError","formSubmitErrors","_a","setCtxErrorsByFormSubmitErrors","childrenProps","_Controller","childrenWrapperProps","FormComponent","FormChildrenWrapper","PassthroughChildren","jsx","e","jsxs","LazyDevTool"],"mappings":";;;;;;;;;AA2CA,SAASA,EAGP;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA;AAAA,EAEA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,UAAAC;AAAA;AAAA,EAEA,MAAAC;AAAA,EACA,OAAAC;AACF,GAAgD;AAC9C,QAAMC,IAAaC,KAMbC,IAASC,KAITC,IAAe,OAAOC,MAA4C;AAElE,IAAAN,KAAA,QAAAA,EAAO,yBAAuBM,EAAM,gBAAgB;AAEpD,QAAA;AACF,YAAML,EAAW,aAAaM,GAAmBV,CAAe,EAAES,CAAK;AAAA,aAChEE,GAAO;AACd,MAAAC,EAAkBD,GAAOF,CAAK;AAAA,IAChC;AAAA,EAAA,GAGIC,IAAqB,CACzBG,GACAJ,MAEOX,KAAA,gBAAAA;AAAA,IACLe;AAAA,IACA;AAAA,MACE,QAAAjB;AAAA,MACA,SAAAC;AAAA,MACA,SAASO;AAAA,MACT,OAAAD;AAAA,MACA,iBAAAW;AAAA,IACF;AAAA,IAIAL;AAAA,KAIEG,IAAoB,CACxBD,GACAF,MACG;;AAEH,UAAMM,IACJJ,aAAiBG;AAAA;AAAA,MAEZH,EAA0B;AAAA;AAAA;AAAA,OAE3BK,IAAAV,KAAA,gBAAAA,EAAQ,yBAAR,gBAAAU,EAAA,KAAAV,GAA+BK;AAAA;AAEjC,IAAAI,KACFE,EAA+Bb,GAAYW,CAAgB,GAE7DhB,KAAA,QAAAA;AAAA,MACEY;AAAA,MACA;AAAA,QACE,QAAAf;AAAA,QACA,SAAAC;AAAA,QACA,SAASO;AAAA,QACT,OAAAD;AAAA,MACF;AAAA,MAIAM;AAAA;AAAA,EACF,GAGIS,IAGF;AAAA,IACF,QAAAtB;AAAA,IACA,SAAAC;AAAA,IACA,SAASO;AAAA,IACT,OAAAD;AAAA,IACA,YAAYgB;AAAA,IACZ,iBAAAL;AAAA,EAAA,GAIIM,IACJF,GAEIG,KAAgBf,KAAA,gBAAAA,EAAQ,kBAAiB,QAEzCgB,KACJhB,KAAA,gBAAAA,EAAQ,wBAAuBiB;AAG/B,SAAA,gBAAAC;AAAA,IAACH;AAAA,IAAA;AAAA,MACE,GAAGnB;AAAA,MACJ,KAAKL;AAAA,MACL,UAAU,CAAC4B,MAAM,KAAKjB,EAAaiB,CAAC;AAAA,MAEpC,UAAA,gBAAAC,EAACJ,GAAqB,EAAA,GAAGF,GACtB,UAAA;AAAA,SAAAjB,KAAA,gBAAAA,EAAO,YACN,gBAAAqB;AAAA,UAACG;AAAA,UAAA;AAAA,YACC,OACE,OAAOxB,EAAM,WAAY,WAAWA,EAAM,UAAU;AAAA,UAAA;AAAA,QAExD;AAAA,QAGF,gBAAAqB,EAACvB,GAAU,EAAA,GAAGiB,GAAe;AAAA,MAAA,GAC/B;AAAA,IAAA;AAAA,EAAA;AAGN;"}
@@ -1,7 +1,6 @@
1
1
  import { UseFormProps } from 'react-hook-form';
2
2
  import { FlatFieldErrorsOutputConfig } from '../../errors/flat/context/FlatFieldErrorsOutputConfig';
3
3
  import { RhfUtilsFormOptions } from '../../form/RhfUtilsFormOptions';
4
- import { SafeFieldValues } from '../../form/SafeFieldValues';
5
4
  import { UseRhfUtilsFormChildrenProps } from '../../form/UseRhfUtilsFormChildrenProps';
6
5
  import { FormSubmitErrors } from '../../submit/error/FormSubmitErrors';
7
6
 
@@ -41,11 +40,13 @@ export type RhfUtilsClientConfig = {
41
40
  /**
42
41
  * Wrap all form bodies with your own hooks, components, etc.
43
42
  *
43
+ * (NOTE: not schema-typed as not possible at this level)
44
+ *
44
45
  * Use cases:
45
46
  * - custom hooks/behaviors based on `options`
46
47
  * - shared header, footer
47
48
  */
48
- FormChildrenWrapper?: <TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>(props: React.PropsWithChildren<UseRhfUtilsFormChildrenProps<TFieldValues, TTransformedValues>>) => React.ReactNode;
49
+ FormChildrenWrapper?: (props: RhfUtilsFormChildrenWrapperProps) => React.ReactNode;
49
50
  /**
50
51
  * Global submit error handler when/if submit handler throws an error other than {@link FormSubmitError}.
51
52
  *
@@ -64,3 +65,7 @@ export type RhfUtilsClientConfig = {
64
65
  output?: FlatFieldErrorsOutputConfig;
65
66
  };
66
67
  };
68
+ /**
69
+ * Non-schema-typed version of `UseRhfUtilsFormChildrenProps` for global config.
70
+ */
71
+ export type RhfUtilsFormChildrenWrapperProps = React.PropsWithChildren<UseRhfUtilsFormChildrenProps>;
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.132",
5
+ "version": "0.0.134",
6
6
  "description": "Integration utilities for react-hook-form.",
7
7
  "type": "module",
8
8
  "sideEffects": false,