@graphcommerce/react-hook-form 9.0.4-canary.0 → 9.0.4-canary.2
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 +3 -13
- package/package.json +4 -4
- package/src/ComposedForm/types.ts +9 -4
- package/src/ComposedForm/useFormCompose.ts +5 -5
- package/src/useFormAutoSubmit.tsx +3 -2
- package/src/useFormGql.tsx +2 -6
- package/src/useFormGqlMutation.tsx +5 -8
- package/src/useFormMuiRegister.tsx +1 -3
- package/src/useFormPersist.tsx +8 -8
- package/src/useFormValidFields.tsx +6 -4
- package/src/useGqlDocumentHandler.tsx +1 -1
- package/src/utils/useDebounce.ts +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
## 9.0.4-canary.
|
|
3
|
+
## 9.0.4-canary.2
|
|
4
4
|
|
|
5
|
-
## 9.0.
|
|
5
|
+
## 9.0.4-canary.1
|
|
6
6
|
|
|
7
|
-
## 9.0.
|
|
7
|
+
## 9.0.4-canary.0
|
|
8
8
|
|
|
9
9
|
## 9.0.2
|
|
10
10
|
|
|
@@ -12,16 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
- [`c40c559`](https://github.com/graphcommerce-org/graphcommerce/commit/c40c5596bcc8f3c2e1e15c9e6ad85bfa1f9154b0) - Solve an issue where the payment submission would remain in a spinning state when placing an order failed: `useFormGql` will now set `root` error on the form when there is an error response on the GraphQL operation, an error is thrown in onBeforeSubmit and in onSuccess. ([@paales](https://github.com/paales))
|
|
14
14
|
|
|
15
|
-
## 9.0.2-canary.0
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
18
|
-
|
|
19
|
-
- [`c40c559`](https://github.com/graphcommerce-org/graphcommerce/commit/c40c5596bcc8f3c2e1e15c9e6ad85bfa1f9154b0) - Solve an issue where the payment submission would remain in a spinning state when placing an order failed: `useFormGql` will now set `root` error on the form when there is an error response on the GraphQL operation, an error is thrown in onBeforeSubmit and in onSuccess. ([@paales](https://github.com/paales))
|
|
20
|
-
|
|
21
|
-
## 9.0.1
|
|
22
|
-
|
|
23
|
-
## 9.0.1-canary.1
|
|
24
|
-
|
|
25
15
|
## 9.0.0
|
|
26
16
|
|
|
27
17
|
### Major Changes
|
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": "9.0.4-canary.
|
|
5
|
+
"version": "9.0.4-canary.2",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@apollo/client": "*",
|
|
16
|
-
"@graphcommerce/eslint-config-pwa": "^9.0.4-canary.
|
|
17
|
-
"@graphcommerce/prettier-config-pwa": "^9.0.4-canary.
|
|
18
|
-
"@graphcommerce/typescript-config-pwa": "^9.0.4-canary.
|
|
16
|
+
"@graphcommerce/eslint-config-pwa": "^9.0.4-canary.2",
|
|
17
|
+
"@graphcommerce/prettier-config-pwa": "^9.0.4-canary.2",
|
|
18
|
+
"@graphcommerce/typescript-config-pwa": "^9.0.4-canary.2",
|
|
19
19
|
"@mui/utils": "^5",
|
|
20
20
|
"graphql": "^16.6.0",
|
|
21
21
|
"react": "^18.2.0",
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { ApolloError } from '@apollo/client'
|
|
2
|
-
import type { FieldValues, FormState,
|
|
2
|
+
import type { FieldValues, FormState, UseFormHandleSubmit, UseFormTrigger } from 'react-hook-form'
|
|
3
3
|
import type { SetOptional } from 'type-fest'
|
|
4
4
|
|
|
5
|
-
export type
|
|
5
|
+
export type MinimalUseFormReturn<TFieldValues extends FieldValues = FieldValues> = {
|
|
6
|
+
formState: FormState<TFieldValues>
|
|
7
|
+
trigger: UseFormTrigger<TFieldValues>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type UseFormComposeOptions<TFieldValues extends FieldValues = FieldValues> = {
|
|
6
11
|
/** The form that is used to submit */
|
|
7
|
-
form:
|
|
12
|
+
form: MinimalUseFormReturn<TFieldValues>
|
|
8
13
|
/** Method to submit the form */
|
|
9
|
-
submit: ReturnType<
|
|
14
|
+
submit: ReturnType<UseFormHandleSubmit<TFieldValues>>
|
|
10
15
|
|
|
11
16
|
/** Identifier of the specific */
|
|
12
17
|
key: string
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useContext, useEffect } from 'react'
|
|
2
|
-
import type { FieldValues
|
|
2
|
+
import type { FieldValues } from 'react-hook-form'
|
|
3
3
|
import { isFormGqlOperation } from '../useFormGqlMutation'
|
|
4
4
|
import { composedFormContext } from './context'
|
|
5
|
-
import type { UseFormComposeOptions } from './types'
|
|
5
|
+
import type { MinimalUseFormReturn, UseFormComposeOptions } from './types'
|
|
6
6
|
|
|
7
|
-
export function useFormCompose<
|
|
8
|
-
fields: UseFormComposeOptions<
|
|
7
|
+
export function useFormCompose<TFieldValues extends FieldValues = FieldValues>(
|
|
8
|
+
fields: UseFormComposeOptions<TFieldValues>,
|
|
9
9
|
) {
|
|
10
10
|
const [state, dispatch] = useContext(composedFormContext)
|
|
11
11
|
const { form, key, step, submit } = fields
|
|
@@ -18,7 +18,7 @@ export function useFormCompose<V extends Record<string, unknown>>(
|
|
|
18
18
|
}, [dispatch, key, step])
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
dispatch({ type: 'ASSIGN', key, form: form as
|
|
21
|
+
dispatch({ type: 'ASSIGN', key, form: form as MinimalUseFormReturn, submit })
|
|
22
22
|
}, [dispatch, fields, form, key, submit])
|
|
23
23
|
|
|
24
24
|
const error = isFormGqlOperation(form) ? form.error : undefined
|
|
@@ -4,11 +4,12 @@ import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject'
|
|
|
4
4
|
import { cloneDeep } from '@apollo/client/utilities'
|
|
5
5
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
6
|
import { debounce } from '@mui/material'
|
|
7
|
-
import React, {
|
|
7
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
8
8
|
import type {
|
|
9
9
|
DeepPartialSkipArrayKey,
|
|
10
10
|
FieldPath,
|
|
11
11
|
FieldValues,
|
|
12
|
+
UseFormHandleSubmit,
|
|
12
13
|
UseFormReturn,
|
|
13
14
|
UseWatchProps,
|
|
14
15
|
} from 'react-hook-form'
|
|
@@ -105,7 +106,7 @@ export type FormAutoSubmitProps<TFieldValues extends FieldValues = FieldValues>
|
|
|
105
106
|
|
|
106
107
|
/** SubmitHandler */
|
|
107
108
|
// eslint-disable-next-line react/no-unused-prop-types
|
|
108
|
-
submit: ReturnType<
|
|
109
|
+
submit: ReturnType<UseFormHandleSubmit<TFieldValues>>
|
|
109
110
|
|
|
110
111
|
/**
|
|
111
112
|
* When a current submission is already in flight, should we wait for it to finish before
|
package/src/useFormGql.tsx
CHANGED
|
@@ -2,7 +2,6 @@ import type {
|
|
|
2
2
|
FetchResult,
|
|
3
3
|
LazyQueryHookOptions,
|
|
4
4
|
LazyQueryResultTuple,
|
|
5
|
-
MaybeMasked,
|
|
6
5
|
MutationHookOptions,
|
|
7
6
|
MutationTuple,
|
|
8
7
|
TypedDocumentNode,
|
|
@@ -17,10 +16,7 @@ import type { UseGqlDocumentHandler } from './useGqlDocumentHandler'
|
|
|
17
16
|
import { useGqlDocumentHandler } from './useGqlDocumentHandler'
|
|
18
17
|
import { tryAsync } from './utils/tryTuple'
|
|
19
18
|
|
|
20
|
-
export type OnCompleteFn<Q, V> = (
|
|
21
|
-
data: FetchResult<MaybeMasked<Q>>,
|
|
22
|
-
variables: V,
|
|
23
|
-
) => void | Promise<void>
|
|
19
|
+
export type OnCompleteFn<Q, V> = (data: FetchResult<Q>, variables: V) => void | Promise<void>
|
|
24
20
|
|
|
25
21
|
type UseFormGraphQLCallbacks<Q, V> = {
|
|
26
22
|
/**
|
|
@@ -88,7 +84,7 @@ export type UseFormGqlMethods<Q, V extends FieldValues> = Omit<
|
|
|
88
84
|
'encode' | 'type'
|
|
89
85
|
> &
|
|
90
86
|
Pick<UseFormReturn<V>, 'handleSubmit'> & {
|
|
91
|
-
data?:
|
|
87
|
+
data?: Q | null
|
|
92
88
|
error?: ApolloError
|
|
93
89
|
submittedVariables?: V
|
|
94
90
|
}
|
|
@@ -15,21 +15,18 @@ export type UseFormGqlMutationReturn<
|
|
|
15
15
|
V extends FieldValues = FieldValues,
|
|
16
16
|
> = UseFormGqlMethods<Q, V> &
|
|
17
17
|
UseFormReturn<V> & {
|
|
18
|
-
/**
|
|
19
|
-
* @deprecated Please use TextFieldElement
|
|
20
|
-
*/
|
|
18
|
+
/** @deprecated Please use TextFieldElement */
|
|
21
19
|
muiRegister: UseMuiFormRegister<V>
|
|
22
|
-
/**
|
|
23
|
-
* @deprecated Please use TextFieldElement showValid
|
|
24
|
-
*/
|
|
20
|
+
/** @deprecated Please use TextFieldElement showValid */
|
|
25
21
|
valid: UseFormValidReturn<V>
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
export function isFormGqlOperation<
|
|
29
25
|
V extends FieldValues,
|
|
30
26
|
Q extends Record<string, unknown> = Record<string, unknown>,
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
|
|
28
|
+
>(form: any): form is UseFormGqlMutationReturn<Q, V> {
|
|
29
|
+
return typeof (form as UseFormGqlMutationReturn<Q, V>).submittedVariables !== 'undefined'
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
export function assertFormGqlOperation<
|
|
@@ -13,9 +13,7 @@ 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
|
+
/** @deprecated Please use use TextFieldElement, etc. */
|
|
19
17
|
export function useFormMuiRegister<V extends FieldValues>({
|
|
20
18
|
register,
|
|
21
19
|
}: Pick<UseFormReturn<V>, 'register'>) {
|
package/src/useFormPersist.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/no-unused-prop-types */
|
|
2
2
|
import { useEffect } from 'react'
|
|
3
|
-
import type { FieldPath, FieldValues,
|
|
3
|
+
import type { Control, FieldPath, FieldValues, PathValue, UseFormSetValue } from 'react-hook-form'
|
|
4
4
|
import { useFormState, useWatch } from 'react-hook-form'
|
|
5
5
|
|
|
6
6
|
export type UseFormPersistOptions<
|
|
@@ -9,7 +9,10 @@ export type UseFormPersistOptions<
|
|
|
9
9
|
TContext = any,
|
|
10
10
|
> = {
|
|
11
11
|
/** Instance of current form, used to watch value */
|
|
12
|
-
form:
|
|
12
|
+
form: {
|
|
13
|
+
control: Control<TFieldValues, TContext>
|
|
14
|
+
setValue: UseFormSetValue<TFieldValues>
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
/** Name of the key how it will be stored in the storage. */
|
|
15
18
|
name: string
|
|
@@ -42,7 +45,7 @@ export function useFormPersist<V extends FieldValues>(options: UseFormPersistOpt
|
|
|
42
45
|
const formState = useFormState({ control })
|
|
43
46
|
const allFields = useWatch({ control })
|
|
44
47
|
|
|
45
|
-
const dirtyFieldKeys = Object.keys(formState.dirtyFields) as
|
|
48
|
+
const dirtyFieldKeys = Object.keys(formState.dirtyFields) as FieldPath<V>[]
|
|
46
49
|
|
|
47
50
|
// // Get all dirty field values and exclude sensitive data
|
|
48
51
|
const newValues = Object.fromEntries(
|
|
@@ -67,12 +70,9 @@ export function useFormPersist<V extends FieldValues>(options: UseFormPersistOpt
|
|
|
67
70
|
|
|
68
71
|
const storedValues = JSON.parse(storedFormStr) as FieldValues
|
|
69
72
|
if (storedValues) {
|
|
70
|
-
const entries = Object.entries(storedValues) as [
|
|
73
|
+
const entries = Object.entries(storedValues) as [FieldPath<V>, PathValue<V, FieldPath<V>>][]
|
|
71
74
|
entries.forEach(([entryName, value]) =>
|
|
72
|
-
setValue(entryName, value, {
|
|
73
|
-
shouldDirty: true,
|
|
74
|
-
shouldValidate: true,
|
|
75
|
-
}),
|
|
75
|
+
setValue(entryName, value, { shouldDirty: true, shouldValidate: true }),
|
|
76
76
|
)
|
|
77
77
|
}
|
|
78
78
|
} catch {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FieldPath, FieldValues, UseFormReturn } from 'react-hook-form'
|
|
2
2
|
import type { IsRequired } from './useGqlDocumentHandler'
|
|
3
3
|
|
|
4
|
-
export type UseFormValidReturn<TFieldValues> = Partial<
|
|
4
|
+
export type UseFormValidReturn<TFieldValues extends FieldValues> = Partial<
|
|
5
|
+
Record<FieldPath<TFieldValues>, boolean>
|
|
6
|
+
>
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* ### useFormValidFields
|
|
@@ -16,10 +18,10 @@ export function useFormValidFields<TFieldValues extends FieldValues>(
|
|
|
16
18
|
required: IsRequired<TFieldValues>,
|
|
17
19
|
): UseFormValidReturn<TFieldValues> {
|
|
18
20
|
const { watch, formState } = form
|
|
19
|
-
const fields: Partial<Record<
|
|
21
|
+
const fields: Partial<Record<FieldPath<TFieldValues>, boolean>> = {}
|
|
20
22
|
|
|
21
23
|
Object.keys(required).forEach((key) => {
|
|
22
|
-
fields[key] = !formState.errors[key] && watch(key as
|
|
24
|
+
fields[key] = !formState.errors[key] && watch(key as FieldPath<TFieldValues>)
|
|
23
25
|
})
|
|
24
26
|
|
|
25
27
|
return fields
|
package/src/utils/useDebounce.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject'
|
|
3
3
|
import useEventCallback from '@mui/utils/useEventCallback'
|
|
4
4
|
import type {
|
|
5
|
-
DebounceSettings,
|
|
6
|
-
DebounceSettingsLeading,
|
|
7
5
|
DebouncedFunc,
|
|
8
6
|
DebouncedFuncLeading,
|
|
7
|
+
DebounceSettings,
|
|
8
|
+
DebounceSettingsLeading,
|
|
9
9
|
} from 'lodash'
|
|
10
10
|
import debounce from 'lodash/debounce'
|
|
11
11
|
import { useMemo } from 'react'
|
|
@@ -13,14 +13,15 @@ import { useMemo } from 'react'
|
|
|
13
13
|
export type { DebounceSettings, DebounceSettingsLeading, DebouncedFunc, DebouncedFuncLeading }
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Creates a debounced function that delays invoking func until after wait milliseconds have elapsed
|
|
17
|
-
* the last time the debounced function was invoked. The debounced function comes with a
|
|
18
|
-
* cancel delayed invocations and a flush method to immediately invoke them.
|
|
19
|
-
* indicate that func should be invoked on the leading and/or trailing
|
|
20
|
-
* calls to the debounced function return the result of the
|
|
16
|
+
* Creates a debounced function that delays invoking func until after wait milliseconds have elapsed
|
|
17
|
+
* since the last time the debounced function was invoked. The debounced function comes with a
|
|
18
|
+
* cancel method to cancel delayed invocations and a flush method to immediately invoke them.
|
|
19
|
+
* Provide an options object to indicate that func should be invoked on the leading and/or trailing
|
|
20
|
+
* edge of the wait timeout. Subsequent calls to the debounced function return the result of the
|
|
21
|
+
* last func invocation.
|
|
21
22
|
*
|
|
22
|
-
* Note: If leading and trailing options are true, func is invoked on the trailing edge of the
|
|
23
|
-
* if the the debounced function is invoked more than once during the wait timeout.
|
|
23
|
+
* Note: If leading and trailing options are true, func is invoked on the trailing edge of the
|
|
24
|
+
* timeout only if the the debounced function is invoked more than once during the wait timeout.
|
|
24
25
|
*
|
|
25
26
|
* See David Corbacho’s article for details over the differences between _.debounce and _.throttle.
|
|
26
27
|
*
|
|
@@ -30,7 +31,7 @@ export type { DebounceSettings, DebounceSettingsLeading, DebouncedFunc, Debounce
|
|
|
30
31
|
* @param options.leading Specify invoking on the leading edge of the timeout.
|
|
31
32
|
* @param options.maxWait The maximum time func is allowed to be delayed before it’s invoked.
|
|
32
33
|
* @param options.trailing Specify invoking on the trailing edge of the timeout.
|
|
33
|
-
* @
|
|
34
|
+
* @returns Returns the new debounced function.
|
|
34
35
|
*/
|
|
35
36
|
export function useDebounce<T extends (...args: never[]) => unknown>(
|
|
36
37
|
func: T,
|