@tanstack/react-form 0.13.6 → 0.14.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/dist/cjs/createFormFactory.cjs.map +1 -1
- package/dist/cjs/createFormFactory.d.cts +3 -3
- package/dist/cjs/types.d.cts +2 -2
- package/dist/cjs/useField.cjs +5 -28
- package/dist/cjs/useField.cjs.map +1 -1
- package/dist/cjs/useField.d.cts +4 -12
- package/dist/cjs/useForm.cjs +4 -6
- package/dist/cjs/useForm.cjs.map +1 -1
- package/dist/cjs/useForm.d.cts +14 -4
- package/dist/esm/createFormFactory.d.ts +3 -3
- package/dist/esm/createFormFactory.js.map +1 -1
- package/dist/esm/types.d.ts +2 -2
- package/dist/esm/useField.d.ts +4 -12
- package/dist/esm/useField.js +7 -30
- package/dist/esm/useField.js.map +1 -1
- package/dist/esm/useForm.d.ts +14 -4
- package/dist/esm/useForm.js +4 -6
- package/dist/esm/useForm.js.map +1 -1
- package/package.json +3 -3
- package/src/createFormFactory.ts +4 -4
- package/src/tests/createFormFactory.test.tsx +4 -5
- package/src/tests/useField.test-d.tsx +5 -5
- package/src/tests/useField.test.tsx +257 -32
- package/src/tests/useForm.test-d.tsx +1 -1
- package/src/tests/useForm.test.tsx +48 -25
- package/src/types.ts +8 -2
- package/src/useField.tsx +26 -68
- package/src/useForm.tsx +19 -14
- package/dist/cjs/formContext.cjs +0 -14
- package/dist/cjs/formContext.cjs.map +0 -1
- package/dist/cjs/formContext.d.cts +0 -10
- package/dist/cjs/useIsomorphicEffectOnce.cjs +0 -30
- package/dist/cjs/useIsomorphicEffectOnce.cjs.map +0 -1
- package/dist/cjs/useIsomorphicEffectOnce.d.cts +0 -5
- package/dist/esm/formContext.d.ts +0 -10
- package/dist/esm/formContext.js +0 -14
- package/dist/esm/formContext.js.map +0 -1
- package/dist/esm/useIsomorphicEffectOnce.d.ts +0 -5
- package/dist/esm/useIsomorphicEffectOnce.js +0 -30
- package/dist/esm/useIsomorphicEffectOnce.js.map +0 -1
- package/src/formContext.ts +0 -17
- package/src/useIsomorphicEffectOnce.ts +0 -39
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
3
|
import { render, waitFor } from '@testing-library/react'
|
|
4
4
|
import userEvent from '@testing-library/user-event'
|
|
5
|
-
import * as React from 'react'
|
|
6
5
|
import { createFormFactory, useForm } from '../index'
|
|
7
6
|
import { sleep } from './utils'
|
|
8
7
|
|
|
@@ -21,7 +20,7 @@ describe('useForm', () => {
|
|
|
21
20
|
const form = formFactory.useForm()
|
|
22
21
|
|
|
23
22
|
return (
|
|
24
|
-
|
|
23
|
+
<>
|
|
25
24
|
<form.Field
|
|
26
25
|
name="firstName"
|
|
27
26
|
defaultValue={''}
|
|
@@ -36,7 +35,7 @@ describe('useForm', () => {
|
|
|
36
35
|
)
|
|
37
36
|
}}
|
|
38
37
|
/>
|
|
39
|
-
|
|
38
|
+
</>
|
|
40
39
|
)
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -64,14 +63,14 @@ describe('useForm', () => {
|
|
|
64
63
|
})
|
|
65
64
|
|
|
66
65
|
return (
|
|
67
|
-
|
|
66
|
+
<>
|
|
68
67
|
<form.Field
|
|
69
68
|
name="firstName"
|
|
70
69
|
children={(field) => {
|
|
71
70
|
return <p>{field.state.value}</p>
|
|
72
71
|
}}
|
|
73
72
|
/>
|
|
74
|
-
|
|
73
|
+
</>
|
|
75
74
|
)
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -96,7 +95,7 @@ describe('useForm', () => {
|
|
|
96
95
|
})
|
|
97
96
|
|
|
98
97
|
return (
|
|
99
|
-
|
|
98
|
+
<>
|
|
100
99
|
<form.Field
|
|
101
100
|
name="firstName"
|
|
102
101
|
children={(field) => {
|
|
@@ -112,7 +111,7 @@ describe('useForm', () => {
|
|
|
112
111
|
/>
|
|
113
112
|
<button onClick={form.handleSubmit}>Submit</button>
|
|
114
113
|
{submittedData && <p>Submitted data: {submittedData.firstName}</p>}
|
|
115
|
-
|
|
114
|
+
</>
|
|
116
115
|
)
|
|
117
116
|
}
|
|
118
117
|
|
|
@@ -146,9 +145,9 @@ describe('useForm', () => {
|
|
|
146
145
|
return (
|
|
147
146
|
<>
|
|
148
147
|
{mountForm ? (
|
|
149
|
-
|
|
148
|
+
<>
|
|
150
149
|
<h1>{formMounted ? 'Form mounted' : 'Not mounted'}</h1>
|
|
151
|
-
|
|
150
|
+
</>
|
|
152
151
|
) : (
|
|
153
152
|
<button onClick={() => setMountForm(true)}>Mount form</button>
|
|
154
153
|
)}
|
|
@@ -172,6 +171,10 @@ describe('useForm', () => {
|
|
|
172
171
|
|
|
173
172
|
function Comp() {
|
|
174
173
|
const form = formFactory.useForm({
|
|
174
|
+
defaultValues: {
|
|
175
|
+
firstName: '',
|
|
176
|
+
lastName: '',
|
|
177
|
+
},
|
|
175
178
|
validators: {
|
|
176
179
|
onChange() {
|
|
177
180
|
return error
|
|
@@ -180,7 +183,7 @@ describe('useForm', () => {
|
|
|
180
183
|
})
|
|
181
184
|
const onChangeError = form.useStore((s) => s.errorMap.onChange)
|
|
182
185
|
return (
|
|
183
|
-
|
|
186
|
+
<>
|
|
184
187
|
<form.Field
|
|
185
188
|
name="firstName"
|
|
186
189
|
children={(field) => (
|
|
@@ -194,7 +197,7 @@ describe('useForm', () => {
|
|
|
194
197
|
)}
|
|
195
198
|
/>
|
|
196
199
|
<p>{onChangeError}</p>
|
|
197
|
-
|
|
200
|
+
</>
|
|
198
201
|
)
|
|
199
202
|
}
|
|
200
203
|
|
|
@@ -217,6 +220,10 @@ describe('useForm', () => {
|
|
|
217
220
|
|
|
218
221
|
function Comp() {
|
|
219
222
|
const form = formFactory.useForm({
|
|
223
|
+
defaultValues: {
|
|
224
|
+
firstName: '',
|
|
225
|
+
lastName: '',
|
|
226
|
+
},
|
|
220
227
|
validators: {
|
|
221
228
|
onChange: ({ value }) =>
|
|
222
229
|
value.firstName === 'other' ? error : undefined,
|
|
@@ -225,7 +232,7 @@ describe('useForm', () => {
|
|
|
225
232
|
|
|
226
233
|
const errors = form.useStore((s) => s.errors)
|
|
227
234
|
return (
|
|
228
|
-
|
|
235
|
+
<>
|
|
229
236
|
<form.Field
|
|
230
237
|
name="firstName"
|
|
231
238
|
children={(field) => (
|
|
@@ -241,7 +248,7 @@ describe('useForm', () => {
|
|
|
241
248
|
</div>
|
|
242
249
|
)}
|
|
243
250
|
/>
|
|
244
|
-
|
|
251
|
+
</>
|
|
245
252
|
)
|
|
246
253
|
}
|
|
247
254
|
|
|
@@ -262,6 +269,10 @@ describe('useForm', () => {
|
|
|
262
269
|
|
|
263
270
|
function Comp() {
|
|
264
271
|
const form = formFactory.useForm({
|
|
272
|
+
defaultValues: {
|
|
273
|
+
firstName: '',
|
|
274
|
+
lastName: '',
|
|
275
|
+
},
|
|
265
276
|
validators: {
|
|
266
277
|
onChange: ({ value }) =>
|
|
267
278
|
value.firstName === 'other' ? error : undefined,
|
|
@@ -269,7 +280,7 @@ describe('useForm', () => {
|
|
|
269
280
|
})
|
|
270
281
|
const errors = form.useStore((s) => s.errorMap)
|
|
271
282
|
return (
|
|
272
|
-
|
|
283
|
+
<>
|
|
273
284
|
<form.Field
|
|
274
285
|
name="firstName"
|
|
275
286
|
defaultMeta={{ isTouched: true }}
|
|
@@ -286,7 +297,7 @@ describe('useForm', () => {
|
|
|
286
297
|
</div>
|
|
287
298
|
)}
|
|
288
299
|
/>
|
|
289
|
-
|
|
300
|
+
</>
|
|
290
301
|
)
|
|
291
302
|
}
|
|
292
303
|
|
|
@@ -320,7 +331,7 @@ describe('useForm', () => {
|
|
|
320
331
|
|
|
321
332
|
const errors = form.useStore((s) => s.errorMap)
|
|
322
333
|
return (
|
|
323
|
-
|
|
334
|
+
<>
|
|
324
335
|
<form.Field
|
|
325
336
|
name="firstName"
|
|
326
337
|
defaultMeta={{ isTouched: true }}
|
|
@@ -338,7 +349,7 @@ describe('useForm', () => {
|
|
|
338
349
|
</div>
|
|
339
350
|
)}
|
|
340
351
|
/>
|
|
341
|
-
|
|
352
|
+
</>
|
|
342
353
|
)
|
|
343
354
|
}
|
|
344
355
|
const { getByTestId, getByText, queryByText } = render(<Comp />)
|
|
@@ -362,6 +373,10 @@ describe('useForm', () => {
|
|
|
362
373
|
|
|
363
374
|
function Comp() {
|
|
364
375
|
const form = formFactory.useForm({
|
|
376
|
+
defaultValues: {
|
|
377
|
+
firstName: '',
|
|
378
|
+
lastName: '',
|
|
379
|
+
},
|
|
365
380
|
validators: {
|
|
366
381
|
onChangeAsync: async () => {
|
|
367
382
|
await sleep(10)
|
|
@@ -371,7 +386,7 @@ describe('useForm', () => {
|
|
|
371
386
|
})
|
|
372
387
|
const errors = form.useStore((s) => s.errorMap)
|
|
373
388
|
return (
|
|
374
|
-
|
|
389
|
+
<>
|
|
375
390
|
<form.Field
|
|
376
391
|
name="firstName"
|
|
377
392
|
defaultMeta={{ isTouched: true }}
|
|
@@ -388,7 +403,7 @@ describe('useForm', () => {
|
|
|
388
403
|
</div>
|
|
389
404
|
)}
|
|
390
405
|
/>
|
|
391
|
-
|
|
406
|
+
</>
|
|
392
407
|
)
|
|
393
408
|
}
|
|
394
409
|
|
|
@@ -412,6 +427,10 @@ describe('useForm', () => {
|
|
|
412
427
|
|
|
413
428
|
function Comp() {
|
|
414
429
|
const form = formFactory.useForm({
|
|
430
|
+
defaultValues: {
|
|
431
|
+
firstName: '',
|
|
432
|
+
lastName: '',
|
|
433
|
+
},
|
|
415
434
|
validators: {
|
|
416
435
|
onChangeAsync: async () => {
|
|
417
436
|
await sleep(10)
|
|
@@ -426,7 +445,7 @@ describe('useForm', () => {
|
|
|
426
445
|
const errors = form.useStore((s) => s.errorMap)
|
|
427
446
|
|
|
428
447
|
return (
|
|
429
|
-
|
|
448
|
+
<>
|
|
430
449
|
<form.Field
|
|
431
450
|
name="firstName"
|
|
432
451
|
defaultMeta={{ isTouched: true }}
|
|
@@ -444,7 +463,7 @@ describe('useForm', () => {
|
|
|
444
463
|
</div>
|
|
445
464
|
)}
|
|
446
465
|
/>
|
|
447
|
-
|
|
466
|
+
</>
|
|
448
467
|
)
|
|
449
468
|
}
|
|
450
469
|
|
|
@@ -472,6 +491,10 @@ describe('useForm', () => {
|
|
|
472
491
|
|
|
473
492
|
function Comp() {
|
|
474
493
|
const form = formFactory.useForm({
|
|
494
|
+
defaultValues: {
|
|
495
|
+
firstName: '',
|
|
496
|
+
lastName: '',
|
|
497
|
+
},
|
|
475
498
|
validators: {
|
|
476
499
|
onChangeAsyncDebounceMs: 100,
|
|
477
500
|
onChangeAsync: async () => {
|
|
@@ -484,7 +507,7 @@ describe('useForm', () => {
|
|
|
484
507
|
const errors = form.useStore((s) => s.errors)
|
|
485
508
|
|
|
486
509
|
return (
|
|
487
|
-
|
|
510
|
+
<>
|
|
488
511
|
<form.Field
|
|
489
512
|
name="firstName"
|
|
490
513
|
defaultMeta={{ isTouched: true }}
|
|
@@ -501,7 +524,7 @@ describe('useForm', () => {
|
|
|
501
524
|
</div>
|
|
502
525
|
)}
|
|
503
526
|
/>
|
|
504
|
-
|
|
527
|
+
</>
|
|
505
528
|
)
|
|
506
529
|
}
|
|
507
530
|
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
DeepKeys,
|
|
3
3
|
DeepValue,
|
|
4
|
-
|
|
4
|
+
FieldApiOptions,
|
|
5
5
|
Validator,
|
|
6
6
|
} from '@tanstack/form-core'
|
|
7
7
|
|
|
@@ -15,6 +15,12 @@ export type UseFieldOptions<
|
|
|
15
15
|
| Validator<TParentData, unknown>
|
|
16
16
|
| undefined = undefined,
|
|
17
17
|
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
|
|
18
|
-
> =
|
|
18
|
+
> = FieldApiOptions<
|
|
19
|
+
TParentData,
|
|
20
|
+
TName,
|
|
21
|
+
TFieldValidator,
|
|
22
|
+
TFormValidator,
|
|
23
|
+
TData
|
|
24
|
+
> & {
|
|
19
25
|
mode?: 'value' | 'array'
|
|
20
26
|
}
|
package/src/useField.tsx
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'rehackt'
|
|
2
2
|
import { useStore } from '@tanstack/react-store'
|
|
3
3
|
import { FieldApi, functionalUpdate } from '@tanstack/form-core'
|
|
4
|
-
import { formContext, useFormContext } from './formContext'
|
|
5
4
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
|
|
6
|
-
import { useIsomorphicEffectOnce } from './useIsomorphicEffectOnce'
|
|
7
5
|
import type { UseFieldOptions } from './types'
|
|
8
6
|
import type {
|
|
9
7
|
DeepKeys,
|
|
@@ -29,20 +27,20 @@ declare module '@tanstack/form-core' {
|
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
export type UseField<
|
|
30
|
+
export type UseField<
|
|
31
|
+
TParentData,
|
|
32
|
+
TFormValidator extends
|
|
33
|
+
| Validator<TParentData, unknown>
|
|
34
|
+
| undefined = undefined,
|
|
35
|
+
> = <
|
|
33
36
|
TName extends DeepKeys<TParentData>,
|
|
34
37
|
TFieldValidator extends
|
|
35
38
|
| Validator<DeepValue<TParentData, TName>, unknown>
|
|
36
39
|
| undefined = undefined,
|
|
37
|
-
TFormValidator extends
|
|
38
|
-
| Validator<TParentData, unknown>
|
|
39
|
-
| undefined = undefined,
|
|
40
40
|
>(
|
|
41
|
-
opts
|
|
42
|
-
TParentData,
|
|
43
|
-
|
|
44
|
-
TFieldValidator,
|
|
45
|
-
TFormValidator
|
|
41
|
+
opts: Omit<
|
|
42
|
+
UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,
|
|
43
|
+
'form'
|
|
46
44
|
>,
|
|
47
45
|
) => FieldApi<
|
|
48
46
|
TParentData,
|
|
@@ -64,23 +62,11 @@ export function useField<
|
|
|
64
62
|
>(
|
|
65
63
|
opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,
|
|
66
64
|
): FieldApi<TParentData, TName, TFieldValidator, TFormValidator> {
|
|
67
|
-
// Get the form API either manually or from context
|
|
68
|
-
const { formApi, parentFieldName } = useFormContext()
|
|
69
|
-
|
|
70
65
|
const [fieldApi] = useState(() => {
|
|
71
|
-
const name = (
|
|
72
|
-
typeof opts.index === 'number'
|
|
73
|
-
? [parentFieldName, opts.index, opts.name]
|
|
74
|
-
: [parentFieldName, opts.name]
|
|
75
|
-
)
|
|
76
|
-
.filter((d) => d !== undefined)
|
|
77
|
-
.join('.')
|
|
78
|
-
|
|
79
66
|
const api = new FieldApi({
|
|
80
67
|
...opts,
|
|
81
|
-
form:
|
|
82
|
-
|
|
83
|
-
name: name as typeof opts.name as never,
|
|
68
|
+
form: opts.form,
|
|
69
|
+
name: opts.name,
|
|
84
70
|
})
|
|
85
71
|
|
|
86
72
|
api.Field = Field as never
|
|
@@ -88,12 +74,14 @@ export function useField<
|
|
|
88
74
|
return api
|
|
89
75
|
})
|
|
90
76
|
|
|
77
|
+
useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])
|
|
78
|
+
|
|
91
79
|
/**
|
|
92
80
|
* fieldApi.update should not have any side effects. Think of it like a `useRef`
|
|
93
81
|
* that we need to keep updated every render with the most up-to-date information.
|
|
94
82
|
*/
|
|
95
83
|
useIsomorphicLayoutEffect(() => {
|
|
96
|
-
fieldApi.update(
|
|
84
|
+
fieldApi.update(opts)
|
|
97
85
|
})
|
|
98
86
|
|
|
99
87
|
useStore(
|
|
@@ -104,19 +92,6 @@ export function useField<
|
|
|
104
92
|
}
|
|
105
93
|
: undefined,
|
|
106
94
|
)
|
|
107
|
-
const unmountFn = useRef<(() => void) | null>(null)
|
|
108
|
-
|
|
109
|
-
useIsomorphicEffectOnce(() => {
|
|
110
|
-
return () => {
|
|
111
|
-
unmountFn.current?.()
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// We have to mount it right as soon as it renders, otherwise we get:
|
|
116
|
-
// https://github.com/TanStack/form/issues/523
|
|
117
|
-
if (!unmountFn.current) {
|
|
118
|
-
unmountFn.current = fieldApi.mount()
|
|
119
|
-
}
|
|
120
95
|
|
|
121
96
|
return fieldApi as never
|
|
122
97
|
}
|
|
@@ -141,19 +116,7 @@ type FieldComponentProps<
|
|
|
141
116
|
TData
|
|
142
117
|
>,
|
|
143
118
|
) => any
|
|
144
|
-
} &
|
|
145
|
-
? {
|
|
146
|
-
name?: TName
|
|
147
|
-
index: number
|
|
148
|
-
}
|
|
149
|
-
: {
|
|
150
|
-
name: TName
|
|
151
|
-
index?: never
|
|
152
|
-
}) &
|
|
153
|
-
Omit<
|
|
154
|
-
UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,
|
|
155
|
-
'name' | 'index'
|
|
156
|
-
>
|
|
119
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>
|
|
157
120
|
|
|
158
121
|
export type FieldComponent<
|
|
159
122
|
TParentData,
|
|
@@ -169,12 +132,15 @@ export type FieldComponent<
|
|
|
169
132
|
>({
|
|
170
133
|
children,
|
|
171
134
|
...fieldOptions
|
|
172
|
-
}:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
135
|
+
}: Omit<
|
|
136
|
+
FieldComponentProps<
|
|
137
|
+
TParentData,
|
|
138
|
+
TName,
|
|
139
|
+
TFieldValidator,
|
|
140
|
+
TFormValidator,
|
|
141
|
+
TData
|
|
142
|
+
>,
|
|
143
|
+
'form'
|
|
178
144
|
>) => any
|
|
179
145
|
|
|
180
146
|
export function Field<
|
|
@@ -196,13 +162,5 @@ export function Field<
|
|
|
196
162
|
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>) {
|
|
197
163
|
const fieldApi = useField(fieldOptions as any)
|
|
198
164
|
|
|
199
|
-
return (
|
|
200
|
-
<formContext.Provider
|
|
201
|
-
value={{
|
|
202
|
-
formApi: fieldApi.form as never,
|
|
203
|
-
parentFieldName: fieldApi.name,
|
|
204
|
-
}}
|
|
205
|
-
children={functionalUpdate(children, fieldApi as any)}
|
|
206
|
-
/>
|
|
207
|
-
)
|
|
165
|
+
return <>{functionalUpdate(children, fieldApi as any)}</>
|
|
208
166
|
}
|
package/src/useForm.tsx
CHANGED
|
@@ -5,23 +5,31 @@ import React, {
|
|
|
5
5
|
type ReactNode,
|
|
6
6
|
useState,
|
|
7
7
|
} from 'rehackt'
|
|
8
|
-
import { Field, useField } from './useField'
|
|
9
|
-
import { formContext } from './formContext'
|
|
8
|
+
import { Field, type FieldComponent, type UseField, useField } from './useField'
|
|
10
9
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
|
|
11
10
|
import type { NoInfer } from '@tanstack/react-store'
|
|
12
11
|
import type { FormOptions, FormState, Validator } from '@tanstack/form-core'
|
|
13
|
-
import type { FieldComponent, UseField } from './useField'
|
|
14
12
|
|
|
15
13
|
declare module '@tanstack/form-core' {
|
|
16
14
|
// eslint-disable-next-line no-shadow
|
|
17
15
|
interface FormApi<TFormData, TFormValidator> {
|
|
18
|
-
Provider: (props: PropsWithChildren) => JSX.Element
|
|
19
16
|
Field: FieldComponent<TFormData, TFormValidator>
|
|
20
|
-
useField: UseField<TFormData>
|
|
17
|
+
useField: UseField<TFormData, TFormValidator>
|
|
21
18
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
|
22
19
|
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
|
23
20
|
) => TSelected
|
|
24
21
|
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
|
|
22
|
+
/**
|
|
23
|
+
TypeScript versions <=5.0.4 have a bug that prevents
|
|
24
|
+
the type of the `TSelected` generic from being inferred
|
|
25
|
+
from the return type of this method.
|
|
26
|
+
|
|
27
|
+
In these versions, `TSelected` will fall back to the default
|
|
28
|
+
type (or `unknown` if that's not defined).
|
|
29
|
+
|
|
30
|
+
@see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}
|
|
31
|
+
@see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}
|
|
32
|
+
*/
|
|
25
33
|
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
|
|
26
34
|
children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
|
|
27
35
|
}) => JSX.Element
|
|
@@ -35,17 +43,12 @@ export function useForm<
|
|
|
35
43
|
opts?: FormOptions<TFormData, TFormValidator>,
|
|
36
44
|
): FormApi<TFormData, TFormValidator> {
|
|
37
45
|
const [formApi] = useState(() => {
|
|
38
|
-
// @ts-ignore
|
|
39
46
|
const api = new FormApi<TFormData, TFormValidator>(opts)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
useIsomorphicLayoutEffect(api.mount, [])
|
|
43
|
-
return (
|
|
44
|
-
<formContext.Provider {...props} value={{ formApi: api as never }} />
|
|
45
|
-
)
|
|
47
|
+
api.Field = function APIField(props) {
|
|
48
|
+
return <Field {...props} form={api} />
|
|
46
49
|
}
|
|
47
|
-
|
|
48
|
-
api.useField = useField
|
|
50
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
51
|
+
api.useField = (props) => useField({ ...props, form: api })
|
|
49
52
|
api.useStore = (
|
|
50
53
|
// @ts-ignore
|
|
51
54
|
selector,
|
|
@@ -67,6 +70,8 @@ export function useForm<
|
|
|
67
70
|
return api
|
|
68
71
|
})
|
|
69
72
|
|
|
73
|
+
useIsomorphicLayoutEffect(formApi.mount, [])
|
|
74
|
+
|
|
70
75
|
formApi.useStore((state) => state.isSubmitting)
|
|
71
76
|
|
|
72
77
|
/**
|
package/dist/cjs/formContext.cjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const rehackt = require("rehackt");
|
|
4
|
-
const formContext = rehackt.createContext(null);
|
|
5
|
-
function useFormContext() {
|
|
6
|
-
const formApi = rehackt.useContext(formContext);
|
|
7
|
-
if (!formApi) {
|
|
8
|
-
throw new Error(`You are trying to use the form API outside of a form!`);
|
|
9
|
-
}
|
|
10
|
-
return formApi;
|
|
11
|
-
}
|
|
12
|
-
exports.formContext = formContext;
|
|
13
|
-
exports.useFormContext = useFormContext;
|
|
14
|
-
//# sourceMappingURL=formContext.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formContext.cjs","sources":["../../src/formContext.ts"],"sourcesContent":["import { createContext, useContext } from 'rehackt'\nimport type { FormApi, Validator } from '@tanstack/form-core'\n\nexport const formContext = createContext<{\n formApi: FormApi<any, Validator<any, unknown> | undefined>\n parentFieldName?: string\n} | null>(null!)\n\nexport function useFormContext() {\n const formApi = useContext(formContext)\n\n if (!formApi) {\n throw new Error(`You are trying to use the form API outside of a form!`)\n }\n\n return formApi\n}\n"],"names":["createContext","useContext"],"mappings":";;;AAGa,MAAA,cAAcA,sBAGjB,IAAK;AAER,SAAS,iBAAiB;AACzB,QAAA,UAAUC,mBAAW,WAAW;AAEtC,MAAI,CAAC,SAAS;AACN,UAAA,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEO,SAAA;AACT;;;"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { FormApi, Validator } from '@tanstack/form-core';
|
|
3
|
-
export declare const formContext: import("react").Context<{
|
|
4
|
-
formApi: FormApi<any, Validator<any, unknown> | undefined>;
|
|
5
|
-
parentFieldName?: string | undefined;
|
|
6
|
-
} | null>;
|
|
7
|
-
export declare function useFormContext(): {
|
|
8
|
-
formApi: FormApi<any, Validator<any, unknown> | undefined>;
|
|
9
|
-
parentFieldName?: string | undefined;
|
|
10
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const rehackt = require("rehackt");
|
|
4
|
-
const useIsomorphicLayoutEffect = require("./useIsomorphicLayoutEffect.cjs");
|
|
5
|
-
const useIsomorphicEffectOnce = (effect) => {
|
|
6
|
-
const destroyFunc = rehackt.useRef();
|
|
7
|
-
const effectCalled = rehackt.useRef(false);
|
|
8
|
-
const renderAfterCalled = rehackt.useRef(false);
|
|
9
|
-
const [val, setVal] = rehackt.useState(0);
|
|
10
|
-
if (effectCalled.current) {
|
|
11
|
-
renderAfterCalled.current = true;
|
|
12
|
-
}
|
|
13
|
-
useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
|
|
14
|
-
if (!effectCalled.current) {
|
|
15
|
-
destroyFunc.current = effect();
|
|
16
|
-
effectCalled.current = true;
|
|
17
|
-
}
|
|
18
|
-
setVal((v) => v + 1);
|
|
19
|
-
return () => {
|
|
20
|
-
if (!renderAfterCalled.current) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (destroyFunc.current) {
|
|
24
|
-
destroyFunc.current();
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}, []);
|
|
28
|
-
};
|
|
29
|
-
exports.useIsomorphicEffectOnce = useIsomorphicEffectOnce;
|
|
30
|
-
//# sourceMappingURL=useIsomorphicEffectOnce.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useIsomorphicEffectOnce.cjs","sources":["../../src/useIsomorphicEffectOnce.ts"],"sourcesContent":["import { useRef, useState } from 'rehackt'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { EffectCallback } from 'rehackt'\n\n/**\n * This hook handles StrictMode and prod mode\n */\nexport const useIsomorphicEffectOnce = (effect: EffectCallback) => {\n const destroyFunc = useRef<void | (() => void)>()\n const effectCalled = useRef(false)\n const renderAfterCalled = useRef(false)\n const [val, setVal] = useState(0)\n\n if (effectCalled.current) {\n renderAfterCalled.current = true\n }\n\n useIsomorphicLayoutEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect()\n effectCalled.current = true\n }\n\n // this forces one render after the effect is run\n setVal((v) => v + 1)\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) {\n return\n }\n if (destroyFunc.current) {\n destroyFunc.current()\n }\n }\n }, [])\n}\n"],"names":["useRef","useState","useIsomorphicLayoutEffect"],"mappings":";;;;AAOa,MAAA,0BAA0B,CAAC,WAA2B;AACjE,QAAM,cAAcA,QAAAA;AACd,QAAA,eAAeA,eAAO,KAAK;AAC3B,QAAA,oBAAoBA,eAAO,KAAK;AACtC,QAAM,CAAC,KAAK,MAAM,IAAIC,iBAAS,CAAC;AAEhC,MAAI,aAAa,SAAS;AACxB,sBAAkB,UAAU;AAAA,EAC9B;AAEAC,4BAAAA,0BAA0B,MAAM;AAE1B,QAAA,CAAC,aAAa,SAAS;AACzB,kBAAY,UAAU;AACtB,mBAAa,UAAU;AAAA,IACzB;AAGO,WAAA,CAAC,MAAM,IAAI,CAAC;AAEnB,WAAO,MAAM;AAGP,UAAA,CAAC,kBAAkB,SAAS;AAC9B;AAAA,MACF;AACA,UAAI,YAAY,SAAS;AACvB,oBAAY,QAAQ;AAAA,MACtB;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAE,CAAA;AACP;;"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { FormApi, Validator } from '@tanstack/form-core';
|
|
3
|
-
export declare const formContext: import("react").Context<{
|
|
4
|
-
formApi: FormApi<any, Validator<any, unknown> | undefined>;
|
|
5
|
-
parentFieldName?: string | undefined;
|
|
6
|
-
} | null>;
|
|
7
|
-
export declare function useFormContext(): {
|
|
8
|
-
formApi: FormApi<any, Validator<any, unknown> | undefined>;
|
|
9
|
-
parentFieldName?: string | undefined;
|
|
10
|
-
};
|
package/dist/esm/formContext.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from "rehackt";
|
|
2
|
-
const formContext = createContext(null);
|
|
3
|
-
function useFormContext() {
|
|
4
|
-
const formApi = useContext(formContext);
|
|
5
|
-
if (!formApi) {
|
|
6
|
-
throw new Error(`You are trying to use the form API outside of a form!`);
|
|
7
|
-
}
|
|
8
|
-
return formApi;
|
|
9
|
-
}
|
|
10
|
-
export {
|
|
11
|
-
formContext,
|
|
12
|
-
useFormContext
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=formContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formContext.js","sources":["../../src/formContext.ts"],"sourcesContent":["import { createContext, useContext } from 'rehackt'\nimport type { FormApi, Validator } from '@tanstack/form-core'\n\nexport const formContext = createContext<{\n formApi: FormApi<any, Validator<any, unknown> | undefined>\n parentFieldName?: string\n} | null>(null!)\n\nexport function useFormContext() {\n const formApi = useContext(formContext)\n\n if (!formApi) {\n throw new Error(`You are trying to use the form API outside of a form!`)\n }\n\n return formApi\n}\n"],"names":[],"mappings":";AAGa,MAAA,cAAc,cAGjB,IAAK;AAER,SAAS,iBAAiB;AACzB,QAAA,UAAU,WAAW,WAAW;AAEtC,MAAI,CAAC,SAAS;AACN,UAAA,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEO,SAAA;AACT;"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { useRef, useState } from "rehackt";
|
|
2
|
-
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
3
|
-
const useIsomorphicEffectOnce = (effect) => {
|
|
4
|
-
const destroyFunc = useRef();
|
|
5
|
-
const effectCalled = useRef(false);
|
|
6
|
-
const renderAfterCalled = useRef(false);
|
|
7
|
-
const [val, setVal] = useState(0);
|
|
8
|
-
if (effectCalled.current) {
|
|
9
|
-
renderAfterCalled.current = true;
|
|
10
|
-
}
|
|
11
|
-
useIsomorphicLayoutEffect(() => {
|
|
12
|
-
if (!effectCalled.current) {
|
|
13
|
-
destroyFunc.current = effect();
|
|
14
|
-
effectCalled.current = true;
|
|
15
|
-
}
|
|
16
|
-
setVal((v) => v + 1);
|
|
17
|
-
return () => {
|
|
18
|
-
if (!renderAfterCalled.current) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (destroyFunc.current) {
|
|
22
|
-
destroyFunc.current();
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}, []);
|
|
26
|
-
};
|
|
27
|
-
export {
|
|
28
|
-
useIsomorphicEffectOnce
|
|
29
|
-
};
|
|
30
|
-
//# sourceMappingURL=useIsomorphicEffectOnce.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useIsomorphicEffectOnce.js","sources":["../../src/useIsomorphicEffectOnce.ts"],"sourcesContent":["import { useRef, useState } from 'rehackt'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { EffectCallback } from 'rehackt'\n\n/**\n * This hook handles StrictMode and prod mode\n */\nexport const useIsomorphicEffectOnce = (effect: EffectCallback) => {\n const destroyFunc = useRef<void | (() => void)>()\n const effectCalled = useRef(false)\n const renderAfterCalled = useRef(false)\n const [val, setVal] = useState(0)\n\n if (effectCalled.current) {\n renderAfterCalled.current = true\n }\n\n useIsomorphicLayoutEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect()\n effectCalled.current = true\n }\n\n // this forces one render after the effect is run\n setVal((v) => v + 1)\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) {\n return\n }\n if (destroyFunc.current) {\n destroyFunc.current()\n }\n }\n }, [])\n}\n"],"names":[],"mappings":";;AAOa,MAAA,0BAA0B,CAAC,WAA2B;AACjE,QAAM,cAAc;AACd,QAAA,eAAe,OAAO,KAAK;AAC3B,QAAA,oBAAoB,OAAO,KAAK;AACtC,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,CAAC;AAEhC,MAAI,aAAa,SAAS;AACxB,sBAAkB,UAAU;AAAA,EAC9B;AAEA,4BAA0B,MAAM;AAE1B,QAAA,CAAC,aAAa,SAAS;AACzB,kBAAY,UAAU;AACtB,mBAAa,UAAU;AAAA,IACzB;AAGO,WAAA,CAAC,MAAM,IAAI,CAAC;AAEnB,WAAO,MAAM;AAGP,UAAA,CAAC,kBAAkB,SAAS;AAC9B;AAAA,MACF;AACA,UAAI,YAAY,SAAS;AACvB,oBAAY,QAAQ;AAAA,MACtB;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAE,CAAA;AACP;"}
|
package/src/formContext.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from 'rehackt'
|
|
2
|
-
import type { FormApi, Validator } from '@tanstack/form-core'
|
|
3
|
-
|
|
4
|
-
export const formContext = createContext<{
|
|
5
|
-
formApi: FormApi<any, Validator<any, unknown> | undefined>
|
|
6
|
-
parentFieldName?: string
|
|
7
|
-
} | null>(null!)
|
|
8
|
-
|
|
9
|
-
export function useFormContext() {
|
|
10
|
-
const formApi = useContext(formContext)
|
|
11
|
-
|
|
12
|
-
if (!formApi) {
|
|
13
|
-
throw new Error(`You are trying to use the form API outside of a form!`)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return formApi
|
|
17
|
-
}
|