@graphcommerce/react-hook-form 10.0.0-canary.68 → 10.0.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.
- package/CHANGELOG.md +114 -0
- package/index.ts +0 -2
- package/package.json +4 -4
- package/src/ComposedForm/ComposedSubmit.tsx +27 -9
- package/src/ComposedForm/types.ts +3 -3
- package/src/useFormAutoSubmit.tsx +10 -3
- package/src/useFormGql.tsx +37 -30
- package/src/useFormGqlMutation.tsx +11 -21
- package/src/useFormGqlQuery.tsx +7 -9
- package/src/useFormMuiRegister.tsx +0 -25
- package/src/useFormValidFields.tsx +0 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,119 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 10.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#2546](https://github.com/graphcommerce-org/graphcommerce/pull/2546) [`ed9332a`](https://github.com/graphcommerce-org/graphcommerce/commit/ed9332a7f78966d932041d9a7725641edc92b28d) - ## GraphCommerce 10 - Turbopack Support
|
|
8
|
+
|
|
9
|
+
This major release brings full Turbopack compatibility, dramatically improving development speed.
|
|
10
|
+
|
|
11
|
+
### 🚀 Turbopack-Compatible Interceptor System
|
|
12
|
+
|
|
13
|
+
The entire plugin/interceptor system has been rewritten to work with Turbopack:
|
|
14
|
+
|
|
15
|
+
- **No more Webpack plugins** - Removed `InterceptorPlugin` webpack plugin entirely
|
|
16
|
+
- **File-based interception** - Original files are moved to `.original.tsx` and replaced with interceptor content
|
|
17
|
+
- **Direct imports** - Interceptors import from `.original` files instead of embedding source
|
|
18
|
+
- **New CLI commands**:
|
|
19
|
+
- `graphcommerce codegen-interceptors` - Generate interceptor files
|
|
20
|
+
- `graphcommerce cleanup-interceptors` - Reset interceptor system, restore original files
|
|
21
|
+
- **Stable file hashing** - Deterministic interceptor generation for better caching
|
|
22
|
+
|
|
23
|
+
### ⚙️ Treeshakable Configuration System
|
|
24
|
+
|
|
25
|
+
Replaced Webpack `DefinePlugin`-based `import.meta.graphCommerce` with a new generated configuration system:
|
|
26
|
+
|
|
27
|
+
- **New `codegen-config-values` command** - Generates TypeScript files with precise typing
|
|
28
|
+
- **Schema-driven** - Dynamically introspects Zod schemas to determine all available properties
|
|
29
|
+
- **Fully treeshakable** - Unused config values are eliminated from the bundle
|
|
30
|
+
- **Type-safe** - Uses `Get<GraphCommerceConfig, 'path'>` for nested property access
|
|
31
|
+
- **Separate files for nested objects** - Optimal treeshaking for complex configurations
|
|
32
|
+
|
|
33
|
+
### 🔧 withGraphCommerce Changes
|
|
34
|
+
|
|
35
|
+
- **Removed** `InterceptorPlugin` - No longer needed with file-based interception
|
|
36
|
+
- **Removed** `DefinePlugin` for `import.meta.graphCommerce` - Replaced with generated config
|
|
37
|
+
- **Removed** `@mui/*` alias rewrites - No longer required
|
|
38
|
+
- **Added** Turbopack loader rules for `.yaml`, `.yml`, and `.po` files
|
|
39
|
+
- **Added** `serverExternalPackages` for all `@whatwg-node/*` packages
|
|
40
|
+
- **Added** `optimizePackageImports` for better bundle optimization
|
|
41
|
+
- **Added** `images.qualities: [52, 75]` for Next.js image optimization
|
|
42
|
+
|
|
43
|
+
### 📦 Lingui Configuration
|
|
44
|
+
|
|
45
|
+
- **Renamed** `lingui.config.js` → `lingui.config.ts` with TypeScript support
|
|
46
|
+
- **Updated** `@graphcommerce/lingui-next/config` to TypeScript with proper exports
|
|
47
|
+
- **Simplified** formatter options
|
|
48
|
+
|
|
49
|
+
### ⚛️ React 19 & Next.js 16 Compatibility
|
|
50
|
+
|
|
51
|
+
- Updated `RefObject<T>` types for React 19 (now includes `null` by default)
|
|
52
|
+
- Replaced deprecated `React.VFC` with `React.FC`
|
|
53
|
+
- Fixed `useRef` calls to require explicit initial values
|
|
54
|
+
- Updated `MutableRefObject` usage in `framer-scroller`
|
|
55
|
+
|
|
56
|
+
### 📋 ESLint 9 Flat Config
|
|
57
|
+
|
|
58
|
+
- Migrated from legacy `.eslintrc` to new flat config format (`eslint.config.mjs`)
|
|
59
|
+
- Updated `@typescript-eslint/*` packages to v8
|
|
60
|
+
- Fixed AST selector for `SxProps` rule (`typeParameters` → `typeArguments`)
|
|
61
|
+
|
|
62
|
+
### 🔄 Apollo Client
|
|
63
|
+
|
|
64
|
+
- Fixed deprecated `name` option → `clientAwareness: { name: 'ssr' }`
|
|
65
|
+
- Updated error handling types to accept `ApolloError | null | undefined`
|
|
66
|
+
|
|
67
|
+
### ⚠️ Breaking Changes
|
|
68
|
+
|
|
69
|
+
- **Node.js 24.x not supported** - Restricted to `>=20 <24.0.0` due to [nodejs/undici#4290](https://github.com/nodejs/undici/issues/4290)
|
|
70
|
+
- **Interceptor files changed** - Original components now at `.original.tsx`
|
|
71
|
+
- **Config access changed** - Use generated config values instead of `import.meta.graphCommerce`
|
|
72
|
+
- **ESLint config format** - Must use flat config (`eslint.config.mjs`)
|
|
73
|
+
- **Lingui config** - Rename `lingui.config.js` to `lingui.config.ts`
|
|
74
|
+
|
|
75
|
+
### 🗑️ Removed
|
|
76
|
+
|
|
77
|
+
- `InterceptorPlugin` webpack plugin
|
|
78
|
+
- `configToImportMeta` utility
|
|
79
|
+
- Webpack `DefinePlugin` usage for config
|
|
80
|
+
- `@mui/*` modern alias rewrites
|
|
81
|
+
- Debug plugins (`CircularDependencyPlugin`, `DuplicatesPlugin`) ([@paales](https://github.com/paales))
|
|
82
|
+
|
|
83
|
+
- [#2565](https://github.com/graphcommerce-org/graphcommerce/pull/2565) [`c96dfcd`](https://github.com/graphcommerce-org/graphcommerce/commit/c96dfcdca981baca387c270ad9e2b9515cdd00cc) - Updated to Apollo Client 4 ([@paales](https://github.com/paales))
|
|
84
|
+
|
|
85
|
+
### Patch Changes
|
|
86
|
+
|
|
87
|
+
- [#2487](https://github.com/graphcommerce-org/graphcommerce/pull/2487) [`935f8f9`](https://github.com/graphcommerce-org/graphcommerce/commit/935f8f9ebe5e79b336e56d40cb1ec96ce17b84d7) - Remove dependency on Magento for @graphcommerec/react-hook-form ([@paales](https://github.com/paales))
|
|
88
|
+
|
|
89
|
+
- [`9aa9a3c`](https://github.com/graphcommerce-org/graphcommerce/commit/9aa9a3cc25c121e217f64efc0cfd19e3b90d15aa) - useFormGql and all derivivatives now get the form as an argument in onComplete for easier form resets. ([@paales](https://github.com/paales))
|
|
90
|
+
|
|
91
|
+
- [#2539](https://github.com/graphcommerce-org/graphcommerce/pull/2539) [`5036171`](https://github.com/graphcommerce-org/graphcommerce/commit/5036171618492d7587cc02c557a4e9343e8240cd) - Fix typescript infer ([@paales](https://github.com/paales))
|
|
92
|
+
|
|
93
|
+
- [#2539](https://github.com/graphcommerce-org/graphcommerce/pull/2539) [`31ef9c5`](https://github.com/graphcommerce-org/graphcommerce/commit/31ef9c59b18dd58fbb3625abf586f0a53f3d63cb) - Solve an issue where the false value of the useFormGql was incorrectly interpreted as an error while it was a SKIP. Fixes an issue where the CustomerAddressForm is not submitting properly when the user is adding a new address. ([@paales](https://github.com/paales))
|
|
94
|
+
|
|
95
|
+
- [#2567](https://github.com/graphcommerce-org/graphcommerce/pull/2567) [`41f9619`](https://github.com/graphcommerce-org/graphcommerce/commit/41f96194a5740465663d8f8e5ee1c10af0365748) - Fix issue where FormAutoSubmit would not listen for changes when no field names were provided (meaning it should watch changes on all fields) ([@paales](https://github.com/paales))
|
|
96
|
+
|
|
97
|
+
- [#2539](https://github.com/graphcommerce-org/graphcommerce/pull/2539) [`9bf02b6`](https://github.com/graphcommerce-org/graphcommerce/commit/9bf02b6dd20c086db0c93fe9efea140b673bc4a2) - Solve issue with react-hook-form causing ts errors, now version is fixed and the ts error is solved ([@paales](https://github.com/paales))
|
|
98
|
+
|
|
99
|
+
- [#2477](https://github.com/graphcommerce-org/graphcommerce/pull/2477) [`8015eab`](https://github.com/graphcommerce-org/graphcommerce/commit/8015eabc130dacf1f2703980cd5f0ad2c550aa4d) - Upgraded to @apollo/client 3.12.3 without impacting typescript compilation performance. ([@paales](https://github.com/paales))
|
|
100
|
+
|
|
101
|
+
## 10.0.0-canary.72
|
|
102
|
+
|
|
103
|
+
## 10.0.0-canary.71
|
|
104
|
+
|
|
105
|
+
## 10.0.0-canary.70
|
|
106
|
+
|
|
107
|
+
### Major Changes
|
|
108
|
+
|
|
109
|
+
- [#2565](https://github.com/graphcommerce-org/graphcommerce/pull/2565) [`c96dfcd`](https://github.com/graphcommerce-org/graphcommerce/commit/c96dfcdca981baca387c270ad9e2b9515cdd00cc) - Updated to Apollo Client 4 ([@paales](https://github.com/paales))
|
|
110
|
+
|
|
111
|
+
## 10.0.0-canary.69
|
|
112
|
+
|
|
113
|
+
### Patch Changes
|
|
114
|
+
|
|
115
|
+
- [#2567](https://github.com/graphcommerce-org/graphcommerce/pull/2567) [`41f9619`](https://github.com/graphcommerce-org/graphcommerce/commit/41f96194a5740465663d8f8e5ee1c10af0365748) - Fix issue where FormAutoSubmit would not listen for changes when no field names were provided (meaning it should watch changes on all fields) ([@paales](https://github.com/paales))
|
|
116
|
+
|
|
3
117
|
## 10.0.0-canary.68
|
|
4
118
|
|
|
5
119
|
## 10.0.0-canary.67
|
package/index.ts
CHANGED
|
@@ -5,9 +5,7 @@ export * from './src/useFormAutoSubmit'
|
|
|
5
5
|
export * from './src/useFormGql'
|
|
6
6
|
export * from './src/useFormGqlMutation'
|
|
7
7
|
export * from './src/useFormGqlQuery'
|
|
8
|
-
export * from './src/useFormMuiRegister'
|
|
9
8
|
export * from './src/useFormPersist'
|
|
10
|
-
export * from './src/useFormValidFields'
|
|
11
9
|
export * from './src/utils/tryTuple'
|
|
12
10
|
export * from './src/utils/useDebounce'
|
|
13
11
|
export * from './src/validationPatterns'
|
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": "10.0.0
|
|
5
|
+
"version": "10.0.0",
|
|
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": "^10.0.0
|
|
17
|
-
"@graphcommerce/prettier-config-pwa": "^10.0.0
|
|
18
|
-
"@graphcommerce/typescript-config-pwa": "^10.0.0
|
|
16
|
+
"@graphcommerce/eslint-config-pwa": "^10.0.0",
|
|
17
|
+
"@graphcommerce/prettier-config-pwa": "^10.0.0",
|
|
18
|
+
"@graphcommerce/typescript-config-pwa": "^10.0.0",
|
|
19
19
|
"@mui/utils": "^7.0.0",
|
|
20
20
|
"graphql": "^16.6.0",
|
|
21
21
|
"react": "^19.2.0",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { ErrorLike } from '@apollo/client'
|
|
2
|
+
import { CombinedGraphQLErrors } from '@apollo/client/errors'
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
import { useContext, useEffect, useRef } from 'react'
|
|
3
5
|
import { isFormGqlOperation } from '../useFormGqlMutation'
|
|
4
6
|
import { composedFormContext } from './context'
|
|
5
7
|
import type { ComposedSubmitRenderComponentProps } from './types'
|
|
@@ -9,13 +11,29 @@ export type ComposedSubmitProps = {
|
|
|
9
11
|
render: React.FC<ComposedSubmitRenderComponentProps>
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export function mergeErrors(errors:
|
|
14
|
+
export function mergeErrors(errors: ErrorLike[]): ErrorLike | undefined {
|
|
13
15
|
if (!errors.length) return undefined
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
// Collect all GraphQL errors from CombinedGraphQLErrors instances
|
|
18
|
+
const graphQLErrors = errors.flatMap((error) =>
|
|
19
|
+
CombinedGraphQLErrors.is(error) ? error.errors : [],
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// Collect non-GraphQL errors (network errors, etc.)
|
|
23
|
+
const nonGraphQLErrors = errors.filter((error) => !CombinedGraphQLErrors.is(error))
|
|
24
|
+
|
|
25
|
+
// If we have GraphQL errors, return a CombinedGraphQLErrors
|
|
26
|
+
// Include non-GraphQL error messages as additional GraphQL errors to avoid losing them
|
|
27
|
+
if (graphQLErrors.length > 0) {
|
|
28
|
+
const allErrors = [
|
|
29
|
+
...graphQLErrors,
|
|
30
|
+
...nonGraphQLErrors.map((error) => ({ message: error.message })),
|
|
31
|
+
]
|
|
32
|
+
return new CombinedGraphQLErrors({ errors: allErrors })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If we only have non-GraphQL errors, return the first one
|
|
36
|
+
return nonGraphQLErrors[0]
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
export function ComposedSubmit(props: ComposedSubmitProps) {
|
|
@@ -118,7 +136,7 @@ export function ComposedSubmit(props: ComposedSubmitProps) {
|
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
|
|
121
|
-
const errors:
|
|
139
|
+
const errors: ErrorLike[] = []
|
|
122
140
|
|
|
123
141
|
formEntries.forEach(([, { form }]) => {
|
|
124
142
|
if (form && isFormGqlOperation(form) && form.error) errors.push(form.error)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ErrorLike } from '@apollo/client'
|
|
2
2
|
import type { FieldValues, FormState, UseFormHandleSubmit, UseFormTrigger } from 'react-hook-form'
|
|
3
3
|
import type { SetOptional } from 'type-fest'
|
|
4
4
|
|
|
@@ -40,7 +40,7 @@ export type ButtonState = {
|
|
|
40
40
|
export type ComposedSubmitRenderComponentProps = {
|
|
41
41
|
submit: () => Promise<void>
|
|
42
42
|
buttonState: ButtonState
|
|
43
|
-
error?:
|
|
43
|
+
error?: ErrorLike
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export type ComposedFormState = {
|
|
@@ -51,7 +51,7 @@ export type ComposedFormState = {
|
|
|
51
51
|
buttonState: ButtonState
|
|
52
52
|
formState: FormStateAll
|
|
53
53
|
submitted: boolean
|
|
54
|
-
error?:
|
|
54
|
+
error?: ErrorLike
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/** Register a new form with the useFormCompose hook */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react/no-unused-prop-types */
|
|
2
2
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
3
|
import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject'
|
|
4
|
-
import { cloneDeep } from '@apollo/client/utilities'
|
|
4
|
+
import { cloneDeep } from '@apollo/client/utilities/internal'
|
|
5
5
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
6
|
import { debounce } from '@mui/material'
|
|
7
7
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
@@ -143,12 +143,19 @@ function useAutoSubmitBase<TFieldValues extends FieldValues = FieldValues>(
|
|
|
143
143
|
submit,
|
|
144
144
|
parallel,
|
|
145
145
|
noValidate,
|
|
146
|
-
name
|
|
146
|
+
name,
|
|
147
147
|
...watchOptions
|
|
148
148
|
} = props
|
|
149
149
|
|
|
150
150
|
// We create a stable object from the values, so that we can compare them later
|
|
151
|
-
const values = useMemoObject(
|
|
151
|
+
const values = useMemoObject(
|
|
152
|
+
cloneDeep(
|
|
153
|
+
useWatch({
|
|
154
|
+
...watchOptions,
|
|
155
|
+
name: name as Path<TFieldValues>[],
|
|
156
|
+
}),
|
|
157
|
+
),
|
|
158
|
+
)
|
|
152
159
|
const oldValues = useRef<PathValue<TFieldValues, Path<TFieldValues>>[]>(values)
|
|
153
160
|
const { isValidating, isSubmitting, isValid } = useFormState(watchOptions)
|
|
154
161
|
|
package/src/useFormGql.tsx
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
MaybeMasked,
|
|
6
|
-
MutationHookOptions,
|
|
7
|
-
MutationTuple,
|
|
8
|
-
TypedDocumentNode,
|
|
9
|
-
} from '@apollo/client'
|
|
10
|
-
import { ApolloError, isApolloError } from '@apollo/client'
|
|
11
|
-
import { getOperationName } from '@apollo/client/utilities'
|
|
1
|
+
import { getOperationName } from '@graphcommerce/graphql/apollo'
|
|
2
|
+
import type { ApolloLink, ErrorLike, MaybeMasked, TypedDocumentNode } from '@apollo/client'
|
|
3
|
+
import { CombinedGraphQLErrors } from '@apollo/client/errors'
|
|
4
|
+
import type { useLazyQuery, useMutation } from '@apollo/client/react'
|
|
12
5
|
import useEventCallback from '@mui/utils/useEventCallback'
|
|
13
6
|
import { useEffect, useRef } from 'react'
|
|
14
7
|
import type { DefaultValues, FieldValues, UseFormProps, UseFormReturn } from 'react-hook-form'
|
|
@@ -23,16 +16,16 @@ type UseFormGraphQLCallbacks<Q, V extends FieldValues> = {
|
|
|
23
16
|
* Mutation.
|
|
24
17
|
*
|
|
25
18
|
* When returning false, it will SKIP the submission. When an Error is thrown, it will be set as
|
|
26
|
-
* an
|
|
19
|
+
* an error.
|
|
27
20
|
*/
|
|
28
21
|
onBeforeSubmit?: (variables: V, form?: UseFormReturn<V>) => V | false | Promise<V | false>
|
|
29
22
|
/**
|
|
30
23
|
* Called after the mutation has been executed. Allows you to handle the result of the mutation.
|
|
31
24
|
*
|
|
32
|
-
* When an error is thrown, it will be set as an
|
|
25
|
+
* When an error is thrown, it will be set as an error
|
|
33
26
|
*/
|
|
34
27
|
onComplete?: (
|
|
35
|
-
result:
|
|
28
|
+
result: ApolloLink.Result<MaybeMasked<Q>>,
|
|
36
29
|
variables: V,
|
|
37
30
|
form?: UseFormReturn<V>,
|
|
38
31
|
) => void | Promise<void>
|
|
@@ -60,7 +53,7 @@ type UseFormGraphQLCallbacks<Q, V extends FieldValues> = {
|
|
|
60
53
|
* const result = mutate() // executes the mutation and automatically sets generic errors with setError('root')
|
|
61
54
|
* // onComplete: now simply use the result after the form, to for example reset the form, or do other things.
|
|
62
55
|
* })
|
|
63
|
-
*
|
|
56
|
+
* ```
|
|
64
57
|
*/
|
|
65
58
|
experimental_useV2?: boolean
|
|
66
59
|
/**
|
|
@@ -82,14 +75,17 @@ type UseFormGraphQLCallbacks<Q, V extends FieldValues> = {
|
|
|
82
75
|
export type UseFormGraphQlOptions<Q, V extends FieldValues> = UseFormProps<V> &
|
|
83
76
|
UseFormGraphQLCallbacks<Q, V>
|
|
84
77
|
|
|
78
|
+
export const UseFormGqlSymbol = Symbol('UseFormGql')
|
|
79
|
+
|
|
85
80
|
export type UseFormGqlMethods<Q, V extends FieldValues> = Omit<
|
|
86
81
|
UseGqlDocumentHandler<V>,
|
|
87
82
|
'encode' | 'type'
|
|
88
83
|
> &
|
|
89
84
|
Pick<UseFormReturn<V>, 'handleSubmit'> & {
|
|
90
85
|
data?: MaybeMasked<Q> | null
|
|
91
|
-
error?:
|
|
86
|
+
error?: ErrorLike | null
|
|
92
87
|
submittedVariables?: V | null
|
|
88
|
+
[UseFormGqlSymbol]: true
|
|
93
89
|
}
|
|
94
90
|
|
|
95
91
|
/**
|
|
@@ -104,10 +100,12 @@ export function useFormGql<Q, V extends FieldValues>(
|
|
|
104
100
|
options: {
|
|
105
101
|
document: TypedDocumentNode<Q, V>
|
|
106
102
|
form: UseFormReturn<V>
|
|
107
|
-
tuple:
|
|
103
|
+
tuple:
|
|
104
|
+
| useMutation.ResultTuple<Q, V>
|
|
105
|
+
| useLazyQuery.ResultTuple<Q, V, 'streaming' | 'complete' | 'empty'>
|
|
108
106
|
operationOptions?:
|
|
109
|
-
| Omit<
|
|
110
|
-
| Omit<
|
|
107
|
+
| Omit<useMutation.Options<Q, V>, 'fetchPolicy' | 'variables'>
|
|
108
|
+
| Omit<useLazyQuery.Options<Q, V>, 'fetchPolicy' | 'variables'>
|
|
111
109
|
defaultValues?: UseFormProps<V>['defaultValues']
|
|
112
110
|
skipUnchanged?: boolean
|
|
113
111
|
} & UseFormGraphQLCallbacks<Q, V>,
|
|
@@ -127,7 +125,7 @@ export function useFormGql<Q, V extends FieldValues>(
|
|
|
127
125
|
const [execute, { data, error, loading }] = tuple
|
|
128
126
|
|
|
129
127
|
const submittedVariables = useRef<V | null>(null)
|
|
130
|
-
const returnedError = useRef<
|
|
128
|
+
const returnedError = useRef<ErrorLike | null>(null)
|
|
131
129
|
|
|
132
130
|
// automatically updates the default values
|
|
133
131
|
const initital = useRef(true)
|
|
@@ -175,16 +173,17 @@ export function useFormGql<Q, V extends FieldValues>(
|
|
|
175
173
|
// Wait for the onBeforeSubmit to complete
|
|
176
174
|
const [onBeforeSubmitResult, onBeforeSubmitError] = await beforeSubmit(variables, form)
|
|
177
175
|
if (onBeforeSubmitError) {
|
|
178
|
-
if
|
|
176
|
+
// Check if it's a GraphQL error or a regular error
|
|
177
|
+
if (CombinedGraphQLErrors.is(onBeforeSubmitError)) {
|
|
179
178
|
returnedError.current = onBeforeSubmitError
|
|
180
179
|
form.setError('root', { message: onBeforeSubmitError.message })
|
|
181
180
|
} else {
|
|
182
181
|
const message =
|
|
183
182
|
process.env.NODE_ENV === 'development'
|
|
184
|
-
? `
|
|
183
|
+
? `An error was thrown during the onBeforeSubmit handler: ${onBeforeSubmitError.message}`
|
|
185
184
|
: 'An unexpected error occurred, please contact the store owner'
|
|
186
185
|
form.setError('root', { message })
|
|
187
|
-
returnedError.current = new
|
|
186
|
+
returnedError.current = new CombinedGraphQLErrors({ errors: [{ message }] })
|
|
188
187
|
}
|
|
189
188
|
return
|
|
190
189
|
}
|
|
@@ -201,32 +200,39 @@ export function useFormGql<Q, V extends FieldValues>(
|
|
|
201
200
|
...operationOptions,
|
|
202
201
|
variables,
|
|
203
202
|
context: {
|
|
204
|
-
...operationOptions?.context,
|
|
203
|
+
...(operationOptions as { context?: Record<string, unknown> } | undefined)?.context,
|
|
205
204
|
fetchOptions: {
|
|
206
|
-
...
|
|
205
|
+
...(
|
|
206
|
+
operationOptions as
|
|
207
|
+
| { context?: { fetchOptions?: Record<string, unknown> } }
|
|
208
|
+
| undefined
|
|
209
|
+
)?.context?.fetchOptions,
|
|
207
210
|
signal: controllerRef.current.signal,
|
|
208
211
|
},
|
|
209
212
|
},
|
|
210
213
|
})
|
|
211
214
|
|
|
212
215
|
// If there are submission errors, set the error and return
|
|
213
|
-
if (result.
|
|
214
|
-
|
|
216
|
+
if (result.error) {
|
|
217
|
+
const errorMessage = CombinedGraphQLErrors.is(result.error)
|
|
218
|
+
? result.error.errors.map((e) => e.message).join(', ')
|
|
219
|
+
: result.error.message
|
|
220
|
+
form.setError('root', { message: errorMessage })
|
|
215
221
|
return
|
|
216
222
|
}
|
|
217
223
|
|
|
218
224
|
const [, onCompleteError] = await complete(result, variables, form)
|
|
219
225
|
if (onCompleteError) {
|
|
220
|
-
if (
|
|
226
|
+
if (CombinedGraphQLErrors.is(onCompleteError)) {
|
|
221
227
|
returnedError.current = onCompleteError
|
|
222
228
|
form.setError('root', { message: onCompleteError.message })
|
|
223
229
|
} else {
|
|
224
230
|
const message =
|
|
225
231
|
process.env.NODE_ENV === 'development'
|
|
226
|
-
? `
|
|
232
|
+
? `An error was thrown during the onComplete handler: ${onCompleteError.message}`
|
|
227
233
|
: 'An unexpected error occurred, please contact the store owner'
|
|
228
234
|
form.setError('root', { message })
|
|
229
|
-
returnedError.current = new
|
|
235
|
+
returnedError.current = new CombinedGraphQLErrors({ errors: [{ message }] })
|
|
230
236
|
}
|
|
231
237
|
return
|
|
232
238
|
}
|
|
@@ -244,5 +250,6 @@ export function useFormGql<Q, V extends FieldValues>(
|
|
|
244
250
|
data,
|
|
245
251
|
error: returnedError.current ?? error,
|
|
246
252
|
submittedVariables: submittedVariables.current,
|
|
253
|
+
[UseFormGqlSymbol]: true,
|
|
247
254
|
}
|
|
248
255
|
}
|
|
@@ -1,52 +1,42 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { useMutation } from '@apollo/client'
|
|
1
|
+
import type { TypedDocumentNode } from '@apollo/client'
|
|
2
|
+
import type { useMutation } from '@apollo/client/react'
|
|
3
|
+
import { useMutation as useMutationHook } from '@apollo/client/react'
|
|
3
4
|
import type { FieldValues, UseFormReturn } from 'react-hook-form'
|
|
4
5
|
import { useForm } from 'react-hook-form'
|
|
5
6
|
import type { UseFormGqlMethods, UseFormGraphQlOptions } from './useFormGql'
|
|
6
|
-
import { useFormGql } from './useFormGql'
|
|
7
|
-
import type { UseMuiFormRegister } from './useFormMuiRegister'
|
|
8
|
-
import { useFormMuiRegister } from './useFormMuiRegister'
|
|
9
|
-
import type { UseFormValidReturn } from './useFormValidFields'
|
|
7
|
+
import { useFormGql, UseFormGqlSymbol } from './useFormGql'
|
|
10
8
|
|
|
11
9
|
export type UseFormGqlMutationReturn<
|
|
12
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
11
|
Q extends Record<string, any> = Record<string, any>,
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
12
|
V extends FieldValues = FieldValues,
|
|
16
|
-
> = UseFormGqlMethods<Q, V>
|
|
17
|
-
UseFormReturn<V> & {
|
|
18
|
-
/** @deprecated Please use TextFieldElement */
|
|
19
|
-
muiRegister: UseMuiFormRegister<V>
|
|
20
|
-
/** @deprecated Please use TextFieldElement showValid */
|
|
21
|
-
valid: UseFormValidReturn<V>
|
|
22
|
-
}
|
|
13
|
+
> = Omit<UseFormReturn<V>, 'handleSubmit'> & UseFormGqlMethods<Q, V>
|
|
23
14
|
|
|
24
15
|
export function isFormGqlOperation<
|
|
25
16
|
V extends FieldValues,
|
|
26
17
|
Q extends Record<string, unknown> = Record<string, unknown>,
|
|
27
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
|
|
28
19
|
>(form: any): form is UseFormGqlMutationReturn<Q, V> {
|
|
29
|
-
return
|
|
20
|
+
return (form as UseFormGqlMutationReturn<Q, V>)[UseFormGqlSymbol] === true
|
|
30
21
|
}
|
|
31
22
|
|
|
32
23
|
export function assertFormGqlOperation<
|
|
33
24
|
V extends FieldValues,
|
|
34
25
|
Q extends Record<string, unknown> = Record<string, unknown>,
|
|
35
26
|
>(form: UseFormReturn<V>): asserts form is UseFormGqlMutationReturn<Q, V> {
|
|
36
|
-
if (
|
|
27
|
+
if (!isFormGqlOperation(form))
|
|
37
28
|
throw Error("form must be one of 'useFromGqlMutation' or 'useFormGqlQuery'")
|
|
38
|
-
}
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
/** Bindings between react-hook-form's useForm and Apollo Client's useMutation hook. */
|
|
42
32
|
export function useFormGqlMutation<Q extends Record<string, unknown>, V extends FieldValues>(
|
|
43
33
|
document: TypedDocumentNode<Q, V>,
|
|
44
34
|
options: NoInfer<UseFormGraphQlOptions<Q, V>> = {},
|
|
45
|
-
operationOptions?:
|
|
35
|
+
operationOptions?: useMutation.Options<NoInfer<Q>, NoInfer<V>>,
|
|
46
36
|
): UseFormGqlMutationReturn<Q, V> {
|
|
47
37
|
const form = useForm<V>(options)
|
|
48
|
-
const tuple =
|
|
38
|
+
const tuple = useMutationHook<Q, V>(document, operationOptions as useMutation.Options<Q, V>)
|
|
49
39
|
const operation = useFormGql({ document, form, tuple, operationOptions, ...options })
|
|
50
|
-
|
|
51
|
-
return { ...form, ...operation
|
|
40
|
+
// operation.handleSubmit overrides form.handleSubmit
|
|
41
|
+
return { ...form, ...operation } as unknown as UseFormGqlMutationReturn<Q, V>
|
|
52
42
|
}
|
package/src/useFormGqlQuery.tsx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { useLazyQuery } from '@apollo/client'
|
|
1
|
+
import type { TypedDocumentNode } from '@apollo/client'
|
|
2
|
+
import type { useLazyQuery } from '@apollo/client/react'
|
|
3
|
+
import { useLazyQuery as useLazyQueryHook } from '@apollo/client/react'
|
|
3
4
|
import type { FieldValues } from 'react-hook-form'
|
|
4
5
|
import { useForm } from 'react-hook-form'
|
|
5
6
|
import type { UseFormGraphQlOptions } from './useFormGql'
|
|
6
7
|
import { useFormGql } from './useFormGql'
|
|
7
|
-
import type
|
|
8
|
-
import { useFormMuiRegister } from './useFormMuiRegister'
|
|
8
|
+
import { type UseFormGqlMutationReturn } from './useFormGqlMutation'
|
|
9
9
|
|
|
10
10
|
export type UseFormGqlQueryReturn<
|
|
11
11
|
Q extends Record<string, unknown>,
|
|
@@ -15,12 +15,10 @@ export type UseFormGqlQueryReturn<
|
|
|
15
15
|
export function useFormGqlQuery<Q extends Record<string, unknown>, V extends FieldValues>(
|
|
16
16
|
document: TypedDocumentNode<Q, V>,
|
|
17
17
|
options: UseFormGraphQlOptions<Q, V> = {},
|
|
18
|
-
operationOptions?:
|
|
18
|
+
operationOptions?: useLazyQuery.Options<Q, V>,
|
|
19
19
|
): UseFormGqlQueryReturn<Q, V> {
|
|
20
20
|
const form = useForm<V>(options)
|
|
21
|
-
const tuple =
|
|
21
|
+
const tuple = useLazyQueryHook(document, { ...operationOptions })
|
|
22
22
|
const operation = useFormGql({ document, form, tuple, operationOptions, ...options })
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return { ...form, ...operation, valid: {}, muiRegister }
|
|
23
|
+
return { ...form, ...operation }
|
|
26
24
|
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
FieldPath,
|
|
3
|
-
FieldValues,
|
|
4
|
-
RegisterOptions,
|
|
5
|
-
UseFormRegisterReturn,
|
|
6
|
-
UseFormReturn,
|
|
7
|
-
} from 'react-hook-form'
|
|
8
|
-
|
|
9
|
-
export type UseMuiFormRegister<TFieldValues extends FieldValues> = <
|
|
10
|
-
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
11
|
-
>(
|
|
12
|
-
name: TFieldName,
|
|
13
|
-
options?: RegisterOptions<TFieldValues, TFieldName>,
|
|
14
|
-
) => Omit<UseFormRegisterReturn, 'ref'> & { inputRef: UseFormRegisterReturn['ref'] }
|
|
15
|
-
|
|
16
|
-
/** @deprecated Please use use TextFieldElement, etc. */
|
|
17
|
-
export function useFormMuiRegister<V extends FieldValues>({
|
|
18
|
-
register,
|
|
19
|
-
}: Pick<UseFormReturn<V>, 'register'>) {
|
|
20
|
-
const muiRegister: UseMuiFormRegister<V> = (name, opts) => {
|
|
21
|
-
const { ref: inputRef, ...fields } = register(name, opts)
|
|
22
|
-
return { ...fields, inputRef }
|
|
23
|
-
}
|
|
24
|
-
return muiRegister
|
|
25
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { FieldPath, FieldValues, UseFormReturn } from 'react-hook-form'
|
|
2
|
-
import type { IsRequired } from './useGqlDocumentHandler'
|
|
3
|
-
|
|
4
|
-
export type UseFormValidReturn<TFieldValues extends FieldValues> = Partial<
|
|
5
|
-
Record<FieldPath<TFieldValues>, boolean>
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* ### useFormValidFields
|
|
10
|
-
*
|
|
11
|
-
* Record field names as key and boolean as value indicating whether the field is valid
|
|
12
|
-
*
|
|
13
|
-
* @deprecated Please use TextInputElement, SelectElement, etc. with the showValid prop
|
|
14
|
-
* @public
|
|
15
|
-
*/
|
|
16
|
-
export function useFormValidFields<TFieldValues extends FieldValues>(
|
|
17
|
-
form: Pick<UseFormReturn<TFieldValues>, 'watch' | 'formState'>,
|
|
18
|
-
required: IsRequired<TFieldValues>,
|
|
19
|
-
): UseFormValidReturn<TFieldValues> {
|
|
20
|
-
const { watch, formState } = form
|
|
21
|
-
const fields: Partial<Record<FieldPath<TFieldValues>, boolean>> = {}
|
|
22
|
-
|
|
23
|
-
Object.keys(required).forEach((key) => {
|
|
24
|
-
fields[key] = !formState.errors[key] && watch(key as FieldPath<TFieldValues>)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
return fields
|
|
28
|
-
}
|