@paragrav/rhf-utils 0.60.0 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +57 -96
  2. package/dist/dts/_exports/relay.d.ts +7 -8
  3. package/dist/dts/_exports/types.d.ts +1 -0
  4. package/dist/dts/client/config/RhfUtilsClientConfigType.d.ts +8 -4
  5. package/dist/dts/errors/flat/getFlatFieldErrors.d.ts +5 -1
  6. package/dist/dts/form/RhfUtilsFormComponentPropsType.d.ts +2 -6
  7. package/dist/dts/form/UseRhfUtilsFormChildrenPropsType.d.ts +2 -2
  8. package/dist/dts/form/context/utils/LastSubmitStateType.d.ts +1 -0
  9. package/dist/dts/form/context/utils/{RhfUtilsContextPropsType.d.ts → RhfUtilsContextType.d.ts} +3 -2
  10. package/dist/dts/form/context/utils/useRhfUtilsContext.d.ts +4 -4
  11. package/dist/dts/form/defaults/form/useRhfUtilsFormResolvedFormProps.d.ts +10 -10
  12. package/dist/dts/form/providers/RhfUtilsFormProviders.d.ts +1 -1
  13. package/dist/dts/form/providers/RhfUtilsFormProvidersPropsType.d.ts +2 -0
  14. package/dist/dts/form/relay/FormRelayOptions.d.ts +16 -0
  15. package/dist/dts/form/{state/relay/FormStateRelayContextProvider.d.ts → relay/context/FormRelayContextProvider.d.ts} +1 -1
  16. package/dist/dts/form/relay/context/useFormRelayContext.d.ts +12 -0
  17. package/dist/dts/form/relay/context/utils.d.ts +4 -0
  18. package/dist/dts/form/relay/get/FormRelayGroupType.d.ts +16 -0
  19. package/dist/dts/form/relay/get/grouper/context/hooks.d.ts +8 -0
  20. package/dist/dts/form/relay/get/grouper/context/index.d.ts +5 -0
  21. package/dist/dts/form/relay/get/grouper/context/provider.d.ts +9 -0
  22. package/dist/dts/form/relay/get/grouper/useFirstFormStateGroup.d.ts +9 -0
  23. package/dist/dts/form/relay/get/useFormRelay.d.ts +13 -0
  24. package/dist/dts/form/relay/set/FormRelaySetter.d.ts +6 -0
  25. package/dist/dts/form/relay/set/useFormRelaySet.d.ts +2 -0
  26. package/dist/dts/form/relay/types.d.ts +12 -0
  27. package/dist/dts/form/with-handlers-and-children/RhfUtilsFormProps.d.ts +5 -1
  28. package/dist/dts/form/with-handlers-and-children/_useHandleSubmit.d.ts +1 -1
  29. package/dist/dts/form/with-providers/RhfUtilsFormWithProviders.d.ts +1 -1
  30. package/dist/dts/submit/UseRhfUtilsFormOnSubmitContextType.d.ts +3 -3
  31. package/dist/dts/submit/last-error/useLastSubmitErrorContextWith.d.ts +1 -1
  32. package/dist/esm/FormRelaySetter.mjs +140 -0
  33. package/dist/esm/index.mjs +203 -202
  34. package/dist/esm/relay.mjs +71 -209
  35. package/package.json +17 -17
  36. package/dist/dts/form/RhfUtilsFormStateWithUtilsType.d.ts +0 -7
  37. package/dist/dts/form/state/relay/FormStateRelayedAggregatedType.d.ts +0 -10
  38. package/dist/dts/form/state/relay/FormStateRelayedItemType.d.ts +0 -11
  39. package/dist/dts/form/state/relay/FormStateRelayedOptionsType.d.ts +0 -20
  40. package/dist/dts/form/state/relay/FormStateRelayedType.d.ts +0 -3
  41. package/dist/dts/form/state/relay/pull/hooks.d.ts +0 -31
  42. package/dist/dts/form/state/relay/push/FormStateRelayPusher.d.ts +0 -4
  43. package/dist/dts/form/state/relay/push/useFormStateRelayPusher.d.ts +0 -3
  44. package/dist/dts/form/state/relay/useFormStateRelayContext.d.ts +0 -20
  45. package/dist/dts/form/state/relay/utils.d.ts +0 -4
  46. package/dist/esm/getFlatFieldErrors.mjs +0 -55
package/README.md CHANGED
@@ -9,11 +9,11 @@ Integration and utility library for [react-hook-form](https://www.react-hook-for
9
9
  - TypeScript-first
10
10
  - global configuration (🔗 [`RhfUtilsClientConfig`](#config) section)
11
11
  - RHF (`UseFormProps`) and utilities (`RhfUtilsFormOptions`) options defaults
12
- - inject your own hooks and UI (`FormComponent`)
12
+ - inject your own hooks and UI (`FormChildren`)
13
13
  - server error transformation (`onSubmitErrorUnknown`) ✨
14
14
  - handle cancel prompt (`useCanFormBeCancelled`) ✨
15
15
  - RHF `FormState.errors` logging/throwing (`RhfUtilsClientConfig.fieldErrors`) ✨
16
- - form-level configuration (🔗 [`RhfUtilsZodForm`](#form) section)
16
+ - form-level configuration (🔗 [`RhfUtilsZodForm`](#form-with-providers) section)
17
17
  - RHF and utilities options overrides
18
18
  - extendable utilities options type (`RhfUtilsFormOptions`)
19
19
  - throw error (`FormSubmitError`) in submit handler to add errors to RHF context and fail submit
@@ -21,7 +21,7 @@ Integration and utility library for [react-hook-form](https://www.react-hook-for
21
21
  - context injection for children (`RhfUtilsZodForm.Children`), including:
22
22
  - formId, formRef, RHF context, utilities options
23
23
  - schema-typed Controller component and FormSubmitError class
24
- - form state relay (🔗 [`FormStateRelayContextProvider`](#form-state-relay) section) ✨
24
+ - form state relay (🔗 [`FormRelayContextProvider`](#form-state-relay) section) ✨
25
25
  - access specific form's state from outside that form/provider
26
26
  - assign forms into groups and watch collectively
27
27
  - simpler/flatter `FieldErrors` structure (🔗 [`FlatFieldErrors`](#flatfielderrors) section)
@@ -44,7 +44,7 @@ yarn add @paragrav/rhf-utils # yarn
44
44
  - 🔗 [Config](#config) (`RhfUtilsClientConfig`): define your global config (optional)
45
45
  - 🔗 [Provider](#config-provider) (`RhfUtilsClientConfigProvider`): add to your global stack
46
46
  - 🔗 [Form With Providers](#form-with-providers) (`RhfUtilsZodFormWithProviders`): use as form component
47
- - 🔗 [Form State Relay](#form-state-relay) (`FormStateRelayContextProvider`): relay form state
47
+ - 🔗 [Form State Relay](#form-state-relay) (`FormRelayContextProvider`): relay form state
48
48
 
49
49
  ## Config
50
50
 
@@ -72,14 +72,15 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
72
72
  },
73
73
 
74
74
  // optional form component to use (defaults to primitive HTML form)
75
- // also, is used to inject your own hooks and components
76
- // for all RhfUtilsZodForm instances
77
- FormComponent: (
75
+ FormComponent: Form.Root,
76
+
77
+ // inject your own hooks and components
78
+ // into all RhfUtilsZodForm instances
79
+ FormChildren: (
78
80
  // RhfUtilsFormComponentProps
79
81
  {
80
- formProps, // computed form props
81
82
  formId, // unique id string
82
- formRef, // ref
83
+ formRef, // form element ref
83
84
  context, // rhf UseFormReturn (without proxy `formState`)
84
85
  options, // RhfUtilsFormOptions (with any custom props)
85
86
  Controller, // rhf controller (SafeFieldValues-typed; no schema at this level)
@@ -96,13 +97,13 @@ export const rhfUtilsClientConfig: RhfUtilsClientConfig = {
96
97
  });
97
98
 
98
99
  return (
99
- <Form.Root {...formProps} ref={formRef}>
100
+ <>
100
101
  {/* RhfUtilsZodForm.Children "outlet" (see "Component Hierarchy" section) */}
101
102
  {children}
102
103
 
103
104
  {/* root errors list */}
104
105
  <RootErrorsList />
105
- </Form.Root>
106
+ </>
106
107
  );
107
108
  },
108
109
 
@@ -179,17 +180,18 @@ Currently, only `zod` schemas are supported.
179
180
  // cancel handler (passed to `Children` below)
180
181
  // execution routed through `RhfUtilsClientConfig.useCanFormBeCancelled`, if provided
181
182
  onCancel={handleCancel}
182
- // submit handlers
183
+ // SUBMIT HANDLERS
184
+ // invariants
183
185
  onBeforeSubmitInvariants={async (
184
186
  { input, output, api }, // schema input (form values), output; api data (via getApiData)
185
187
  context, // UseRhfUtilsFormOnSubmitContext (id, ref, rhf context (without proxy formState), utils options, schema-typed FormSubmitError class)
186
188
  event, // SubmitEvent
187
189
  ) => [
188
- [
189
- 'passwordConfirm', // type safe
190
- 'Passwords must match.',
191
- data.password === data.passwordConfirm,
192
- ],
190
+ {
191
+ field: 'passwordConfirm', // type safe
192
+ message: 'Passwords must match.',
193
+ valid: data.password === data.passwordConfirm,
194
+ },
193
195
  ]}
194
196
  onBeforeSubmit={({ input, output, api }, context, event) => {
195
197
  if (!isValid(input.email))
@@ -326,7 +328,7 @@ Sometimes you need to control the nesting of the Form element. For example, to a
326
328
  </aside>
327
329
  ```
328
330
 
329
- For similar pattern, especially across more than one form, see [Form State Relay](#form-state-relay) section.
331
+ To access forms' state outside its respective context, including in aggregate across more than one form, see [Form State Relay](#form-state-relay) section.
330
332
 
331
333
  ## `FormSubmitError`
332
334
 
@@ -382,7 +384,9 @@ type RhfUtilsFormOptions = {
382
384
  };
383
385
  ```
384
386
 
385
- If you need access to options deeper in your component structure, use `useRhfUtilsContext` to receive `RhfUtilsContext` object, which includes `formId`, `formRef`, and `options` settings.
387
+ If you need access to options deeper in your component structure, use `useRhfUtilsContext` to receive `RhfUtilsContext` object, which includes `formId`, `formRef`, `options`, and `lastSubmitStateRef`.
388
+
389
+ `lastSubmitStateRef` (a ref with possible value of `null | 'submitting' | 'success' | 'error'`) conveys current submit state via ref -- i.e., without needing to wait for next render cycle. If your form navigates away via `onSubmitSuccess`, RHF's `useFormContext` still shows form as `isDirty` and `isSubmitting`, which makes it difficult to distinguish from a user-initiated navigation before form is submitted successfully.
386
390
 
387
391
  Use `useRhfUtilsContextRequestSubmit` hook to get `requestSubmit` function for current form ref in context. This is useful when you need to trigger form submission programatically.
388
392
 
@@ -396,7 +400,7 @@ import '@paragrav/rhf-utils';
396
400
  declare module '@paragrav/rhf-utils' {
397
401
  export interface Register {
398
402
  RhfUtilsFormOptions: {
399
- /** Custom props for your custom options/hooks/behaviors. */
403
+ /** Custom props for your custom options/hooks/behaviors per form instance. */
400
404
  enableMyPrompter?: boolean;
401
405
  enableMyOptionalFormHook?: boolean;
402
406
  configMyOptionalFormHook?: MyCustomFormHookConfig;
@@ -405,99 +409,56 @@ declare module '@paragrav/rhf-utils' {
405
409
  }
406
410
  ```
407
411
 
408
- ## <a id="form-state-relay" /> Form State Relay _(~1.2kB min+gzip)_
412
+ ## <a id="form-state-relay"></a> Form State Relay
409
413
 
410
- Sometimes you need to access one or more forms' state outside the form (and its providers).
414
+ Sometimes you need to access one or more forms' state outside its respective context.
411
415
 
412
- ### Single form state
413
-
414
- Use case: display a form's errors (or any other state) outside form and its context.
415
-
416
- ```tsx
417
- <FormStateRelayContextProvider> // relay provider
418
- <ReactHookForm.FormProvider> // rhf provider
419
- <FormStateRelayPusher /> // push form state
420
- <ReactHookForm.FormProvider>
421
-
422
- <WatchOutsideFormContext /> // watch form state
423
- </FormStateRelayContextProvider>;
424
- ```
425
-
426
- Push can be configured via `FormStateRelayPusher` component or `useFormStateRelayPush` hook with `FormStateRelayPushOptions` options.
416
+ `FormRelayContextProvider` is included by default, but form's state is only relayed with opted-in. Configuration is done per form instance via `relay` prop.
427
417
 
428
418
  ```ts
429
- type FormStateRelayPushOptions = {
430
- group?: string | string[]; // assign group(s) to watch multiple forms in aggregate
431
- flaggedState?: {
432
- isMounted?: true; // flag form when mounted -- e.g., forms that are hidden by default
433
- };
434
- };
435
- ```
436
-
437
- ```tsx
438
- function WatchOutsideFormContext() {
439
- // FormStateWithUtils (either via RHF -- when requested within form context -- or relay when not)
440
- const formState = useFormStateWithUtilsViaRhfOrRelay();
441
- }
419
+ type FormRelayOptions = {
420
+ /**
421
+ * Determines what part of RHF's form state is relayed.
422
+ * Also acts to activate RHF proxy values.
423
+ */
424
+ select: (formState: FormState<SafeFieldValues>) => FormRelayStateSelected;
442
425
 
443
- // when watching a single form, original RHF FormState with generally-typed SafeFieldValues
444
- type FormStateRelayed = FormState<SafeFieldValues>;
426
+ /**
427
+ * Arbitrary group name(s) for this form.
428
+ * Think of it like class or category names.
429
+ * (e.g., "parent" or "children")
430
+ */
431
+ groups?: string[];
432
+ };
445
433
  ```
446
434
 
447
- The `useFormStateWithUtilsViaRhfOrRelay` hook uses `useFormStateRelayPullOnlyOrThrow` internally. It provides additional naivety when consumer doesn't know which context between RHF or Relay is present. (This is useful when building base components -- e.g., buttons -- which may exist outside of form context.)
435
+ There are two main ways to get form state that has been relayed.
448
436
 
449
- ### Multiple forms
437
+ ### Get form relay by id
450
438
 
451
- Use cases:
439
+ You can retrieve a singular form's relay state via `useFormRelayId(formId)`. This will return a `FormRelay` object with that form's selected state (`FormRelayStateSelected`), options (`FormRelayOptions`), and utils (`RhfUtilsContext`).
452
440
 
453
- - disable parent form when ANY child is "flagged" (i.e., dirty)
454
- - disable ALL children when parent is "flagged" (i.e., submitting)
455
- - confirm navigation when ANY mounted form is "flagged" (i.e., dirty)
441
+ ### Get form relay by group
456
442
 
457
- ```tsx
458
- function ParentForm() {
459
- const childrenFormState = useFormStateRelayWatchGroup('children'); // FormStateRelayedAggregated
460
-
461
- return (
462
- <ReactHookForm.FormProvider>
463
- <FormStateRelayPusher formId="parent" /> // pusher
464
- <input type="submit" disabled={childrenFormState.isDirty} />
465
- </ReactHookForm.FormProvider>
466
- );
467
- }
443
+ When retrieving by group, state is merged into a `FormRelayGroup` object (and no options or utils are provided, as these are form-specific).
468
444
 
469
- function ChildForm() {
470
- const parentFormState = useFormStateRelayWatchId('parent'); // FormStateRelayed
445
+ Use `useFormRelayGroup(callback)` and providing a callback that is is supplied with options (`FormRelayOptions`) and utils (`RhfUtilsContext`) of each form registered to relay, in order for you to determine whether it should be included in this arbitrary "group".
471
446
 
472
- return (
473
- <ReactHookForm.FormProvider>
474
- <FormStateRelayPusher group="children" /> // pusher
475
- <input type="submit" disabled={parentFormState.isSubmitting} />
476
- </ReactHookForm.FormProvider>
477
- );
478
- }
447
+ You can also use `FormRelayGrouperContextProvider` if you want to make this group accessible via naive hook.
479
448
 
480
- type FormStateRelayedAggregated = FormStateRelayed & {
481
- // object values reduced to booleans for non-empty-ness
482
- dirtyFields: boolean;
483
- touchedFields: boolean;
484
- validatingFields: boolean;
485
- error: boolean;
486
- // composites
487
- isSubmitUnsuccessful: boolean;
488
- isMountedFlagged: boolean; // via RelayedFormOptions['flaggedState']['isMounted']
489
- };
449
+ ```tsx
450
+ <FormRelayGrouperContextProvider
451
+ predicate={({ options, utils }) =>
452
+ !!options?.groups?.includes("parent") // find specific group
453
+ }
454
+ >
455
+ {(state: FormRelayGroup) => ()}
456
+ </FormRelayGrouperContextProvider>
490
457
  ```
491
458
 
492
- You can also aggregate any (i.e., all) forms via `useFormStateRelayPullAny`, which returns `FormStateRelayedAggregated` as well.
459
+ Alternatively, instead render callback, you can use `useFormRelayGrouper`.
493
460
 
494
- ```tsx
495
- <FormStateRelayContextProvider>
496
- <ParentForm />
497
- <ChildForm />
498
- <Child2Form />
499
- </FormStateRelayContextProvider>
500
- ```
461
+ If you want to build some components to be independent of any one specific context -- i.e., RHF's context, `FormRelayGrouperContext`, or `FormRelayContext` -- you can use `useFirstFormStateGroup` to get `FormRelayGroup` from nearest available context. (If RHF's context is found, its singular state is transformed to `FormRelayGroup`.)
501
462
 
502
463
  ## Field Errors
503
464
 
@@ -1,8 +1,7 @@
1
- export { FormStateRelayContextProvider } from '../form/state/relay/FormStateRelayContextProvider';
2
- export type { FormStateRelayedAggregated } from '../form/state/relay/FormStateRelayedAggregatedType';
3
- export type { FormStateRelayedItemWithUtils } from '../form/state/relay/FormStateRelayedItemType';
4
- export type { FormStateRelayedOptions } from '../form/state/relay/FormStateRelayedOptionsType';
5
- export type { FormStateRelayed } from '../form/state/relay/FormStateRelayedType';
6
- export { useFormStateRelayPullAny, useFormStateRelayPullById, useFormStateRelayPullGroup, useFormStateRelayPullOnlyOrThrow, useFormStateWithUtilsViaRhfOrRelay, } from '../form/state/relay/pull/hooks';
7
- export { FormStateRelayPusher } from '../form/state/relay/push/FormStateRelayPusher';
8
- export { useFormStateRelayPusher } from '../form/state/relay/push/useFormStateRelayPusher';
1
+ export { FormRelayContextProvider } from '../form/relay/context/FormRelayContextProvider';
2
+ export type { FormRelayGroup } from '../form/relay/get/FormRelayGroupType';
3
+ export { useFirstFormStateGroup } from '../form/relay/get/grouper/useFirstFormStateGroup';
4
+ export { useFormRelayGroup, useFormRelayId, } from '../form/relay/get/useFormRelay';
5
+ export { FormRelaySetter } from '../form/relay/set/FormRelaySetter';
6
+ export { useFormRelaySet } from '../form/relay/set/useFormRelaySet';
7
+ export type { FormRelay, FormRelayStateSelected } from '../form/relay/types';
@@ -4,3 +4,4 @@ export type * from './relay';
4
4
  export type * from './submit';
5
5
  export type * from './trpc';
6
6
  export type * from './zod';
7
+ export type { FlatFieldErrors } from '../errors/flat/types';
@@ -15,15 +15,19 @@ export type RhfUtilsClientConfig = {
15
15
  */
16
16
  defaults?: UseRhfUtilsFormGlobalDefaults;
17
17
  /**
18
- * Supply your own `<form>` component. (By default, a native {@link HTMLFormElement} is used.)
18
+ * Supply your own `<form>` component.
19
19
  *
20
- * @description
20
+ * (By default, a native {@link HTMLFormElement} is used.)
21
+ */
22
+ FormComponent?: React.FC<React.PropsWithChildren<React.HTMLAttributes<HTMLFormElement>>>;
23
+ /**
24
+ * Inject your own hooks, components, etc., into every form instance.
21
25
  *
22
- * Can be used to inject your own hooks, components, etc.
26
+ * @description
23
27
  *
24
28
  * (NOTE: context params are not schema-typed as not possible at this level.)
25
29
  */
26
- FormComponent?: React.FC<React.PropsWithChildren<RhfUtilsFormComponentProps>>;
30
+ FormChildren?: React.FC<React.PropsWithChildren<RhfUtilsFormComponentProps>>;
27
31
  /**
28
32
  * A hook that returns a callback that determines whether form can be cancelled at event-time.
29
33
  *
@@ -1,4 +1,5 @@
1
1
  import { FieldError, FieldErrors } from 'react-hook-form';
2
+ import { SafeFieldValues } from '../../form/rhf/SafeFieldValuesType';
2
3
  import { FlatFieldErrors } from './types';
3
4
  /**
4
5
  * Get {@link FlatFieldErrors} from {@link FieldErrors}.
@@ -28,4 +29,7 @@ export declare const getFlatFieldErrors: (errors: FieldErrors) => FlatFieldError
28
29
  * iow: dot [?: non-capturing]("type" | "message")[\b word boundary][$ end of string]
29
30
  */
30
31
  export declare const regexMaybeFieldErrorLeafNodeSuffix: RegExp;
31
- export declare const getFlatFieldErrorsSansRef: (errors: FieldErrors) => Record<string, Omit<FieldError, "ref">>;
32
+ export type FieldErrorsSansRef<TFieldValues extends SafeFieldValues = SafeFieldValues> = Record<keyof TFieldValues | 'root', Partial<Pick<FieldError, 'message' | 'type'>> & {
33
+ hasRef: boolean;
34
+ }>;
35
+ export declare const getFlatFieldErrorsSansRef: <TFieldValues extends SafeFieldValues>(errors: FieldErrors<TFieldValues>) => FieldErrorsSansRef<TFieldValues>;
@@ -1,17 +1,13 @@
1
1
  import { UseFormReturn } from 'react-hook-form';
2
2
  import { FormSubmitError } from '../submit/error/FormSubmitError';
3
3
  import { _Controller } from './_Controller';
4
- import { RhfUtilsContextProps } from './context/utils/RhfUtilsContextPropsType';
5
- import { UseRhfUtilsFormInstanceFormProps } from './defaults/form/UseRhfUtilsFormInstanceFormProps';
4
+ import { RhfUtilsContext } from './context/utils/RhfUtilsContextType';
6
5
  import { SafeFieldValues } from './rhf/SafeFieldValuesType';
7
6
  /**
8
7
  * RhfUtilsClientConfig's FormComponent props.
9
8
  */
10
- export type RhfUtilsFormComponentProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = TFieldValues> = RhfUtilsContextProps & {
9
+ export type RhfUtilsFormComponentProps<TFieldValues extends SafeFieldValues = SafeFieldValues, TTransformedValues extends SafeFieldValues = TFieldValues> = RhfUtilsContext & {
11
10
  rhf: UseFormReturn<TFieldValues, unknown, TTransformedValues>;
12
- formProps: UseRhfUtilsFormInstanceFormProps & {
13
- onSubmit: NonNullable<React.PropsWithoutRef<React.JSX.IntrinsicElements['form']>['onSubmit']>;
14
- };
15
11
  Controller: typeof _Controller<TFieldValues>;
16
12
  FormSubmitError: typeof FormSubmitError<TFieldValues>;
17
13
  };
@@ -2,7 +2,7 @@ import { UseFormReturn } from 'react-hook-form';
2
2
  import { FormSubmitError } from '../submit/error/FormSubmitError';
3
3
  import { MaybePromise } from '../utils/types';
4
4
  import { _Controller } from './_Controller';
5
- import { RhfUtilsContextProps } from './context/utils/RhfUtilsContextPropsType';
5
+ import { RhfUtilsContext } from './context/utils/RhfUtilsContextType';
6
6
  import { RhfUtilsFormOptions } from './options/RhfUtilsFormOptionsType';
7
7
  import { SafeFieldValues } from './rhf/SafeFieldValuesType';
8
8
  /**
@@ -10,7 +10,7 @@ import { SafeFieldValues } from './rhf/SafeFieldValuesType';
10
10
  *
11
11
  * (Consider keeping shape in line with `UseRhfUtilsFormOnSubmitProps` and `UseRhfUtilsFormReturn`.)
12
12
  */
13
- export type UseRhfUtilsFormChildrenProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TProps = undefined> = RhfUtilsContextProps & {
13
+ export type UseRhfUtilsFormChildrenProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TProps = undefined> = RhfUtilsContext & {
14
14
  rhf: UseFormReturn<TFieldValues, unknown, TTransformedValues>;
15
15
  options: RhfUtilsFormOptions;
16
16
  Controller: typeof _Controller<TFieldValues>;
@@ -0,0 +1 @@
1
+ export type LastSubmitState = null | 'submitting' | 'success' | 'error';
@@ -1,11 +1,12 @@
1
1
  import { RefObject } from 'react';
2
+ import { LastSubmitState } from './LastSubmitStateType';
2
3
  import { RhfUtilsContextProviderProps } from './RhfUtilsContextProvider';
3
- export type RhfUtilsContextProps = RhfUtilsContextProviderProps & {
4
+ export type RhfUtilsContext = RhfUtilsContextProviderProps & {
4
5
  /**
5
6
  * Current form submit state.
6
7
  *
7
8
  * e.g., can be used to determine whether safe to redirect (navigate) without prompter.
8
9
  * Unlike RHF's `isSubmitSuccessful`, is computed/set immediately after `onSubmit` succeeds/fails.
9
10
  */
10
- lastSubmitStateRef: RefObject<null | 'submitting' | 'success' | 'error'>;
11
+ lastSubmitStateRef: RefObject<LastSubmitState>;
11
12
  };
@@ -1,5 +1,5 @@
1
- import { RhfUtilsContextProps } from './RhfUtilsContextPropsType';
2
- declare const _RhfUtilsContextProvider: import('react').Provider<RhfUtilsContextProps | undefined>, useRhfUtilsContext: () => import('./RhfUtilsContextProvider').RhfUtilsContextProviderProps & {
3
- lastSubmitStateRef: import('react').RefObject<null | "submitting" | "success" | "error">;
4
- }, useRhfUtilsMaybeContext: () => RhfUtilsContextProps | undefined;
1
+ import { RhfUtilsContext } from './RhfUtilsContextType';
2
+ declare const _RhfUtilsContextProvider: import('react').Provider<RhfUtilsContext | undefined>, useRhfUtilsContext: () => import('./RhfUtilsContextProvider').RhfUtilsContextProviderProps & {
3
+ lastSubmitStateRef: import('react').RefObject<import('./LastSubmitStateType').LastSubmitState>;
4
+ }, useRhfUtilsMaybeContext: () => RhfUtilsContext | undefined;
5
5
  export { _RhfUtilsContextProvider, useRhfUtilsContext, useRhfUtilsMaybeContext, };
@@ -30,7 +30,7 @@ export declare const useRhfUtilsFormResolvedFormProps: (formProps: UseRhfUtilsFo
30
30
  inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
31
31
  nonce?: string | undefined | undefined;
32
32
  tabIndex?: number | undefined | undefined;
33
- onChange?: import('react').FormEventHandler<HTMLFormElement> | undefined;
33
+ onChange?: import('react').ChangeEventHandler<HTMLFormElement, Element> | undefined;
34
34
  onBlur?: import('react').FocusEventHandler<HTMLFormElement> | undefined;
35
35
  key?: import('react').Key | null | undefined;
36
36
  autoComplete?: string | undefined | undefined;
@@ -139,16 +139,16 @@ export declare const useRhfUtilsFormResolvedFormProps: (formProps: UseRhfUtilsFo
139
139
  onFocus?: import('react').FocusEventHandler<HTMLFormElement> | undefined;
140
140
  onFocusCapture?: import('react').FocusEventHandler<HTMLFormElement> | undefined;
141
141
  onBlurCapture?: import('react').FocusEventHandler<HTMLFormElement> | undefined;
142
- onChangeCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
142
+ onChangeCapture?: import('react').ChangeEventHandler<HTMLFormElement, Element> | undefined;
143
143
  onBeforeInput?: import('react').InputEventHandler<HTMLFormElement> | undefined;
144
- onBeforeInputCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
145
- onInput?: import('react').FormEventHandler<HTMLFormElement> | undefined;
146
- onInputCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
147
- onReset?: import('react').FormEventHandler<HTMLFormElement> | undefined;
148
- onResetCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
149
- onSubmitCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
150
- onInvalid?: import('react').FormEventHandler<HTMLFormElement> | undefined;
151
- onInvalidCapture?: import('react').FormEventHandler<HTMLFormElement> | undefined;
144
+ onBeforeInputCapture?: import('react').InputEventHandler<HTMLFormElement> | undefined;
145
+ onInput?: import('react').InputEventHandler<HTMLFormElement> | undefined;
146
+ onInputCapture?: import('react').InputEventHandler<HTMLFormElement> | undefined;
147
+ onReset?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
148
+ onResetCapture?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
149
+ onSubmitCapture?: import('react').SubmitEventHandler<HTMLFormElement> | undefined;
150
+ onInvalid?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
151
+ onInvalidCapture?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
152
152
  onLoad?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
153
153
  onLoadCapture?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
154
154
  onError?: import('react').ReactEventHandler<HTMLFormElement> | undefined;
@@ -2,5 +2,5 @@ import { default as React } from 'react';
2
2
  import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
3
3
  import { RhfUtilsFormProvidersProps } from './RhfUtilsFormProvidersPropsType';
4
4
  type Props<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues> = React.PropsWithChildren<RhfUtilsFormProvidersProps<TFieldValues, TTransformedValues>>;
5
- export declare function RhfUtilsFormProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, rhf, resolver, defaultValues, options, children, }: Props<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
5
+ export declare function RhfUtilsFormProviders<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ formId, rhf, resolver, defaultValues, options, relay, children, }: Props<TFieldValues, TTransformedValues>): import("react/jsx-runtime").JSX.Element;
6
6
  export {};
@@ -1,5 +1,6 @@
1
1
  import { Resolver, UseFormProps } from 'react-hook-form';
2
2
  import { RhfUtilsFormOptions } from '../options/RhfUtilsFormOptionsType';
3
+ import { FormRelayOptions } from '../relay/FormRelayOptions';
3
4
  import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
4
5
  import { RhfUseFormInstanceProps } from '../rhf/UseFormPropsType';
5
6
  /**
@@ -12,4 +13,5 @@ export type RhfUtilsFormProvidersProps<TFieldValues extends SafeFieldValues, TTr
12
13
  rhf?: RhfUseFormInstanceProps<TFieldValues, TTransformedValues>;
13
14
  defaultValues?: UseFormProps<TFieldValues, unknown, TTransformedValues>['defaultValues'];
14
15
  options?: RhfUtilsFormOptions;
16
+ relay?: FormRelayOptions;
15
17
  };
@@ -0,0 +1,16 @@
1
+ import { FormState } from 'react-hook-form';
2
+ import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
3
+ import { FormRelayStateSelected } from './types';
4
+ export type FormRelayOptions = {
5
+ /**
6
+ * Determines what part of RHF's form state is relayed.
7
+ * Also acts to activate RHF proxy values.
8
+ */
9
+ select: (formState: FormState<SafeFieldValues>) => FormRelayStateSelected;
10
+ /**
11
+ * Arbitrary group name(s) for this form.
12
+ * Think of it like class or category names.
13
+ * (e.g., "parent" or "children")
14
+ */
15
+ groups?: string[];
16
+ };
@@ -1,4 +1,4 @@
1
1
  import { default as React } from 'react';
2
2
  type Props = React.PropsWithChildren;
3
- export declare const FormStateRelayContextProvider: React.FC<Props>;
3
+ export declare const FormRelayContextProvider: React.FC<Props>;
4
4
  export {};
@@ -0,0 +1,12 @@
1
+ import { RhfUtilsContext } from '../../context/utils/RhfUtilsContextType';
2
+ import { FormRelayOptions } from '../FormRelayOptions';
3
+ import { FormRelay, FormRelayStateSelected } from '../types';
4
+ export type FormsRelayed = Record<string, // form id
5
+ FormRelay>;
6
+ export type FormRelayContext = {
7
+ add: (state: FormRelayStateSelected, utils: RhfUtilsContext, options: FormRelayOptions) => void;
8
+ update: (id: string, state: FormRelayStateSelected) => void;
9
+ remove: (id: string) => void;
10
+ state: FormsRelayed;
11
+ };
12
+ export declare const _FormRelayContextProvider: import('react').Provider<FormRelayContext | undefined>, useFormRelayContext: () => FormRelayContext;
@@ -0,0 +1,4 @@
1
+ import { FormRelayGroup } from '../get/FormRelayGroupType';
2
+ import { FormRelayStateSelected } from '../types';
3
+ /** Condense list of form states to singular booleans. */
4
+ export declare const getFormRelayedAggregatedByRelayedItem: (formStates: FormRelayStateSelected[]) => FormRelayGroup;
@@ -0,0 +1,16 @@
1
+ import { FormState } from 'react-hook-form';
2
+ import { SafeFieldValues } from '../../rhf/SafeFieldValuesType';
3
+ export type FormRelayGroup = Partial<Omit<FormState<SafeFieldValues>, 'defaultValues' | 'dirtyFields' | 'touchedFields' | 'validatingFields' | 'errors' | 'submitErrors'> & {
4
+ hasErrors: boolean;
5
+ hasDirtyFields: boolean;
6
+ hasTouchedFields: boolean;
7
+ hasValidatingFields: boolean;
8
+ /** Sum of all submit counts. */
9
+ submitCount: number;
10
+ /**
11
+ * Consider form flagged when mounted.
12
+ *
13
+ * (To use, return via `FormRelayOptions`'s `select`'s return's `FormRelayStateSelected`'s `isMounted` property.)
14
+ */
15
+ isMounted: boolean;
16
+ }>;
@@ -0,0 +1,8 @@
1
+ export declare const useFormRelayGrouper: () => Partial<Omit<import('react-hook-form').FormState<import('../../../../rhf/SafeFieldValuesType').SafeFieldValues>, "defaultValues" | "errors" | "dirtyFields" | "touchedFields" | "validatingFields" | "submitErrors"> & {
2
+ hasErrors: boolean;
3
+ hasDirtyFields: boolean;
4
+ hasTouchedFields: boolean;
5
+ hasValidatingFields: boolean;
6
+ submitCount: number;
7
+ isMounted: boolean;
8
+ }>;
@@ -0,0 +1,5 @@
1
+ import { FormRelayGroup } from '../../FormRelayGroupType';
2
+ export type FormRelayGrouperContext = {
3
+ state: FormRelayGroup;
4
+ };
5
+ export declare const _FormRelayGrouperContextProvider: import('react').Provider<FormRelayGrouperContext | undefined>, _useFormRelayGrouperContext: () => FormRelayGrouperContext, _useFormRelayGrouperMaybeContext: () => FormRelayGrouperContext | undefined;
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ import { FormRelayGroup } from '../../FormRelayGroupType';
3
+ import { FormRelayGroupCriteria } from '../../useFormRelay';
4
+ type Props = {
5
+ criteria: FormRelayGroupCriteria;
6
+ children: ((state: FormRelayGroup) => React.ReactNode) | React.ReactNode;
7
+ };
8
+ export declare const FormRelayGrouperContextProvider: React.FC<Props>;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { FormRelayGroup } from '../FormRelayGroupType';
2
+ /**
3
+ * Use this when you don't (want to) know whether component is wrapped
4
+ * with RHF context, `FormRelayGrouperContext`, or `FormRelayContext`.
5
+ * Will return `FormRelayGroup`, regardless.
6
+ *
7
+ * Allows you to build naive components that are not tied to one specific context.
8
+ */
9
+ export declare const useFirstFormStateGroup: () => FormRelayGroup;
@@ -0,0 +1,13 @@
1
+ import { RhfUtilsFormOptions } from '../../options/RhfUtilsFormOptionsType';
2
+ import { FormRelayOptions } from '../FormRelayOptions';
3
+ import { FormRelayGroup } from './FormRelayGroupType';
4
+ export declare const useFormRelayId: (formId: string) => import('../types').FormRelay | undefined;
5
+ export type FormRelayGroupCriteria = {
6
+ groups: string[];
7
+ } | {
8
+ predicate: (context: {
9
+ groups: FormRelayOptions['groups'];
10
+ options: RhfUtilsFormOptions;
11
+ }) => boolean;
12
+ };
13
+ export declare const useFormRelayGroup: (criteria?: FormRelayGroupCriteria) => FormRelayGroup;
@@ -0,0 +1,6 @@
1
+ import { FormRelayOptions } from '../FormRelayOptions';
2
+ type Props = {
3
+ options?: FormRelayOptions;
4
+ };
5
+ export declare const FormRelaySetter: React.FC<Props>;
6
+ export {};
@@ -0,0 +1,2 @@
1
+ import { FormRelayOptions } from '../FormRelayOptions';
2
+ export declare const useFormRelaySet: (options?: FormRelayOptions) => void;
@@ -0,0 +1,12 @@
1
+ import { FormState } from 'react-hook-form';
2
+ import { RhfUtilsContext } from '../context/utils/RhfUtilsContextType';
3
+ import { SafeFieldValues } from '../rhf/SafeFieldValuesType';
4
+ import { FormRelayOptions } from './FormRelayOptions';
5
+ export type FormRelay<TFieldValues extends SafeFieldValues = SafeFieldValues> = {
6
+ state: FormRelayStateSelected<TFieldValues>;
7
+ options: FormRelayOptions;
8
+ utils: RhfUtilsContext;
9
+ };
10
+ export type FormRelayStateSelected<TFieldValues extends SafeFieldValues = SafeFieldValues> = Partial<FormState<TFieldValues> & {
11
+ isMounted: true;
12
+ }>;
@@ -9,7 +9,11 @@ export type RhfUtilsFormPropsonBeforeSubmitInvariants<TFieldValues extends SafeF
9
9
  input: TFieldValues;
10
10
  output: TTransformedValues;
11
11
  api: TApiValues;
12
- }, context: UseRhfUtilsFormOnSubmitContext<TFieldValues, TTransformedValues, TApiValues>, event: React.BaseSyntheticEvent<SubmitEvent>) => MaybePromise<[keyof TFieldValues | keyof TApiValues, string, unknown][]>;
12
+ }, context: UseRhfUtilsFormOnSubmitContext<TFieldValues, TTransformedValues, TApiValues>, event: React.BaseSyntheticEvent<SubmitEvent>) => MaybePromise<{
13
+ field: keyof TFieldValues | keyof TApiValues;
14
+ message: string;
15
+ valid: boolean | undefined | null;
16
+ }[]>;
13
17
  export type RhfUtilsFormProps<TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues, TGetApiValues extends undefined | RhfUtilsFormPropsGetApiValues<TTransformedValues, SafeFieldValues>, TOnSubmitReturnType, TApiValues extends undefined | SafeFieldValues = TGetApiValues extends RhfUtilsFormPropsGetApiValues<TTransformedValues, infer U> ? U : undefined> = {
14
18
  getApiData?: TGetApiValues;
15
19
  /** Cancellation handler -- channeled through {@link RhfUtilsClientConfig.useCanFormBeCancelled} before propagating to `Children` component. */
@@ -7,5 +7,5 @@ type Props<TFieldValues extends SafeFieldValues, TTransformedValues extends Safe
7
7
  onError: (error: unknown, event: React.BaseSyntheticEvent) => void;
8
8
  onFinally?: () => MaybePromise<unknown>;
9
9
  };
10
- export declare const useRhfUtilsFormHandleSubmit_Internal: <TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ onValid, onInvalid, onError, onFinally, }: Props<TFieldValues, TTransformedValues>) => ((event: React.FormEvent<HTMLFormElement>) => void);
10
+ export declare const useRhfUtilsFormHandleSubmit_Internal: <TFieldValues extends SafeFieldValues, TTransformedValues extends SafeFieldValues>({ onValid, onInvalid, onError, onFinally, }: Props<TFieldValues, TTransformedValues>) => ((event: React.SubmitEvent<HTMLFormElement>) => void);
11
11
  export {};