@tanstack/react-form 0.0.2 → 0.0.4
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/build/cjs/index.js +7 -0
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +116 -110
- package/build/types/form-core/src/FieldApi.d.ts +9 -11
- package/build/types/form-core/src/FormApi.d.ts +7 -3
- package/build/types/index.d.ts +1 -0
- package/build/types/react-form/src/index.d.ts +1 -0
- package/build/umd/index.development.js +166 -74
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +5 -4
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import type { FormEvent } from 'react';
|
|
2
2
|
import { Store } from '@tanstack/store';
|
|
3
3
|
import type { DeepKeys, DeepValue, Updater } from './utils';
|
|
4
|
-
import type { FieldApi, FieldMeta } from './FieldApi';
|
|
4
|
+
import type { FieldApi, FieldMeta, ValidationCause } from './FieldApi';
|
|
5
5
|
export declare type FormOptions<TData> = {
|
|
6
6
|
defaultValues?: TData;
|
|
7
7
|
defaultState?: Partial<FormState<TData>>;
|
|
8
|
-
onSubmit?: (values: TData, formApi: FormApi<TData>) =>
|
|
8
|
+
onSubmit?: (values: TData, formApi: FormApi<TData>) => void;
|
|
9
9
|
onInvalidSubmit?: (values: TData, formApi: FormApi<TData>) => void;
|
|
10
10
|
validate?: (values: TData, formApi: FormApi<TData>) => Promise<any>;
|
|
11
11
|
debugForm?: boolean;
|
|
12
|
-
|
|
12
|
+
defaultValidatePristine?: boolean;
|
|
13
|
+
defaultValidateOn?: ValidationCause;
|
|
14
|
+
defaultValidateAsyncOn?: ValidationCause;
|
|
15
|
+
defaultValidateAsyncDebounceMs?: number;
|
|
13
16
|
};
|
|
14
17
|
export declare type FieldInfo<TFormData> = {
|
|
15
18
|
instances: Record<string, FieldApi<any, TFormData>>;
|
|
16
19
|
} & ValidationMeta;
|
|
17
20
|
export declare type ValidationMeta = {
|
|
18
21
|
validationCount?: number;
|
|
22
|
+
validationAsyncCount?: number;
|
|
19
23
|
validationPromise?: Promise<ValidationError>;
|
|
20
24
|
validationResolve?: (error: ValidationError) => void;
|
|
21
25
|
validationReject?: (error: unknown) => void;
|
package/build/types/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
import { DeepKeys, FieldApi, DeepValue, FieldOptions, FormApi, FormState, FormOptions } from '@tanstack/form-core';
|
|
12
|
+
export * from '@tanstack/form-core';
|
|
12
13
|
import { NoInfer } from '@tanstack/react-store';
|
|
13
14
|
import React from 'react';
|
|
14
15
|
|
|
@@ -37,23 +37,6 @@
|
|
|
37
37
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
38
38
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
39
39
|
|
|
40
|
-
function _extends() {
|
|
41
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
42
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
43
|
-
var source = arguments[i];
|
|
44
|
-
|
|
45
|
-
for (var key in source) {
|
|
46
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
47
|
-
target[key] = source[key];
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return target;
|
|
53
|
-
};
|
|
54
|
-
return _extends.apply(this, arguments);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
40
|
/**
|
|
58
41
|
* store
|
|
59
42
|
*
|
|
@@ -498,7 +481,7 @@
|
|
|
498
481
|
|
|
499
482
|
var _updateStore = /*#__PURE__*/_classPrivateFieldLooseKey("updateStore");
|
|
500
483
|
|
|
501
|
-
var
|
|
484
|
+
var _leaseValidateAsync = /*#__PURE__*/_classPrivateFieldLooseKey("leaseValidateAsync");
|
|
502
485
|
|
|
503
486
|
class FieldApi {
|
|
504
487
|
constructor(_opts) {
|
|
@@ -545,10 +528,13 @@
|
|
|
545
528
|
});
|
|
546
529
|
|
|
547
530
|
this.update = opts => {
|
|
531
|
+
var _this$form$options$de, _this$form$options$de2, _this$form$options$de3, _this$form$options$de4;
|
|
532
|
+
|
|
548
533
|
this.options = {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
534
|
+
validatePristine: (_this$form$options$de = this.form.options.defaultValidatePristine) != null ? _this$form$options$de : false,
|
|
535
|
+
validateOn: (_this$form$options$de2 = this.form.options.defaultValidateOn) != null ? _this$form$options$de2 : 'change',
|
|
536
|
+
validateAsyncOn: (_this$form$options$de3 = this.form.options.defaultValidateAsyncOn) != null ? _this$form$options$de3 : 'blur',
|
|
537
|
+
validateAsyncDebounceMs: (_this$form$options$de4 = this.form.options.defaultValidateAsyncDebounceMs) != null ? _this$form$options$de4 : 0,
|
|
552
538
|
...opts
|
|
553
539
|
}; // Default Value
|
|
554
540
|
|
|
@@ -586,48 +572,91 @@
|
|
|
586
572
|
form: this.form
|
|
587
573
|
});
|
|
588
574
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
575
|
+
this.validateSync = async (value = this.state.value) => {
|
|
576
|
+
const {
|
|
577
|
+
validate
|
|
578
|
+
} = this.options;
|
|
579
|
+
|
|
580
|
+
if (!validate) {
|
|
581
|
+
return;
|
|
582
|
+
} // Use the validationCount for all field instances to
|
|
583
|
+
// track freshness of the validation
|
|
584
|
+
|
|
595
585
|
|
|
586
|
+
const validationCount = (this.getInfo().validationCount || 0) + 1;
|
|
587
|
+
this.getInfo().validationCount = validationCount;
|
|
588
|
+
const error = normalizeError(validate(value, this));
|
|
589
|
+
|
|
590
|
+
if (this.state.meta.error !== error) {
|
|
596
591
|
this.setMeta(prev => ({ ...prev,
|
|
597
|
-
|
|
598
|
-
}));
|
|
599
|
-
|
|
592
|
+
error
|
|
593
|
+
}));
|
|
594
|
+
} // If a sync error is encountered, cancel any async validation
|
|
600
595
|
|
|
601
|
-
const validationCount = (this.getInfo().validationCount || 0) + 1;
|
|
602
|
-
this.getInfo().validationCount = validationCount;
|
|
603
596
|
|
|
604
|
-
|
|
597
|
+
if (this.state.meta.error) {
|
|
598
|
+
this.cancelValidateAsync();
|
|
599
|
+
}
|
|
600
|
+
};
|
|
605
601
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
602
|
+
Object.defineProperty(this, _leaseValidateAsync, {
|
|
603
|
+
writable: true,
|
|
604
|
+
value: () => {
|
|
605
|
+
const count = (this.getInfo().validationAsyncCount || 0) + 1;
|
|
606
|
+
this.getInfo().validationAsyncCount = count;
|
|
607
|
+
return count;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
612
610
|
|
|
613
|
-
|
|
614
|
-
|
|
611
|
+
this.cancelValidateAsync = () => {
|
|
612
|
+
// Lease a new validation count to ignore any pending validations
|
|
613
|
+
_classPrivateFieldLooseBase(this, _leaseValidateAsync)[_leaseValidateAsync](); // Cancel any pending validation state
|
|
615
614
|
|
|
616
|
-
if (checkLatest()) {
|
|
617
|
-
var _this$getInfo$validat, _this$getInfo;
|
|
618
615
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
616
|
+
this.setMeta(prev => ({ ...prev,
|
|
617
|
+
isValidating: false
|
|
618
|
+
}));
|
|
619
|
+
};
|
|
624
620
|
|
|
625
|
-
|
|
626
|
-
|
|
621
|
+
this.validateAsync = async (value = this.state.value) => {
|
|
622
|
+
const {
|
|
623
|
+
validateAsync,
|
|
624
|
+
validateAsyncDebounceMs
|
|
625
|
+
} = this.options;
|
|
626
|
+
|
|
627
|
+
if (!validateAsync) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
627
630
|
|
|
628
|
-
|
|
629
|
-
|
|
631
|
+
if (this.state.meta.isValidating !== true) this.setMeta(prev => ({ ...prev,
|
|
632
|
+
isValidating: true
|
|
633
|
+
})); // Use the validationCount for all field instances to
|
|
634
|
+
// track freshness of the validation
|
|
635
|
+
|
|
636
|
+
const validationAsyncCount = _classPrivateFieldLooseBase(this, _leaseValidateAsync)[_leaseValidateAsync]();
|
|
637
|
+
|
|
638
|
+
const checkLatest = () => validationAsyncCount === this.getInfo().validationAsyncCount;
|
|
639
|
+
|
|
640
|
+
if (!this.getInfo().validationPromise) {
|
|
641
|
+
this.getInfo().validationPromise = new Promise((resolve, reject) => {
|
|
642
|
+
this.getInfo().validationResolve = resolve;
|
|
643
|
+
this.getInfo().validationReject = reject;
|
|
644
|
+
});
|
|
645
|
+
}
|
|
630
646
|
|
|
647
|
+
if (validateAsyncDebounceMs > 0) {
|
|
648
|
+
await new Promise(r => setTimeout(r, validateAsyncDebounceMs));
|
|
649
|
+
} // Only kick off validation if this validation is the latest attempt
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
if (checkLatest()) {
|
|
653
|
+
try {
|
|
654
|
+
const rawError = await validateAsync(value, this);
|
|
655
|
+
|
|
656
|
+
if (checkLatest()) {
|
|
657
|
+
var _this$getInfo$validat, _this$getInfo;
|
|
658
|
+
|
|
659
|
+
const error = normalizeError(rawError);
|
|
631
660
|
this.setMeta(prev => ({ ...prev,
|
|
632
661
|
isValidating: false,
|
|
633
662
|
error
|
|
@@ -649,14 +678,45 @@
|
|
|
649
678
|
delete this.getInfo().validationPromise;
|
|
650
679
|
}
|
|
651
680
|
}
|
|
681
|
+
} // Always return the latest validation promise to the caller
|
|
652
682
|
|
|
653
|
-
return this.getInfo().validationPromise;
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
683
|
|
|
657
|
-
|
|
684
|
+
return this.getInfo().validationPromise;
|
|
685
|
+
};
|
|
658
686
|
|
|
659
|
-
this.
|
|
687
|
+
this.shouldValidate = (isAsync, cause) => {
|
|
688
|
+
const {
|
|
689
|
+
validateOn,
|
|
690
|
+
validateAsyncOn
|
|
691
|
+
} = this.options;
|
|
692
|
+
const level = getValidationCauseLevel(cause); // Must meet *at least* the validation level to validate,
|
|
693
|
+
// e.g. if validateOn is 'change' and validateCause is 'blur',
|
|
694
|
+
// the field will still validate
|
|
695
|
+
|
|
696
|
+
return Object.keys(validateCauseLevels).some(d => isAsync ? validateAsyncOn : validateOn === d && level >= validateCauseLevels[d]);
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
this.validate = async (cause, value) => {
|
|
700
|
+
// If the field is pristine and validatePristine is false, do not validate
|
|
701
|
+
if (!this.options.validatePristine && !this.state.meta.isTouched) return; // Attempt to sync validate first
|
|
702
|
+
|
|
703
|
+
if (this.shouldValidate(false, cause)) {
|
|
704
|
+
this.validateSync(value);
|
|
705
|
+
} // If there is an error, return it, do not attempt async validation
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
if (this.state.meta.error) {
|
|
709
|
+
return this.state.meta.error;
|
|
710
|
+
} // No error? Attempt async validation
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
if (this.shouldValidate(true, cause)) {
|
|
714
|
+
return this.validateAsync(value);
|
|
715
|
+
} // If there is no sync error or async validation attempt, there is no error
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
return undefined;
|
|
719
|
+
};
|
|
660
720
|
|
|
661
721
|
this.getChangeProps = (props = {}) => {
|
|
662
722
|
return { ...props,
|
|
@@ -669,14 +729,7 @@
|
|
|
669
729
|
this.setMeta(prev => ({ ...prev,
|
|
670
730
|
isTouched: true
|
|
671
731
|
}));
|
|
672
|
-
|
|
673
|
-
validateOn
|
|
674
|
-
} = this.options;
|
|
675
|
-
|
|
676
|
-
if (validateOn === 'blur' || validateOn.split('-')[0] === 'blur') {
|
|
677
|
-
this.validate();
|
|
678
|
-
}
|
|
679
|
-
|
|
732
|
+
this.validate('blur');
|
|
680
733
|
props.onBlur == null ? void 0 : props.onBlur(e);
|
|
681
734
|
}
|
|
682
735
|
};
|
|
@@ -715,17 +768,12 @@
|
|
|
715
768
|
onUpdate: next => {
|
|
716
769
|
next.meta.touchedError = next.meta.isTouched ? next.meta.error : undefined; // Do not validate pristine fields
|
|
717
770
|
|
|
718
|
-
|
|
771
|
+
const prevState = this.state;
|
|
772
|
+
this.state = next;
|
|
719
773
|
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
this.validate();
|
|
723
|
-
} catch (err) {
|
|
724
|
-
console.error('An error occurred during validation', err);
|
|
725
|
-
}
|
|
774
|
+
if (next.value !== prevState.value) {
|
|
775
|
+
this.validate('change', next.value);
|
|
726
776
|
}
|
|
727
|
-
|
|
728
|
-
this.state = next;
|
|
729
777
|
}
|
|
730
778
|
});
|
|
731
779
|
this.state = this.store.state;
|
|
@@ -733,6 +781,44 @@
|
|
|
733
781
|
}
|
|
734
782
|
|
|
735
783
|
}
|
|
784
|
+
const validateCauseLevels = {
|
|
785
|
+
change: 0,
|
|
786
|
+
blur: 1,
|
|
787
|
+
submit: 2
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
function getValidationCauseLevel(cause) {
|
|
791
|
+
return !cause ? 3 : validateCauseLevels[cause];
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
function normalizeError(rawError) {
|
|
795
|
+
if (rawError) {
|
|
796
|
+
if (typeof rawError !== 'string') {
|
|
797
|
+
return 'Invalid Form Values';
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
return rawError;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return undefined;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function _extends() {
|
|
807
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
808
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
809
|
+
var source = arguments[i];
|
|
810
|
+
|
|
811
|
+
for (var key in source) {
|
|
812
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
813
|
+
target[key] = source[key];
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return target;
|
|
819
|
+
};
|
|
820
|
+
return _extends.apply(this, arguments);
|
|
821
|
+
}
|
|
736
822
|
|
|
737
823
|
/**
|
|
738
824
|
* react-store
|
|
@@ -895,9 +981,15 @@
|
|
|
895
981
|
}
|
|
896
982
|
|
|
897
983
|
exports.Field = Field;
|
|
984
|
+
exports.FieldApi = FieldApi;
|
|
985
|
+
exports.FormApi = FormApi;
|
|
898
986
|
exports.createFieldComponent = createFieldComponent;
|
|
899
987
|
exports.createFormComponent = createFormComponent;
|
|
900
988
|
exports.createUseField = createUseField;
|
|
989
|
+
exports.functionalUpdate = functionalUpdate;
|
|
990
|
+
exports.getBy = getBy;
|
|
991
|
+
exports.getDefaultFormState = getDefaultFormState;
|
|
992
|
+
exports.setBy = setBy;
|
|
901
993
|
exports.useField = useField;
|
|
902
994
|
exports.useForm = useForm;
|
|
903
995
|
|