@tanstack/form-core 0.20.2 → 0.21.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/FieldApi.cjs +6 -7
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +15 -4
- package/dist/cjs/FormApi.cjs +77 -14
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +12 -3
- package/dist/esm/FieldApi.d.ts +15 -4
- package/dist/esm/FieldApi.js +6 -7
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +12 -3
- package/dist/esm/FormApi.js +77 -14
- package/dist/esm/FormApi.js.map +1 -1
- package/package.json +1 -1
- package/src/FieldApi.ts +19 -11
- package/src/FormApi.ts +118 -12
- package/src/tests/FieldApi.spec.ts +192 -1
- package/src/tests/FormApi.spec.ts +369 -0
|
@@ -324,6 +324,42 @@ describe('form api', () => {
|
|
|
324
324
|
expect(form.getFieldValue('names')).toStrictEqual(['test', 'other'])
|
|
325
325
|
})
|
|
326
326
|
|
|
327
|
+
it("should insert an array field's value as first element", () => {
|
|
328
|
+
const form = new FormApi({
|
|
329
|
+
defaultValues: {
|
|
330
|
+
names: ['one', 'two', 'three'],
|
|
331
|
+
},
|
|
332
|
+
})
|
|
333
|
+
form.mount()
|
|
334
|
+
form.insertFieldValue('names', 0, 'other')
|
|
335
|
+
|
|
336
|
+
expect(form.getFieldValue('names')).toStrictEqual([
|
|
337
|
+
'other',
|
|
338
|
+
'one',
|
|
339
|
+
'two',
|
|
340
|
+
'three',
|
|
341
|
+
])
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it("should run onChange validation when pushing an array field's value", () => {
|
|
345
|
+
const form = new FormApi({
|
|
346
|
+
defaultValues: {
|
|
347
|
+
names: ['test'],
|
|
348
|
+
},
|
|
349
|
+
validators: {
|
|
350
|
+
onChange: ({ value }) =>
|
|
351
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
352
|
+
},
|
|
353
|
+
})
|
|
354
|
+
form.mount()
|
|
355
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
356
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
357
|
+
|
|
358
|
+
form.pushFieldValue('names', 'other')
|
|
359
|
+
|
|
360
|
+
expect(form.state.errors).toStrictEqual(['At least 3 names are required'])
|
|
361
|
+
})
|
|
362
|
+
|
|
327
363
|
it("should insert an array field's value", () => {
|
|
328
364
|
const form = new FormApi({
|
|
329
365
|
defaultValues: {
|
|
@@ -333,9 +369,105 @@ describe('form api', () => {
|
|
|
333
369
|
form.mount()
|
|
334
370
|
form.insertFieldValue('names', 1, 'other')
|
|
335
371
|
|
|
372
|
+
expect(form.getFieldValue('names')).toStrictEqual([
|
|
373
|
+
'one',
|
|
374
|
+
'other',
|
|
375
|
+
'two',
|
|
376
|
+
'three',
|
|
377
|
+
])
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it("should insert an array field's value at the end if the index is higher than the length", () => {
|
|
381
|
+
const form = new FormApi({
|
|
382
|
+
defaultValues: {
|
|
383
|
+
names: ['one', 'two', 'three'],
|
|
384
|
+
},
|
|
385
|
+
})
|
|
386
|
+
form.mount()
|
|
387
|
+
form.insertFieldValue('names', 10, 'other')
|
|
388
|
+
|
|
389
|
+
expect(form.getFieldValue('names')).toStrictEqual([
|
|
390
|
+
'one',
|
|
391
|
+
'two',
|
|
392
|
+
'three',
|
|
393
|
+
'other',
|
|
394
|
+
])
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
it("should replace an array field's value", () => {
|
|
398
|
+
const form = new FormApi({
|
|
399
|
+
defaultValues: {
|
|
400
|
+
names: ['one', 'two', 'three'],
|
|
401
|
+
},
|
|
402
|
+
})
|
|
403
|
+
form.mount()
|
|
404
|
+
form.replaceFieldValue('names', 1, 'other')
|
|
405
|
+
|
|
336
406
|
expect(form.getFieldValue('names')).toStrictEqual(['one', 'other', 'three'])
|
|
337
407
|
})
|
|
338
408
|
|
|
409
|
+
it("should do nothing when replacing an array field's value with an index that doesn't exist", () => {
|
|
410
|
+
const form = new FormApi({
|
|
411
|
+
defaultValues: {
|
|
412
|
+
names: ['one', 'two', 'three'],
|
|
413
|
+
},
|
|
414
|
+
})
|
|
415
|
+
form.mount()
|
|
416
|
+
form.replaceFieldValue('names', 10, 'other')
|
|
417
|
+
|
|
418
|
+
expect(form.getFieldValue('names')).toStrictEqual(['one', 'two', 'three'])
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
it("should run onChange validation when inserting an array field's value", () => {
|
|
422
|
+
const form = new FormApi({
|
|
423
|
+
defaultValues: {
|
|
424
|
+
names: ['test'],
|
|
425
|
+
},
|
|
426
|
+
validators: {
|
|
427
|
+
onChange: ({ value }) =>
|
|
428
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
429
|
+
},
|
|
430
|
+
})
|
|
431
|
+
form.mount()
|
|
432
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
433
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
434
|
+
|
|
435
|
+
form.insertFieldValue('names', 1, 'other')
|
|
436
|
+
|
|
437
|
+
expect(form.state.errors).toStrictEqual(['At least 3 names are required'])
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
it("should validate all shifted fields when inserting an array field's value", async () => {
|
|
441
|
+
const form = new FormApi({
|
|
442
|
+
defaultValues: {
|
|
443
|
+
names: [{ first: 'test' }, { first: 'test2' }],
|
|
444
|
+
},
|
|
445
|
+
validators: {
|
|
446
|
+
onChange: ({ value }) =>
|
|
447
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
448
|
+
},
|
|
449
|
+
})
|
|
450
|
+
form.mount()
|
|
451
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
452
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
453
|
+
|
|
454
|
+
const field1 = new FieldApi({
|
|
455
|
+
form,
|
|
456
|
+
name: 'names[0].first',
|
|
457
|
+
defaultValue: 'test',
|
|
458
|
+
validators: {
|
|
459
|
+
onChange: ({ value }) => value !== 'test' && 'Invalid value',
|
|
460
|
+
},
|
|
461
|
+
})
|
|
462
|
+
field1.mount()
|
|
463
|
+
|
|
464
|
+
expect(field1.state.meta.errors).toStrictEqual([])
|
|
465
|
+
|
|
466
|
+
await form.replaceFieldValue('names', 0, { first: 'other' })
|
|
467
|
+
|
|
468
|
+
expect(field1.state.meta.errors).toStrictEqual(['Invalid value'])
|
|
469
|
+
})
|
|
470
|
+
|
|
339
471
|
it("should remove an array field's value", () => {
|
|
340
472
|
const form = new FormApi({
|
|
341
473
|
defaultValues: {
|
|
@@ -348,6 +480,79 @@ describe('form api', () => {
|
|
|
348
480
|
expect(form.getFieldValue('names')).toStrictEqual(['one', 'three'])
|
|
349
481
|
})
|
|
350
482
|
|
|
483
|
+
it("should run onChange validation when removing an array field's value", () => {
|
|
484
|
+
const form = new FormApi({
|
|
485
|
+
defaultValues: {
|
|
486
|
+
names: ['test'],
|
|
487
|
+
},
|
|
488
|
+
validators: {
|
|
489
|
+
onChange: ({ value }) =>
|
|
490
|
+
value.names.length > 1 ? undefined : 'At least 1 name is required',
|
|
491
|
+
},
|
|
492
|
+
})
|
|
493
|
+
form.mount()
|
|
494
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
495
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
496
|
+
|
|
497
|
+
form.removeFieldValue('names', 0)
|
|
498
|
+
|
|
499
|
+
expect(form.state.errors).toStrictEqual(['At least 1 name is required'])
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
it("should validate following fields when removing an array field's value", async () => {
|
|
503
|
+
const form = new FormApi({
|
|
504
|
+
defaultValues: {
|
|
505
|
+
names: ['test', 'test2', 'test3'],
|
|
506
|
+
},
|
|
507
|
+
validators: {
|
|
508
|
+
onChange: ({ value }) =>
|
|
509
|
+
value.names.length > 1 ? undefined : 'At least 1 name is required',
|
|
510
|
+
},
|
|
511
|
+
})
|
|
512
|
+
form.mount()
|
|
513
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
514
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
515
|
+
|
|
516
|
+
const field1 = new FieldApi({
|
|
517
|
+
form,
|
|
518
|
+
name: 'names[0]',
|
|
519
|
+
defaultValue: 'test',
|
|
520
|
+
validators: {
|
|
521
|
+
onChange: ({ value }) => value !== 'test' && 'Invalid value',
|
|
522
|
+
},
|
|
523
|
+
})
|
|
524
|
+
field1.mount()
|
|
525
|
+
const field2 = new FieldApi({
|
|
526
|
+
form,
|
|
527
|
+
name: 'names[1]',
|
|
528
|
+
defaultValue: 'test2',
|
|
529
|
+
validators: {
|
|
530
|
+
onChange: ({ value }) => value !== 'test2' && 'Invalid value',
|
|
531
|
+
},
|
|
532
|
+
})
|
|
533
|
+
field2.mount()
|
|
534
|
+
const field3 = new FieldApi({
|
|
535
|
+
form,
|
|
536
|
+
name: 'names[2]',
|
|
537
|
+
defaultValue: 'test3',
|
|
538
|
+
validators: {
|
|
539
|
+
onChange: ({ value }) => value !== 'test3' && 'Invalid value',
|
|
540
|
+
},
|
|
541
|
+
})
|
|
542
|
+
field3.mount()
|
|
543
|
+
|
|
544
|
+
expect(field1.state.meta.errors).toStrictEqual([])
|
|
545
|
+
expect(field2.state.meta.errors).toStrictEqual([])
|
|
546
|
+
expect(field3.state.meta.errors).toStrictEqual([])
|
|
547
|
+
|
|
548
|
+
await form.removeFieldValue('names', 1)
|
|
549
|
+
|
|
550
|
+
expect(field1.state.meta.errors).toStrictEqual([])
|
|
551
|
+
expect(field2.state.meta.errors).toStrictEqual(['Invalid value'])
|
|
552
|
+
// This field does not exist anymore. Therefore, its validation should also not run
|
|
553
|
+
expect(field3.state.meta.errors).toStrictEqual([])
|
|
554
|
+
})
|
|
555
|
+
|
|
351
556
|
it("should swap an array field's value", () => {
|
|
352
557
|
const form = new FormApi({
|
|
353
558
|
defaultValues: {
|
|
@@ -355,11 +560,146 @@ describe('form api', () => {
|
|
|
355
560
|
},
|
|
356
561
|
})
|
|
357
562
|
form.mount()
|
|
563
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
564
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
565
|
+
|
|
358
566
|
form.swapFieldValues('names', 1, 2)
|
|
359
567
|
|
|
360
568
|
expect(form.getFieldValue('names')).toStrictEqual(['one', 'three', 'two'])
|
|
361
569
|
})
|
|
362
570
|
|
|
571
|
+
it("should run onChange validation when swapping an array field's value", () => {
|
|
572
|
+
const form = new FormApi({
|
|
573
|
+
defaultValues: {
|
|
574
|
+
names: ['test', 'test2'],
|
|
575
|
+
},
|
|
576
|
+
validators: {
|
|
577
|
+
onChange: ({ value }) =>
|
|
578
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
579
|
+
},
|
|
580
|
+
})
|
|
581
|
+
form.mount()
|
|
582
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
583
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
584
|
+
expect(form.state.errors).toStrictEqual([])
|
|
585
|
+
|
|
586
|
+
form.swapFieldValues('names', 1, 2)
|
|
587
|
+
|
|
588
|
+
expect(form.state.errors).toStrictEqual(['At least 3 names are required'])
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
it('should run validation on swapped fields', () => {
|
|
592
|
+
const form = new FormApi({
|
|
593
|
+
defaultValues: {
|
|
594
|
+
names: ['test', 'test2'],
|
|
595
|
+
},
|
|
596
|
+
validators: {
|
|
597
|
+
onChange: ({ value }) =>
|
|
598
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
599
|
+
},
|
|
600
|
+
})
|
|
601
|
+
form.mount()
|
|
602
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
603
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
604
|
+
|
|
605
|
+
const field1 = new FieldApi({
|
|
606
|
+
form,
|
|
607
|
+
name: 'names[0]',
|
|
608
|
+
defaultValue: 'test',
|
|
609
|
+
validators: {
|
|
610
|
+
onChange: ({ value }) => value !== 'test' && 'Invalid value',
|
|
611
|
+
},
|
|
612
|
+
})
|
|
613
|
+
field1.mount()
|
|
614
|
+
|
|
615
|
+
const field2 = new FieldApi({
|
|
616
|
+
form,
|
|
617
|
+
name: 'names[1]',
|
|
618
|
+
defaultValue: 'test2',
|
|
619
|
+
})
|
|
620
|
+
field2.mount()
|
|
621
|
+
|
|
622
|
+
expect(field1.state.meta.errors).toStrictEqual([])
|
|
623
|
+
expect(field2.state.meta.errors).toStrictEqual([])
|
|
624
|
+
|
|
625
|
+
form.swapFieldValues('names', 0, 1)
|
|
626
|
+
|
|
627
|
+
expect(field1.state.meta.errors).toStrictEqual(['Invalid value'])
|
|
628
|
+
expect(field2.state.meta.errors).toStrictEqual([])
|
|
629
|
+
})
|
|
630
|
+
|
|
631
|
+
it("should move an array field's value", () => {
|
|
632
|
+
const form = new FormApi({
|
|
633
|
+
defaultValues: {
|
|
634
|
+
names: ['one', 'two', 'three'],
|
|
635
|
+
},
|
|
636
|
+
})
|
|
637
|
+
form.mount()
|
|
638
|
+
form.moveFieldValues('names', 1, 2)
|
|
639
|
+
|
|
640
|
+
expect(form.getFieldValue('names')).toStrictEqual(['one', 'three', 'two'])
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
it("should run onChange validation when moving an array field's value", () => {
|
|
644
|
+
const form = new FormApi({
|
|
645
|
+
defaultValues: {
|
|
646
|
+
names: ['test', 'test2'],
|
|
647
|
+
},
|
|
648
|
+
validators: {
|
|
649
|
+
onChange: ({ value }) =>
|
|
650
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
651
|
+
},
|
|
652
|
+
})
|
|
653
|
+
form.mount()
|
|
654
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
655
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
656
|
+
|
|
657
|
+
expect(form.state.errors).toStrictEqual([])
|
|
658
|
+
form.moveFieldValues('names', 0, 1)
|
|
659
|
+
|
|
660
|
+
expect(form.state.errors).toStrictEqual(['At least 3 names are required'])
|
|
661
|
+
})
|
|
662
|
+
|
|
663
|
+
it('should run validation on moved fields', () => {
|
|
664
|
+
const form = new FormApi({
|
|
665
|
+
defaultValues: {
|
|
666
|
+
names: ['test', 'test2'],
|
|
667
|
+
},
|
|
668
|
+
validators: {
|
|
669
|
+
onChange: ({ value }) =>
|
|
670
|
+
value.names.length > 3 ? undefined : 'At least 3 names are required',
|
|
671
|
+
},
|
|
672
|
+
})
|
|
673
|
+
form.mount()
|
|
674
|
+
// Since validation runs through the field, a field must be mounted for that array
|
|
675
|
+
new FieldApi({ form, name: 'names' }).mount()
|
|
676
|
+
|
|
677
|
+
const field1 = new FieldApi({
|
|
678
|
+
form,
|
|
679
|
+
name: 'names[0]',
|
|
680
|
+
defaultValue: 'test',
|
|
681
|
+
validators: {
|
|
682
|
+
onChange: ({ value }) => value !== 'test' && 'Invalid value',
|
|
683
|
+
},
|
|
684
|
+
})
|
|
685
|
+
field1.mount()
|
|
686
|
+
|
|
687
|
+
const field2 = new FieldApi({
|
|
688
|
+
form,
|
|
689
|
+
name: 'names[1]',
|
|
690
|
+
defaultValue: 'test2',
|
|
691
|
+
})
|
|
692
|
+
field2.mount()
|
|
693
|
+
|
|
694
|
+
expect(field1.state.meta.errors).toStrictEqual([])
|
|
695
|
+
expect(field2.state.meta.errors).toStrictEqual([])
|
|
696
|
+
|
|
697
|
+
form.swapFieldValues('names', 0, 1)
|
|
698
|
+
|
|
699
|
+
expect(field1.state.meta.errors).toStrictEqual(['Invalid value'])
|
|
700
|
+
expect(field2.state.meta.errors).toStrictEqual([])
|
|
701
|
+
})
|
|
702
|
+
|
|
363
703
|
it('should handle fields inside an array', async () => {
|
|
364
704
|
interface Employee {
|
|
365
705
|
firstName: string
|
|
@@ -1052,6 +1392,35 @@ describe('form api', () => {
|
|
|
1052
1392
|
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
|
|
1053
1393
|
})
|
|
1054
1394
|
|
|
1395
|
+
it('should validate a single field consistently if touched', async () => {
|
|
1396
|
+
const form = new FormApi({
|
|
1397
|
+
defaultValues: {
|
|
1398
|
+
firstName: '',
|
|
1399
|
+
lastName: '',
|
|
1400
|
+
},
|
|
1401
|
+
})
|
|
1402
|
+
|
|
1403
|
+
const field = new FieldApi({
|
|
1404
|
+
form,
|
|
1405
|
+
name: 'firstName',
|
|
1406
|
+
validators: {
|
|
1407
|
+
onChange: ({ value }) =>
|
|
1408
|
+
value.length > 0 ? undefined : 'first name is required',
|
|
1409
|
+
},
|
|
1410
|
+
defaultMeta: {
|
|
1411
|
+
isTouched: true,
|
|
1412
|
+
},
|
|
1413
|
+
})
|
|
1414
|
+
|
|
1415
|
+
field.mount()
|
|
1416
|
+
form.mount()
|
|
1417
|
+
|
|
1418
|
+
await form.validateField('firstName', 'change')
|
|
1419
|
+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
|
|
1420
|
+
await form.validateField('firstName', 'change')
|
|
1421
|
+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
|
|
1422
|
+
})
|
|
1423
|
+
|
|
1055
1424
|
it('should show onSubmit errors', async () => {
|
|
1056
1425
|
const form = new FormApi({
|
|
1057
1426
|
defaultValues: {
|