@graphcommerce/react-hook-form 8.1.0-canary.3 → 8.1.0-canary.6

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/CHANGELOG.md CHANGED
@@ -1,8 +1,105 @@
1
1
  # Change Log
2
2
 
3
- ## 8.1.0-canary.3
3
+ ## 8.1.0-canary.6
4
4
 
5
- ## 8.1.0-canary.2
5
+ ## 8.1.0-canary.5
6
+
7
+ ## 8.0.6-canary.4
8
+
9
+ ## 8.0.6-canary.3
10
+
11
+ ## 8.0.6-canary.2
12
+
13
+ ### Patch Changes
14
+
15
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`43bd04a`](https://github.com/graphcommerce-org/graphcommerce/commit/43bd04a777c5800cc7e01bee1e123a5aad82f194) - Add deprecation warnings for useFormMuiRegister. Refactor useFormPersist to useWatch and add a separate `<FormPersist/>` component to prevent rerenders.
16
+ ([@FrankHarland](https://github.com/FrankHarland))
17
+
18
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`0767bc4`](https://github.com/graphcommerce-org/graphcommerce/commit/0767bc40f7b596209f24ca4e745ff0441f3275c9) - Upgrade input components to no longer use muiRegister, which improves INP scores
19
+ ([@FrankHarland](https://github.com/FrankHarland))
20
+
21
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`02da217`](https://github.com/graphcommerce-org/graphcommerce/commit/02da2172ef702133510f6923190efae2801032c5) - Migrate most usages of useFormAutoSubmit to <FormAutoSubmit/> and deprecated useFormAutoSubmit
22
+ ([@FrankHarland](https://github.com/FrankHarland))
23
+
24
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`530076e`](https://github.com/graphcommerce-org/graphcommerce/commit/530076e3664703cb8b577b7fcf1998a420819f60) - Moved all usages of useFormPersist to the <FormPersist/> component to prevent rerenders.
25
+ ([@FrankHarland](https://github.com/FrankHarland))
26
+
27
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`1a6d0c4`](https://github.com/graphcommerce-org/graphcommerce/commit/1a6d0c4a3584b1e404b444f1ca44c68eaad56cb7) - Mark useFormValidFields as deprecated: Please use TextInputElement, SelectElement, etc. with the showValid prop
28
+ ([@FrankHarland](https://github.com/FrankHarland))
29
+
30
+ ## 8.0.6-canary.1
31
+
32
+ ## 8.0.6-canary.0
33
+
34
+ ## 8.0.5
35
+
36
+ ### Patch Changes
37
+
38
+ - [#2237](https://github.com/graphcommerce-org/graphcommerce/pull/2237) [`60f387d`](https://github.com/graphcommerce-org/graphcommerce/commit/60f387d4a037736aa8105fa45728ee481bdaf887) - Solve an issue where the checkout address form wouldn't be automatically submitted on change.
39
+ ([@bramvanderholst](https://github.com/bramvanderholst))
40
+
41
+ ## 8.0.5-canary.10
42
+
43
+ ## 8.0.5-canary.9
44
+
45
+ ## 8.0.5-canary.8
46
+
47
+ ## 8.0.5-canary.7
48
+
49
+ ## 8.0.5-canary.6
50
+
51
+ ## 8.0.5-canary.5
52
+
53
+ ## 8.0.5-canary.4
54
+
55
+ ### Patch Changes
56
+
57
+ - [#2237](https://github.com/graphcommerce-org/graphcommerce/pull/2237) [`60f387d`](https://github.com/graphcommerce-org/graphcommerce/commit/60f387d4a037736aa8105fa45728ee481bdaf887) - Solve an issue where the checkout address form wouldn't be automatically submitted on change.
58
+ ([@bramvanderholst](https://github.com/bramvanderholst))
59
+
60
+ ## 8.0.5-canary.3
61
+
62
+ ## 8.0.5-canary.2
63
+
64
+ ## 8.0.5-canary.1
65
+
66
+ ## 8.0.5-canary.0
67
+
68
+ ## 8.0.4
69
+
70
+ ## 8.0.4-canary.1
71
+
72
+ ## 8.0.4-canary.0
73
+
74
+ ## 8.0.3
75
+
76
+ ### Patch Changes
77
+
78
+ - [#2206](https://github.com/graphcommerce-org/graphcommerce/pull/2206) [`855ab09`](https://github.com/graphcommerce-org/graphcommerce/commit/855ab097b9ea204a7c73c6550b7a5e9e2290f378) - Cleanup `<FormAutoSubmit/>` and remove internal hook.
79
+ ([@paales](https://github.com/paales))
80
+
81
+ - [#2212](https://github.com/graphcommerce-org/graphcommerce/pull/2212) [`7c9f5da`](https://github.com/graphcommerce-org/graphcommerce/commit/7c9f5da1d458a19b0316c556c75415ff28bc5b2d) - Added noValidate prop so we can use the FormAutoSubmit component to submit partial forms
82
+ ([@paales](https://github.com/paales))
83
+
84
+ ## 8.0.3-canary.6
85
+
86
+ ## 8.0.3-canary.5
87
+
88
+ ### Patch Changes
89
+
90
+ - [#2212](https://github.com/graphcommerce-org/graphcommerce/pull/2212) [`7c9f5da`](https://github.com/graphcommerce-org/graphcommerce/commit/7c9f5da1d458a19b0316c556c75415ff28bc5b2d) - Added noValidate prop so we can use the FormAutoSubmit component to submit partial forms
91
+ ([@paales](https://github.com/paales))
92
+
93
+ ## 8.0.3-canary.4
94
+
95
+ ## 8.0.3-canary.3
96
+
97
+ ### Patch Changes
98
+
99
+ - [#2206](https://github.com/graphcommerce-org/graphcommerce/pull/2206) [`855ab09`](https://github.com/graphcommerce-org/graphcommerce/commit/855ab097b9ea204a7c73c6550b7a5e9e2290f378) - Cleanup `<FormAutoSubmit/>` and remove internal hook.
100
+ ([@paales](https://github.com/paales))
101
+
102
+ ## 8.0.3-canary.2
6
103
 
7
104
  ## 8.0.3-canary.1
8
105
 
package/README.md CHANGED
@@ -77,10 +77,10 @@ export default function MyComponent() {
77
77
  }
78
78
  ```
79
79
 
80
- ## `useFormAutoSubmit`
80
+ ## `FormAutoSubmit`
81
81
 
82
82
  ```tsx
83
- import { useFormAutoSubmit } from '@graphcommerce/react-hook-form'
83
+ import { FormAutoSubmit } from '@graphcommerce/react-hook-form'
84
84
 
85
85
  export default function MyAutoSubmitForm() {
86
86
  // Regular useForm hook, but you can also use useFormGqlMutation
@@ -90,20 +90,13 @@ export default function MyAutoSubmitForm() {
90
90
  const submit = handleSubmit(() => {
91
91
  console.log('submitted')
92
92
  })
93
- const autoSubmitting = useFormAutoSubmit({
94
- form,
95
- submit,
96
- fields: ['couponCode'], //optional, default: all fields
97
- wait: 1200, // optional, default: 500ms
98
- })
99
- const disableFields = formState.isSubmitting && !autoSubmitting
100
93
 
101
94
  return (
102
95
  <form onSubmit={submit} noValidate>
96
+ <FormAutoSubmit control={control} submit={submit} name={['couponCode']} wait={1200}>
103
97
  <input
104
98
  type='text'
105
99
  {...register('couponCode', { required: required.couponCode })}
106
- disabled={formState.isSubmitting}
107
100
  />
108
101
  {errors.couponCode?.message}
109
102
  </form>
@@ -111,10 +104,10 @@ export default function MyAutoSubmitForm() {
111
104
  }
112
105
  ```
113
106
 
114
- ### `useFormPersist`
107
+ ### `FormPersist`
115
108
 
116
109
  ```tsx
117
- import { useFormAutoSubmit } from '@graphcommerce/react-hook-form'
110
+ import { FormPersist } from '@graphcommerce/react-hook-form'
118
111
 
119
112
  export default function MyAutoSubmitForm() {
120
113
  // Regular useForm hook, but you can also use useFormGqlMutation
@@ -124,11 +117,10 @@ export default function MyAutoSubmitForm() {
124
117
  const submit = handleSubmit(() => {
125
118
  console.log('submitted')
126
119
  })
127
- const autoSubmitting = useFormPersist({ form, name: 'MyForm' })
128
- const disableFields = formState.isSubmitting && !autoSubmitting
129
120
 
130
121
  return (
131
122
  <form onSubmit={submit} noValidate>
123
+ <FormPersist form={form} name='MyForm'>
132
124
  <input
133
125
  type='text'
134
126
  {...register('couponCode', { required: required.couponCode })}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/react-hook-form",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "8.1.0-canary.3",
5
+ "version": "8.1.0-canary.6",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -16,9 +16,9 @@
16
16
  },
17
17
  "peerDependencies": {
18
18
  "@apollo/client": "^3",
19
- "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.3",
20
- "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.3",
21
- "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.3",
19
+ "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.6",
20
+ "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.6",
21
+ "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.6",
22
22
  "graphql": "^16.6.0",
23
23
  "react": "^18.2.0",
24
24
  "react-dom": "^18.2.0",
@@ -5,11 +5,11 @@ import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject'
5
5
  import { debounce } from '@mui/material'
6
6
  import React, { useCallback, useEffect, useRef, useState } from 'react'
7
7
  import {
8
- Control,
9
8
  DeepPartialSkipArrayKey,
10
9
  FieldPath,
11
10
  FieldValues,
12
11
  UseFormReturn,
12
+ UseWatchProps,
13
13
  useFormState,
14
14
  useWatch,
15
15
  } from 'react-hook-form'
@@ -53,6 +53,9 @@ export type UseFormAutoSubmitOptions<TForm extends UseFormReturn<V>, V extends F
53
53
  * Q: How to I resubmit if the form is modified during the request?
54
54
  * formState.isDirty should be true after the submission
55
55
  * @see useFormGqlMutation.tsx for an example implementation
56
+ *
57
+ *
58
+ * @deprecated Please use the <FormAutoSubmit /> component instead. This method causes excessive rerenders.
56
59
  */
57
60
  export function useFormAutoSubmit<
58
61
  Form extends UseFormReturn<V>,
@@ -98,21 +101,8 @@ export function useFormAutoSubmit<
98
101
  return submitting
99
102
  }
100
103
 
101
- export type FormAutoSubmitProps<
102
- TFieldValues extends FieldValues = FieldValues,
103
- TFieldNames extends readonly FieldPath<TFieldValues>[] = readonly FieldPath<TFieldValues>[],
104
- > = {
105
- // eslint-disable-next-line react/no-unused-prop-types
106
- control: Control<TFieldValues>
104
+ export type FormAutoSubmitProps<TFieldValues extends FieldValues = FieldValues> = {
107
105
  /** Autosubmit only when these field names update */
108
- // eslint-disable-next-line react/no-unused-prop-types
109
- name?: readonly [...TFieldNames]
110
-
111
- // eslint-disable-next-line react/no-unused-prop-types
112
- disabled?: boolean
113
-
114
- // eslint-disable-next-line react/no-unused-prop-types
115
- exact?: boolean
116
106
 
117
107
  /** SubmitHandler */
118
108
  // eslint-disable-next-line react/no-unused-prop-types
@@ -124,13 +114,18 @@ export type FormAutoSubmitProps<
124
114
  */
125
115
  // eslint-disable-next-line react/no-unused-prop-types
126
116
  parallel?: boolean
127
- } & DebounceOptions
128
117
 
129
- function useFormAutoSubmit2<
130
- TFieldValues extends FieldValues = FieldValues,
131
- TFieldNames extends readonly FieldPath<TFieldValues>[] = readonly FieldPath<TFieldValues>[],
132
- >(props: FormAutoSubmitProps<TFieldValues, TFieldNames>) {
133
- const { wait, initialWait, maxWait, submit, parallel, ...watchOptions } = props
118
+ noValidate?: boolean
119
+ } & DebounceOptions &
120
+ Omit<UseWatchProps<TFieldValues>, 'defaultValue'>
121
+
122
+ /**
123
+ * This is made a components so the useWatch that is used here doesn't retrigger the rerender of the parent component.
124
+ */
125
+ function FormAutoSubmitBase<TFieldValues extends FieldValues = FieldValues>(
126
+ props: FormAutoSubmitProps<TFieldValues>,
127
+ ) {
128
+ const { wait, initialWait, maxWait, submit, parallel, noValidate, ...watchOptions } = props
134
129
 
135
130
  // We create a stable object from the values, so that we can compare them later
136
131
  const values = useMemoObject(cloneDeep(useWatch(watchOptions)))
@@ -149,7 +144,7 @@ function useFormAutoSubmit2<
149
144
  { wait, initialWait, maxWait },
150
145
  )
151
146
 
152
- const valid = isValid && !isValidating
147
+ const valid = (noValidate ? true : isValid) && !isValidating
153
148
  const allowed = parallel || !isSubmitting
154
149
  const canSubmit = valid && allowed
155
150
 
@@ -157,17 +152,7 @@ function useFormAutoSubmit2<
157
152
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
158
153
  submitDebounced()
159
154
  }
160
- }
161
155
 
162
- /**
163
- * We're wrapping this in a component so that the parent component doesn't rerender on every
164
- * submission.
165
- */
166
- function FormAutoSubmitBase<
167
- TFieldValues extends FieldValues = FieldValues,
168
- TFieldNames extends readonly FieldPath<TFieldValues>[] = readonly FieldPath<TFieldValues>[],
169
- >(props: FormAutoSubmitProps<TFieldValues, TFieldNames>) {
170
- useFormAutoSubmit2(props)
171
156
  return null
172
157
  }
173
158
 
@@ -2,7 +2,7 @@ import { MutationHookOptions, TypedDocumentNode, useMutation } from '@apollo/cli
2
2
  import { FieldValues, useForm, UseFormReturn } from 'react-hook-form'
3
3
  import { useFormGql, UseFormGqlMethods, UseFormGraphQlOptions } from './useFormGql'
4
4
  import { useFormMuiRegister, UseMuiFormRegister } from './useFormMuiRegister'
5
- import { useFormValidFields, UseFormValidReturn } from './useFormValidFields'
5
+ import { UseFormValidReturn } from './useFormValidFields'
6
6
 
7
7
  export type UseFormGqlMutationReturn<
8
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -10,7 +10,16 @@ export type UseFormGqlMutationReturn<
10
10
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
11
  V extends FieldValues = FieldValues,
12
12
  > = UseFormGqlMethods<Q, V> &
13
- UseFormReturn<V> & { muiRegister: UseMuiFormRegister<V>; valid: UseFormValidReturn<V> }
13
+ UseFormReturn<V> & {
14
+ /**
15
+ * @deprecated Please use TextFieldElement
16
+ */
17
+ muiRegister: UseMuiFormRegister<V>
18
+ /**
19
+ * @deprecated Please use TextFieldElement showValid
20
+ */
21
+ valid: UseFormValidReturn<V>
22
+ }
14
23
 
15
24
  export function isFormGqlOperation<
16
25
  V extends FieldValues,
@@ -38,7 +47,5 @@ export function useFormGqlMutation<Q extends Record<string, unknown>, V extends
38
47
  const tuple = useMutation(document, operationOptions)
39
48
  const operation = useFormGql({ document, form, tuple, ...options })
40
49
  const muiRegister = useFormMuiRegister(form)
41
- const valid = useFormValidFields(form, operation.required)
42
-
43
- return { ...form, ...operation, valid, muiRegister }
50
+ return { ...form, ...operation, muiRegister, valid: {} }
44
51
  }
@@ -3,7 +3,6 @@ import { FieldValues, useForm } from 'react-hook-form'
3
3
  import { useFormGql, UseFormGraphQlOptions } from './useFormGql'
4
4
  import { UseFormGqlMutationReturn } from './useFormGqlMutation'
5
5
  import { useFormMuiRegister } from './useFormMuiRegister'
6
- import { useFormValidFields } from './useFormValidFields'
7
6
 
8
7
  export type UseFormGqlQueryReturn<
9
8
  Q extends Record<string, unknown>,
@@ -19,7 +18,6 @@ export function useFormGqlQuery<Q extends Record<string, unknown>, V extends Fie
19
18
  const tuple = useLazyQuery(document, operationOptions)
20
19
  const operation = useFormGql({ document, form, tuple, ...options })
21
20
  const muiRegister = useFormMuiRegister(form)
22
- const valid = useFormValidFields(form, operation.required)
23
21
 
24
- return { ...form, ...operation, valid, muiRegister }
22
+ return { ...form, ...operation, valid: {}, muiRegister }
25
23
  }
@@ -13,6 +13,9 @@ export type UseMuiFormRegister<TFieldValues extends FieldValues> = <
13
13
  options?: RegisterOptions<TFieldValues, TFieldName>,
14
14
  ) => Omit<UseFormRegisterReturn, 'ref'> & { inputRef: UseFormRegisterReturn['ref'] }
15
15
 
16
+ /**
17
+ * @deprecated Please use use TextFieldElement, etc.
18
+ */
16
19
  export function useFormMuiRegister<V extends FieldValues>({
17
20
  register,
18
21
  }: Pick<UseFormReturn<V>, 'register'>) {
@@ -1,5 +1,14 @@
1
+ import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject'
1
2
  import { useEffect } from 'react'
2
- import { FieldValues, UseFormReturn, Path, FieldPath, PathValue } from 'react-hook-form'
3
+ import {
4
+ FieldValues,
5
+ UseFormReturn,
6
+ Path,
7
+ FieldPath,
8
+ PathValue,
9
+ useWatch,
10
+ useFormState,
11
+ } from 'react-hook-form'
3
12
 
4
13
  export type UseFormPersistOptions<
5
14
  TFieldValues extends FieldValues = FieldValues,
@@ -29,24 +38,30 @@ export type UseFormPersistOptions<
29
38
  * dirty fields when the form is initialized
30
39
  *
31
40
  * Todo: Use wath callback so it won't trigger a rerender
41
+ *
42
+ * @deprecated Please use <FormPersist /> instead. This method causes INP problems.
32
43
  */
33
44
  export function useFormPersist<V extends FieldValues>(options: UseFormPersistOptions<V>) {
34
45
  const { form, name, storage = 'sessionStorage', exclude = [], persist = [] } = options
35
- const { setValue, watch, formState } = form
46
+ const { setValue, control } = form
47
+
48
+ const formState = useFormState({ control })
49
+ const allFields = useWatch({ control })
36
50
 
37
51
  const dirtyFieldKeys = Object.keys(formState.dirtyFields) as Path<V>[]
38
52
 
39
- // Get all dirty field values and exclude sensitive data
53
+ // // Get all dirty field values and exclude sensitive data
40
54
  const newValues = Object.fromEntries(
41
- dirtyFieldKeys.filter((f) => !exclude.includes(f)).map((field) => [field, watch(field)]),
55
+ dirtyFieldKeys.filter((f) => !exclude.includes(f)).map((field) => [field, allFields[field]]),
42
56
  )
43
57
 
44
58
  // Amend the values with the values that should always be persisted
45
59
  persist.forEach((persistKey) => {
46
- const value = watch(persistKey)
60
+ const value = allFields[persistKey]
47
61
  if (value) newValues[persistKey] = value
48
62
  })
49
63
 
64
+ // const valuesJson = useMemoObject(newValues)
50
65
  const valuesJson = JSON.stringify(newValues)
51
66
 
52
67
  // Restore changes
@@ -82,3 +97,8 @@ export function useFormPersist<V extends FieldValues>(options: UseFormPersistOpt
82
97
  }
83
98
  }, [name, storage, valuesJson])
84
99
  }
100
+
101
+ export function FormPersist<V extends FieldValues>(props: UseFormPersistOptions<V>) {
102
+ useFormPersist(props)
103
+ return null
104
+ }
@@ -7,6 +7,8 @@ export type UseFormValidReturn<TFieldValues> = Partial<Record<Path<TFieldValues>
7
7
  * ### useFormValidFields
8
8
  *
9
9
  * Record field names as key and boolean as value indicating whether the field is valid
10
+ *
11
+ * @deprecated Please use TextInputElement, SelectElement, etc. with the showValid prop
10
12
  */
11
13
  export function useFormValidFields<TFieldValues extends FieldValues>(
12
14
  form: Pick<UseFormReturn<TFieldValues>, 'watch' | 'formState'>,
@@ -3,7 +3,7 @@ import useEventCallback from '@mui/utils/useEventCallback'
3
3
  import { useEffect, useRef } from 'react'
4
4
  import debounce, { DebounceOptions } from './debounce'
5
5
 
6
- export function useDebouncedCallback<T extends (...args: unknown[]) => unknown>(
6
+ export function useDebouncedCallback<T extends (...args: any[]) => unknown>(
7
7
  callback: T,
8
8
  { initialWait, maxWait, wait }: DebounceOptions = {},
9
9
  ): T {