@tanstack/form-core 0.10.2 → 0.11.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.
Files changed (55) hide show
  1. package/build/legacy/FieldApi.cjs +98 -125
  2. package/build/legacy/FieldApi.cjs.map +1 -1
  3. package/build/legacy/FieldApi.d.cts +1 -2
  4. package/build/legacy/FieldApi.d.ts +1 -2
  5. package/build/legacy/FieldApi.js +98 -125
  6. package/build/legacy/FieldApi.js.map +1 -1
  7. package/build/legacy/FormApi.cjs +128 -121
  8. package/build/legacy/FormApi.cjs.map +1 -1
  9. package/build/legacy/FormApi.d.cts +1 -2
  10. package/build/legacy/FormApi.d.ts +1 -2
  11. package/build/legacy/FormApi.js +130 -121
  12. package/build/legacy/FormApi.js.map +1 -1
  13. package/build/legacy/index.d.cts +163 -74
  14. package/build/legacy/index.d.ts +163 -74
  15. package/build/legacy/types.cjs.map +1 -1
  16. package/build/legacy/types.d.cts +12 -3
  17. package/build/legacy/types.d.ts +12 -3
  18. package/build/legacy/utils.cjs +55 -0
  19. package/build/legacy/utils.cjs.map +1 -1
  20. package/build/legacy/utils.d.cts +3 -37
  21. package/build/legacy/utils.d.ts +3 -37
  22. package/build/legacy/utils.js +53 -0
  23. package/build/legacy/utils.js.map +1 -1
  24. package/build/modern/FieldApi.cjs +98 -123
  25. package/build/modern/FieldApi.cjs.map +1 -1
  26. package/build/modern/FieldApi.d.cts +1 -2
  27. package/build/modern/FieldApi.d.ts +1 -2
  28. package/build/modern/FieldApi.js +98 -123
  29. package/build/modern/FieldApi.js.map +1 -1
  30. package/build/modern/FormApi.cjs +128 -120
  31. package/build/modern/FormApi.cjs.map +1 -1
  32. package/build/modern/FormApi.d.cts +1 -2
  33. package/build/modern/FormApi.d.ts +1 -2
  34. package/build/modern/FormApi.js +130 -120
  35. package/build/modern/FormApi.js.map +1 -1
  36. package/build/modern/index.d.cts +163 -74
  37. package/build/modern/index.d.ts +163 -74
  38. package/build/modern/types.cjs.map +1 -1
  39. package/build/modern/types.d.cts +12 -3
  40. package/build/modern/types.d.ts +12 -3
  41. package/build/modern/utils.cjs +55 -0
  42. package/build/modern/utils.cjs.map +1 -1
  43. package/build/modern/utils.d.cts +3 -37
  44. package/build/modern/utils.d.ts +3 -37
  45. package/build/modern/utils.js +53 -0
  46. package/build/modern/utils.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/FieldApi.ts +315 -241
  49. package/src/FormApi.ts +263 -213
  50. package/src/tests/FieldApi.spec.ts +135 -48
  51. package/src/tests/FieldApi.test-d.ts +10 -6
  52. package/src/tests/FormApi.spec.ts +192 -61
  53. package/src/tests/utils.ts +1 -1
  54. package/src/types.ts +10 -2
  55. package/src/utils.ts +106 -0
@@ -207,9 +207,11 @@ describe('field api', () => {
207
207
  const field = new FieldApi({
208
208
  form,
209
209
  name: 'name',
210
- onChange: (value) => {
211
- if (value === 'other') return 'Please enter a different value'
212
- return
210
+ validators: {
211
+ onChange: ({ value }) => {
212
+ if (value === 'other') return 'Please enter a different value'
213
+ return
214
+ },
213
215
  },
214
216
  })
215
217
 
@@ -235,10 +237,12 @@ describe('field api', () => {
235
237
  const field = new FieldApi({
236
238
  form,
237
239
  name: 'name',
238
- onChangeAsync: async (value) => {
239
- await sleep(1000)
240
- if (value === 'other') return 'Please enter a different value'
241
- return
240
+ validators: {
241
+ onChangeAsync: async ({ value }) => {
242
+ await sleep(1000)
243
+ if (value === 'other') return 'Please enter a different value'
244
+ return
245
+ },
242
246
  },
243
247
  })
244
248
 
@@ -266,11 +270,13 @@ describe('field api', () => {
266
270
  const field = new FieldApi({
267
271
  form,
268
272
  name: 'name',
269
- onChangeAsyncDebounceMs: 1000,
270
- onChangeAsync: async (value) => {
271
- await sleepMock(1000)
272
- if (value === 'other') return 'Please enter a different value'
273
- return
273
+ validators: {
274
+ onChangeAsyncDebounceMs: 1000,
275
+ onChangeAsync: async ({ value }) => {
276
+ await sleepMock(1000)
277
+ if (value === 'other') return 'Please enter a different value'
278
+ return
279
+ },
274
280
  },
275
281
  })
276
282
 
@@ -302,10 +308,12 @@ describe('field api', () => {
302
308
  form,
303
309
  name: 'name',
304
310
  asyncDebounceMs: 1000,
305
- onChangeAsync: async (value) => {
306
- await sleepMock(1000)
307
- if (value === 'other') return 'Please enter a different value'
308
- return
311
+ validators: {
312
+ onChangeAsync: async ({ value }) => {
313
+ await sleepMock(1000)
314
+ if (value === 'other') return 'Please enter a different value'
315
+ return
316
+ },
309
317
  },
310
318
  })
311
319
 
@@ -333,9 +341,11 @@ describe('field api', () => {
333
341
  const field = new FieldApi({
334
342
  form,
335
343
  name: 'name',
336
- onBlur: (value) => {
337
- if (value === 'other') return 'Please enter a different value'
338
- return
344
+ validators: {
345
+ onBlur: ({ value }) => {
346
+ if (value === 'other') return 'Please enter a different value'
347
+ return
348
+ },
339
349
  },
340
350
  })
341
351
 
@@ -361,10 +371,12 @@ describe('field api', () => {
361
371
  const field = new FieldApi({
362
372
  form,
363
373
  name: 'name',
364
- onBlurAsync: async (value) => {
365
- await sleep(1000)
366
- if (value === 'other') return 'Please enter a different value'
367
- return
374
+ validators: {
375
+ onBlurAsync: async ({ value }) => {
376
+ await sleep(1000)
377
+ if (value === 'other') return 'Please enter a different value'
378
+ return
379
+ },
368
380
  },
369
381
  })
370
382
 
@@ -393,11 +405,13 @@ describe('field api', () => {
393
405
  const field = new FieldApi({
394
406
  form,
395
407
  name: 'name',
396
- onBlurAsyncDebounceMs: 1000,
397
- onBlurAsync: async (value) => {
398
- await sleepMock(10)
399
- if (value === 'other') return 'Please enter a different value'
400
- return
408
+ validators: {
409
+ onBlurAsyncDebounceMs: 1000,
410
+ onBlurAsync: async ({ value }) => {
411
+ await sleepMock(10)
412
+ if (value === 'other') return 'Please enter a different value'
413
+ return
414
+ },
401
415
  },
402
416
  })
403
417
 
@@ -430,10 +444,12 @@ describe('field api', () => {
430
444
  form,
431
445
  name: 'name',
432
446
  asyncDebounceMs: 1000,
433
- onBlurAsync: async (value) => {
434
- await sleepMock(10)
435
- if (value === 'other') return 'Please enter a different value'
436
- return
447
+ validators: {
448
+ onBlurAsync: async ({ value }) => {
449
+ await sleepMock(10)
450
+ if (value === 'other') return 'Please enter a different value'
451
+ return
452
+ },
437
453
  },
438
454
  })
439
455
 
@@ -464,10 +480,12 @@ describe('field api', () => {
464
480
  const field = new FieldApi({
465
481
  form,
466
482
  name: 'name',
467
- onSubmitAsync: async (value) => {
468
- await sleep(1000)
469
- if (value === 'other') return 'Please enter a different value'
470
- return
483
+ validators: {
484
+ onSubmitAsync: async ({ value }) => {
485
+ await sleep(1000)
486
+ if (value === 'other') return 'Please enter a different value'
487
+ return
488
+ },
471
489
  },
472
490
  })
473
491
 
@@ -493,13 +511,15 @@ describe('field api', () => {
493
511
  const field = new FieldApi({
494
512
  form,
495
513
  name: 'name',
496
- onBlur: (value) => {
497
- if (value === 'other') return 'Please enter a different value'
498
- return
499
- },
500
- onChange: (value) => {
501
- if (value === 'other') return 'Please enter a different value'
502
- return
514
+ validators: {
515
+ onBlur: ({ value }) => {
516
+ if (value === 'other') return 'Please enter a different value'
517
+ return
518
+ },
519
+ onChange: ({ value }) => {
520
+ if (value === 'other') return 'Please enter a different value'
521
+ return
522
+ },
503
523
  },
504
524
  })
505
525
 
@@ -527,9 +547,11 @@ describe('field api', () => {
527
547
  const field = new FieldApi({
528
548
  form,
529
549
  name: 'name',
530
- onChange: (value) => {
531
- if (value === 'other') return 'Please enter a different value'
532
- return
550
+ validators: {
551
+ onChange: ({ value }) => {
552
+ if (value === 'other') return 'Please enter a different value'
553
+ return
554
+ },
533
555
  },
534
556
  })
535
557
 
@@ -551,7 +573,7 @@ describe('field api', () => {
551
573
  interface Form {
552
574
  name: string
553
575
  }
554
- const form = new FormApi<Form, unknown>()
576
+ const form = new FormApi<Form>()
555
577
 
556
578
  const field = new FieldApi({
557
579
  form,
@@ -625,7 +647,10 @@ describe('field api', () => {
625
647
  const field = new FieldApi({
626
648
  form,
627
649
  name: 'firstName',
628
- onSubmit: (v) => (v.length > 0 ? undefined : 'first name is required'),
650
+ validators: {
651
+ onSubmit: ({ value }) =>
652
+ value.length > 0 ? undefined : 'first name is required',
653
+ },
629
654
  })
630
655
 
631
656
  field.mount()
@@ -633,4 +658,66 @@ describe('field api', () => {
633
658
  await form.handleSubmit()
634
659
  expect(field.getMeta().errors).toStrictEqual(['first name is required'])
635
660
  })
661
+
662
+ it('should show onMount errors', async () => {
663
+ const form = new FormApi({
664
+ defaultValues: {
665
+ firstName: '',
666
+ },
667
+ })
668
+
669
+ const field = new FieldApi({
670
+ form,
671
+ name: 'firstName',
672
+ validators: {
673
+ onMount: ({ value }) =>
674
+ value.length > 0 ? undefined : 'first name is required',
675
+ },
676
+ })
677
+
678
+ form.mount()
679
+ field.mount()
680
+
681
+ expect(field.getMeta().errors).toStrictEqual(['first name is required'])
682
+ })
683
+
684
+ it('should cancel previous functions from an async validator with an abort signal', async () => {
685
+ vi.useRealTimers()
686
+ const form = new FormApi({
687
+ defaultValues: {
688
+ firstName: '',
689
+ },
690
+ })
691
+
692
+ let resolve!: () => void
693
+ const promise = new Promise((r) => {
694
+ resolve = r as never
695
+ })
696
+
697
+ const fn = vi.fn()
698
+
699
+ const field = new FieldApi({
700
+ form,
701
+ name: 'firstName',
702
+ validators: {
703
+ onChangeAsyncDebounceMs: 0,
704
+ onChangeAsync: async ({ signal }) => {
705
+ await promise
706
+ if (signal.aborted) return
707
+ fn()
708
+ return undefined
709
+ },
710
+ },
711
+ })
712
+
713
+ field.mount()
714
+
715
+ field.setValue('one', { touch: true })
716
+ // Allow for a micro-tick to allow the promise to resolve
717
+ await sleep(1)
718
+ field.setValue('two', { touch: true })
719
+ resolve()
720
+ await sleep(1)
721
+ expect(fn).toHaveBeenCalledTimes(1)
722
+ })
636
723
  })
@@ -29,10 +29,12 @@ it('should type onChange properly', () => {
29
29
  const field = new FieldApi({
30
30
  form,
31
31
  name: 'name',
32
- onChange: (value) => {
33
- assertType<'test'>(value)
32
+ validators: {
33
+ onChange: ({ value }) => {
34
+ assertType<'test'>(value)
34
35
 
35
- return undefined
36
+ return undefined
37
+ },
36
38
  },
37
39
  })
38
40
  })
@@ -47,10 +49,12 @@ it('should type onChangeAsync properly', () => {
47
49
  const field = new FieldApi({
48
50
  form,
49
51
  name: 'name',
50
- onChangeAsync: async (value) => {
51
- assertType<'test'>(value)
52
+ validators: {
53
+ onChangeAsync: async ({ value }) => {
54
+ assertType<'test'>(value)
52
55
 
53
- return undefined
56
+ return undefined
57
+ },
54
58
  },
55
59
  })
56
60
  })