@graphcommerce/react-hook-form 3.0.7 → 3.1.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
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 3.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1426](https://github.com/graphcommerce-org/graphcommerce/pull/1426) [`100f4c38c`](https://github.com/graphcommerce-org/graphcommerce/commit/100f4c38c8fcda4bc6e0425e38028b550b60adc2) Thanks [@paales](https://github.com/paales)! - Upgrade packages
|
|
8
|
+
|
|
9
|
+
## 3.1.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Now using [@graphql-yoga](https://github.com/dotansimha/graphql-yoga) for GraphQL which has full support for [envelop](https://www.envelop.dev/) plugins.
|
|
14
|
+
|
|
15
|
+
* [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Added a new @graphcommerce/cli package to generate the mesh so it can be generated _inside_ the @graphcommerce/graphql-mesh package to allow for better future extensibility.
|
|
16
|
+
|
|
17
|
+
- [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`da0ae7d02`](https://github.com/graphcommerce-org/graphcommerce/commit/da0ae7d0236e4908ba0bf0fa16656be516e841d4) Thanks [@paales](https://github.com/paales)! - Updated dependencies
|
|
18
|
+
|
|
19
|
+
## 3.1.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- [#1379](https://github.com/graphcommerce-org/graphcommerce/pull/1379) [`104abd14e`](https://github.com/graphcommerce-org/graphcommerce/commit/104abd14e1585ef0d8de77937d25156b8fa1e201) Thanks [@paales](https://github.com/paales)! - useFormPersist no accepts a persist array to persist values even if they aren’t dirty anymore
|
|
24
|
+
|
|
25
|
+
* [#1379](https://github.com/graphcommerce-org/graphcommerce/pull/1379) [`2a125b1f9`](https://github.com/graphcommerce-org/graphcommerce/commit/2a125b1f98bb9272d96c3577f21d6c984caad892) Thanks [@paales](https://github.com/paales)! - ComposedSubmit uses the result of form.trigger() method to check if fomrs are valid before atempting to submit any form in the composition
|
|
26
|
+
|
|
3
27
|
## 3.0.7
|
|
4
28
|
|
|
5
29
|
### Patch 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": "3.
|
|
5
|
+
"version": "3.1.2",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": "14.x"
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@graphcommerce/eslint-config-pwa": "^4.1.
|
|
19
|
-
"@graphcommerce/prettier-config-pwa": "^4.0.
|
|
18
|
+
"@graphcommerce/eslint-config-pwa": "^4.1.6",
|
|
19
|
+
"@graphcommerce/prettier-config-pwa": "^4.0.6",
|
|
20
20
|
"@graphcommerce/typescript-config-pwa": "^4.0.2",
|
|
21
|
-
"@playwright/test": "^1.
|
|
22
|
-
"type-fest": "2.12.
|
|
21
|
+
"@playwright/test": "^1.21.1",
|
|
22
|
+
"type-fest": "^2.12.2"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@apollo/client": "^3.
|
|
26
|
-
"graphql": "
|
|
27
|
-
"react-hook-form": "7.
|
|
25
|
+
"@apollo/client": "^3.6.0",
|
|
26
|
+
"graphql": "16.4.0",
|
|
27
|
+
"react-hook-form": "7.30.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"react": "^17.0.2",
|
|
@@ -46,35 +46,62 @@ export function ComposedSubmit(props: ComposedSubmitProps) {
|
|
|
46
46
|
* If we have forms that are have errors, we don't need to actually submit anything yet. We can
|
|
47
47
|
* trigger the submission of the invalid forms and highlight the errors in those forms.
|
|
48
48
|
*/
|
|
49
|
-
|
|
50
|
-
([, f]) => Object.keys(f.form?.formState.errors ?? {}).length > 0,
|
|
51
|
-
)
|
|
49
|
+
dispatch({ type: 'SUBMIT' })
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const invalidKeys: string[] = []
|
|
52
|
+
for (const [, { form, key }] of formEntries) {
|
|
53
|
+
// eslint-disable-next-line no-await-in-loop
|
|
54
|
+
const result = await form?.trigger()
|
|
55
|
+
if (result === false) invalidKeys.push(key)
|
|
56
|
+
}
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
let formsToProcess = formEntries
|
|
59
|
+
if (invalidKeys.length === 0) {
|
|
60
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.log(
|
|
63
|
+
'[ComposedForm] All forms are valid, submitting...',
|
|
64
|
+
formsToProcess.map(([, { key }]) => key),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
formsToProcess = formEntries.filter(([, { key }]) => invalidKeys.includes(key))
|
|
69
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
70
|
+
// eslint-disable-next-line no-console
|
|
71
|
+
console.log(
|
|
72
|
+
'[ComposedForm] Found invalid forms, triggering error messages by submitting...',
|
|
73
|
+
Object.fromEntries(
|
|
74
|
+
formsToProcess.map(([, { key, form }]) => [
|
|
75
|
+
key,
|
|
76
|
+
`Invalid fields ${(form?.formState.errors
|
|
77
|
+
? Object.keys(form.formState.errors)
|
|
78
|
+
: []
|
|
79
|
+
).join(', ')}`,
|
|
80
|
+
]),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
57
85
|
|
|
58
86
|
try {
|
|
59
87
|
/**
|
|
60
88
|
* We're executing these steps all in sequence, since certain forms can depend on other forms
|
|
61
89
|
* in the backend.
|
|
62
|
-
*
|
|
63
|
-
* Todo: There might be a performance optimization by submitting multiple forms in parallel.
|
|
64
90
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
91
|
+
for (const [, { submit, key }] of formsToProcess) {
|
|
92
|
+
try {
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.log(`[ComposedForm] Submitting ${key}`)
|
|
95
|
+
// eslint-disable-next-line no-await-in-loop
|
|
96
|
+
await submit?.()
|
|
97
|
+
} catch (e) {
|
|
98
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
99
|
+
console.error(
|
|
100
|
+
`[ComposedForm] The form ${key} has thrown an Error during submission, halting submissions`,
|
|
101
|
+
e,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
throw e
|
|
78
105
|
}
|
|
79
106
|
}
|
|
80
107
|
dispatch({ type: 'SUBMITTING' })
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApolloError } from '@apollo/client'
|
|
2
|
-
import { FieldValues, FormState, UseFormReturn } from 'react-hook-form'
|
|
3
|
-
import { SetOptional } from 'type-fest'
|
|
2
|
+
import type { FieldValues, FormState, UseFormReturn } from 'react-hook-form'
|
|
3
|
+
import type { SetOptional } from 'type-fest'
|
|
4
4
|
|
|
5
5
|
export type UseFormComposeOptions<V extends FieldValues = FieldValues> = {
|
|
6
6
|
/** The form that is used to submit */
|
package/src/useFormPersist.tsx
CHANGED
|
@@ -5,22 +5,30 @@ import {
|
|
|
5
5
|
Path,
|
|
6
6
|
FieldPathValue,
|
|
7
7
|
UnpackNestedValue,
|
|
8
|
+
FieldPath,
|
|
8
9
|
} from 'react-hook-form'
|
|
9
10
|
|
|
10
|
-
export type UseFormPersistOptions<
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export type UseFormPersistOptions<
|
|
12
|
+
TFieldValues extends FieldValues = FieldValues,
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
TContext = any,
|
|
15
|
+
> = {
|
|
16
|
+
/** Instance of current form, used to watch value */
|
|
17
|
+
form: UseFormReturn<TFieldValues, TContext>
|
|
13
18
|
|
|
14
19
|
/** Name of the key how it will be stored in the storage. */
|
|
15
20
|
name: string
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
|
-
*
|
|
19
|
-
* Will be available when the user returns later.
|
|
23
|
+
* - `sessionStorage`: Will not be avaiable when the user returns later (recommended).
|
|
24
|
+
* - `localStorage`: Will be available when the user returns later.
|
|
20
25
|
*/
|
|
21
26
|
storage?: 'sessionStorage' | 'localStorage'
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
/** Exclude sensitive data from the storage like passwords. */
|
|
29
|
+
exclude?: FieldPath<TFieldValues>[]
|
|
30
|
+
|
|
31
|
+
persist?: FieldPath<TFieldValues>[]
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
/**
|
|
@@ -28,16 +36,24 @@ export type UseFormPersistOptions<V> = {
|
|
|
28
36
|
* dirty fields when the form is initialized
|
|
29
37
|
*/
|
|
30
38
|
export function useFormPersist<V>(options: UseFormPersistOptions<V>) {
|
|
31
|
-
const { form, name, storage = 'sessionStorage', exclude = [] } = options
|
|
39
|
+
const { form, name, storage = 'sessionStorage', exclude = [], persist = [] } = options
|
|
32
40
|
const { setValue, watch, formState } = form
|
|
33
41
|
|
|
34
42
|
const dirtyFieldKeys = Object.keys(formState.dirtyFields) as Path<V>[]
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
),
|
|
43
|
+
|
|
44
|
+
// Get all dirty field values and exclude sensitive data
|
|
45
|
+
const newValues = Object.fromEntries(
|
|
46
|
+
dirtyFieldKeys.filter((f) => !exclude.includes(f)).map((field) => [field, watch(field)]),
|
|
39
47
|
)
|
|
40
48
|
|
|
49
|
+
// Amend the values with the values that should always be persisted
|
|
50
|
+
persist.forEach((persistKey) => {
|
|
51
|
+
const value = watch(persistKey)
|
|
52
|
+
if (value) newValues[persistKey] = value
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const valuesJson = JSON.stringify(newValues)
|
|
56
|
+
|
|
41
57
|
// Restore changes
|
|
42
58
|
useEffect(() => {
|
|
43
59
|
try {
|
|
@@ -51,7 +67,12 @@ export function useFormPersist<V>(options: UseFormPersistOptions<V>) {
|
|
|
51
67
|
Path<V>,
|
|
52
68
|
UnpackNestedValue<FieldPathValue<V, Path<V>>>,
|
|
53
69
|
][]
|
|
54
|
-
entries.forEach((
|
|
70
|
+
entries.forEach(([entryName, value]) =>
|
|
71
|
+
setValue(entryName, value, {
|
|
72
|
+
shouldDirty: true,
|
|
73
|
+
shouldValidate: true,
|
|
74
|
+
}),
|
|
75
|
+
)
|
|
55
76
|
}
|
|
56
77
|
} catch {
|
|
57
78
|
//
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypedDocumentNode } from '@apollo/client'
|
|
1
|
+
import type { TypedDocumentNode } from '@apollo/client'
|
|
2
2
|
import {
|
|
3
3
|
DefinitionNode,
|
|
4
4
|
OperationDefinitionNode,
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
OperationTypeNode,
|
|
13
13
|
} from 'graphql'
|
|
14
14
|
import { useMemo } from 'react'
|
|
15
|
-
import { FieldValues } from 'react-hook-form'
|
|
16
|
-
import { LiteralUnion } from 'type-fest'
|
|
15
|
+
import type { FieldValues } from 'react-hook-form'
|
|
16
|
+
import type { LiteralUnion } from 'type-fest'
|
|
17
17
|
|
|
18
18
|
type Scalars = {
|
|
19
19
|
ID: string
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useLazyQuery,
|
|
8
8
|
} from '@apollo/client'
|
|
9
9
|
import { useEffect, useRef } from 'react'
|
|
10
|
-
import { Promisable } from 'type-fest'
|
|
10
|
+
import type { Promisable } from 'type-fest'
|
|
11
11
|
|
|
12
12
|
export type LazyQueryTuple<Q, V> = [
|
|
13
13
|
(options?: QueryLazyOptions<V>) => Promisable<LazyQueryResult<Q, V>>,
|