react-hook-form 8.0.0-beta.3 → 8.0.0-beta.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/README.md +8 -9
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/controller.d.ts +8 -37
- package/dist/controller.d.ts.map +1 -1
- package/dist/errorMessage.d.ts +27 -0
- package/dist/errorMessage.d.ts.map +1 -0
- package/dist/fieldArray.d.ts +2 -1
- package/dist/fieldArray.d.ts.map +1 -1
- package/dist/form.d.ts +8 -17
- package/dist/form.d.ts.map +1 -1
- package/dist/formState.d.ts +12 -0
- package/dist/formState.d.ts.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.mjs +2966 -2581
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/collectDirtyFieldNames.d.ts +3 -0
- package/dist/logic/collectDirtyFieldNames.d.ts.map +1 -0
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/generateId.d.ts.map +1 -1
- package/dist/logic/getCheckboxValue.d.ts.map +1 -1
- package/dist/logic/getDirtyFields.d.ts +3 -2
- package/dist/logic/getDirtyFields.d.ts.map +1 -1
- package/dist/logic/getEventValue.d.ts.map +1 -1
- package/dist/logic/getFieldArrayItemNames.d.ts +4 -0
- package/dist/logic/getFieldArrayItemNames.d.ts.map +1 -0
- package/dist/logic/getFieldValue.d.ts.map +1 -1
- package/dist/logic/getNullAncestorValue.d.ts +5 -0
- package/dist/logic/getNullAncestorValue.d.ts.map +1 -0
- package/dist/logic/getProxyFormState.d.ts +1 -1
- package/dist/logic/getProxyFormState.d.ts.map +1 -1
- package/dist/logic/getResolverOptions.d.ts +1 -0
- package/dist/logic/getResolverOptions.d.ts.map +1 -1
- package/dist/logic/getValueAndMessage.d.ts +1 -4
- package/dist/logic/getValueAndMessage.d.ts.map +1 -1
- package/dist/logic/hasValidation.d.ts +1 -1
- package/dist/logic/hasValidation.d.ts.map +1 -1
- package/dist/logic/iterateFieldsByAction.d.ts +1 -1
- package/dist/logic/iterateFieldsByAction.d.ts.map +1 -1
- package/dist/logic/schemaErrorLookup.d.ts.map +1 -1
- package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
- package/dist/logic/unsetEmptyArray.d.ts +1 -1
- package/dist/logic/unsetEmptyArray.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +545 -262
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/errors.d.ts +9 -4
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/fields.d.ts +1 -0
- package/dist/types/fields.d.ts.map +1 -1
- package/dist/types/form.d.ts +108 -59
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/path/common.d.ts +6 -0
- package/dist/types/path/common.d.ts.map +1 -1
- package/dist/types/path/eager.d.ts +16 -12
- package/dist/types/path/eager.d.ts.map +1 -1
- package/dist/types/utils.d.ts +30 -5
- package/dist/types/utils.d.ts.map +1 -1
- package/dist/types/validator.d.ts +1 -1
- package/dist/types/validator.d.ts.map +1 -1
- package/dist/types/watch.d.ts +1 -1
- package/dist/types/watch.d.ts.map +1 -1
- package/dist/useController.d.ts +5 -17
- package/dist/useController.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts +5 -30
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts +7 -22
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormContext.d.ts +11 -47
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useFormState.d.ts +4 -23
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useResyncOnReconnect.d.ts +5 -0
- package/dist/useResyncOnReconnect.d.ts.map +1 -0
- package/dist/useWatch.d.ts +7 -140
- package/dist/useWatch.d.ts.map +1 -1
- package/dist/utils/cloneObject.d.ts.map +1 -1
- package/dist/utils/deepEqual.d.ts +1 -1
- package/dist/utils/deepEqual.d.ts.map +1 -1
- package/dist/utils/flatten.d.ts.map +1 -1
- package/dist/utils/formData.d.ts +3 -0
- package/dist/utils/formData.d.ts.map +1 -0
- package/dist/utils/has.d.ts +3 -0
- package/dist/utils/has.d.ts.map +1 -0
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/updateMethodsReference.d.ts.map +1 -1
- package/dist/watch.d.ts +4 -16
- package/dist/watch.d.ts.map +1 -1
- package/package.json +14 -15
- package/dist/formStateSubscribe.d.ts +0 -7
- package/dist/formStateSubscribe.d.ts.map +0 -1
- package/dist/logic/getNodeParentName.d.ts +0 -3
- package/dist/logic/getNodeParentName.d.ts.map +0 -1
- package/dist/utils/deepMerge.d.ts +0 -2
- package/dist/utils/deepMerge.d.ts.map +0 -1
|
@@ -31,38 +31,37 @@ const INPUT_VALIDATION_RULES = {
|
|
|
31
31
|
required: 'required',
|
|
32
32
|
validate: 'validate',
|
|
33
33
|
};
|
|
34
|
+
const REGISTER_VALIDATION_RULES = [
|
|
35
|
+
INPUT_VALIDATION_RULES.required,
|
|
36
|
+
INPUT_VALIDATION_RULES.min,
|
|
37
|
+
INPUT_VALIDATION_RULES.max,
|
|
38
|
+
INPUT_VALIDATION_RULES.minLength,
|
|
39
|
+
INPUT_VALIDATION_RULES.maxLength,
|
|
40
|
+
INPUT_VALIDATION_RULES.pattern,
|
|
41
|
+
INPUT_VALIDATION_RULES.validate,
|
|
42
|
+
];
|
|
43
|
+
const FORM_ERROR_TYPE = 'form';
|
|
34
44
|
const ROOT_ERROR_TYPE = 'root';
|
|
35
45
|
const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
|
|
36
46
|
|
|
37
|
-
var isDateObject = (value) => value instanceof Date;
|
|
38
|
-
|
|
39
|
-
var isNullOrUndefined = (value) => value == null;
|
|
40
|
-
|
|
41
|
-
const isObjectType = (value) => typeof value === 'object';
|
|
42
|
-
var isObject = (value) => !isNullOrUndefined(value) &&
|
|
43
|
-
!Array.isArray(value) &&
|
|
44
|
-
isObjectType(value) &&
|
|
45
|
-
!isDateObject(value);
|
|
46
|
-
|
|
47
|
-
var isPlainObject = (tempObject) => {
|
|
48
|
-
const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
|
|
49
|
-
return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
|
|
50
|
-
};
|
|
51
|
-
|
|
52
47
|
var isWeb = typeof window !== 'undefined' &&
|
|
53
48
|
typeof window.HTMLElement !== 'undefined' &&
|
|
54
49
|
typeof document !== 'undefined';
|
|
55
50
|
|
|
56
51
|
function cloneObject(data) {
|
|
52
|
+
if (data === null || typeof data !== 'object') {
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
57
55
|
if (data instanceof Date) {
|
|
58
56
|
return new Date(data);
|
|
59
57
|
}
|
|
58
|
+
const isBlobInstance = typeof Blob !== 'undefined' && data instanceof Blob;
|
|
60
59
|
const isFileListInstance = typeof FileList !== 'undefined' && data instanceof FileList;
|
|
61
|
-
if (isWeb && (
|
|
60
|
+
if (isWeb && (isBlobInstance || isFileListInstance)) {
|
|
62
61
|
return data;
|
|
63
62
|
}
|
|
64
63
|
const isArray = Array.isArray(data);
|
|
65
|
-
if (!isArray &&
|
|
64
|
+
if (!isArray && data.constructor !== Object) {
|
|
66
65
|
return data;
|
|
67
66
|
}
|
|
68
67
|
const copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
|
|
@@ -106,6 +105,21 @@ var createSubject = () => {
|
|
|
106
105
|
};
|
|
107
106
|
};
|
|
108
107
|
|
|
108
|
+
var isDateObject = (value) => value instanceof Date;
|
|
109
|
+
|
|
110
|
+
var isNullOrUndefined = (value) => value == null;
|
|
111
|
+
|
|
112
|
+
const isObjectType = (value) => typeof value === 'object';
|
|
113
|
+
var isObject = (value) => !isNullOrUndefined(value) &&
|
|
114
|
+
!Array.isArray(value) &&
|
|
115
|
+
isObjectType(value) &&
|
|
116
|
+
!isDateObject(value);
|
|
117
|
+
|
|
118
|
+
var isPlainObject = (tempObject) => {
|
|
119
|
+
const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
|
|
120
|
+
return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
|
|
121
|
+
};
|
|
122
|
+
|
|
109
123
|
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
110
124
|
|
|
111
125
|
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
@@ -163,16 +177,15 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
function extractFormValues(fieldsState, formValues) {
|
|
166
|
-
const values = {};
|
|
180
|
+
const values = (Array.isArray(fieldsState) ? [] : {});
|
|
167
181
|
for (const key in fieldsState) {
|
|
168
182
|
if (fieldsState.hasOwnProperty(key)) {
|
|
169
183
|
const fieldState = fieldsState[key];
|
|
170
184
|
const fieldValue = formValues[key];
|
|
171
|
-
if (fieldState &&
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
185
|
+
if (fieldState &&
|
|
186
|
+
(isObject(fieldState) || Array.isArray(fieldState)) &&
|
|
187
|
+
fieldValue) {
|
|
188
|
+
values[key] = extractFormValues(fieldState, fieldValue);
|
|
176
189
|
}
|
|
177
190
|
else if (fieldsState[key]) {
|
|
178
191
|
values[key] = fieldValue;
|
|
@@ -182,24 +195,6 @@ function extractFormValues(fieldsState, formValues) {
|
|
|
182
195
|
return values;
|
|
183
196
|
}
|
|
184
197
|
|
|
185
|
-
const flatten = (obj) => {
|
|
186
|
-
const output = {};
|
|
187
|
-
for (const key of Object.keys(obj)) {
|
|
188
|
-
if (isObjectType(obj[key]) &&
|
|
189
|
-
obj[key] !== null &&
|
|
190
|
-
!isDateObject(obj[key])) {
|
|
191
|
-
const nested = flatten(obj[key]);
|
|
192
|
-
for (const nestedKey of Object.keys(nested)) {
|
|
193
|
-
output[`${key}.${nestedKey}`] = nested[nestedKey];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
output[key] = obj[key];
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return output;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
198
|
const IS_KEY_RE = /^\w*$/;
|
|
204
199
|
var isKey = (value) => IS_KEY_RE.test(value);
|
|
205
200
|
|
|
@@ -226,6 +221,24 @@ var get = (object, path, defaultValue) => {
|
|
|
226
221
|
: result;
|
|
227
222
|
};
|
|
228
223
|
|
|
224
|
+
const hasOwn = (value, key) => value !== null &&
|
|
225
|
+
isObjectType(value) &&
|
|
226
|
+
Object.prototype.hasOwnProperty.call(value, key);
|
|
227
|
+
var has = (object, path) => {
|
|
228
|
+
if (!path) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
let result = object;
|
|
232
|
+
for (const key of isKey(path) ? [path] : stringToPath(path)) {
|
|
233
|
+
if (!hasOwn(result, key)) {
|
|
234
|
+
// `get` also resolves a path held as a single literal key, eg `{ 'a.b': 1 }`
|
|
235
|
+
return hasOwn(object, path);
|
|
236
|
+
}
|
|
237
|
+
result = result[key];
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
};
|
|
241
|
+
|
|
229
242
|
var isBoolean = (value) => typeof value === 'boolean';
|
|
230
243
|
|
|
231
244
|
var isCheckBoxInput = (element) => element.type === 'checkbox';
|
|
@@ -281,7 +294,7 @@ var set = (object, path, value) => {
|
|
|
281
294
|
};
|
|
282
295
|
|
|
283
296
|
function baseGet(object, updatePath) {
|
|
284
|
-
const length = updatePath.
|
|
297
|
+
const length = updatePath.length - 1;
|
|
285
298
|
let index = 0;
|
|
286
299
|
while (index < length) {
|
|
287
300
|
if (isNullOrUndefined(object)) {
|
|
@@ -328,6 +341,24 @@ function unset(object, path) {
|
|
|
328
341
|
return object;
|
|
329
342
|
}
|
|
330
343
|
|
|
344
|
+
function isDirtyContainer(value) {
|
|
345
|
+
return Array.isArray(value) || isObject(value);
|
|
346
|
+
}
|
|
347
|
+
function collectDirtyFieldNames(dirtyTree, cachedDirtyFields, prefix = '', names = []) {
|
|
348
|
+
for (const key in dirtyTree) {
|
|
349
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
350
|
+
const value = dirtyTree[key];
|
|
351
|
+
if (isDirtyContainer(value) &&
|
|
352
|
+
isDirtyContainer(get(cachedDirtyFields, path))) {
|
|
353
|
+
collectDirtyFieldNames(value, cachedDirtyFields, path, names);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
names.push(path);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return names;
|
|
360
|
+
}
|
|
361
|
+
|
|
331
362
|
var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
|
|
332
363
|
if (isString(names)) {
|
|
333
364
|
isGlobal && _names.watch.add(names);
|
|
@@ -335,7 +366,7 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
335
366
|
}
|
|
336
367
|
if (Array.isArray(names)) {
|
|
337
368
|
return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
|
|
338
|
-
get(formValues, fieldName)));
|
|
369
|
+
get(formValues, fieldName, get(defaultValue, fieldName))));
|
|
339
370
|
}
|
|
340
371
|
isGlobal && (_names.watchAll = true);
|
|
341
372
|
return formValues;
|
|
@@ -353,12 +384,33 @@ var objectHasFunction = (data) => {
|
|
|
353
384
|
function isTraversable(value) {
|
|
354
385
|
return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
|
|
355
386
|
}
|
|
356
|
-
function
|
|
387
|
+
function isRegisteredLeaf(fieldRef) {
|
|
388
|
+
return !!(fieldRef && '_f' in fieldRef);
|
|
389
|
+
}
|
|
390
|
+
function isEmptyDirtyContainer(value) {
|
|
391
|
+
return Array.isArray(value)
|
|
392
|
+
? !value.some((item) => !isUndefined(item))
|
|
393
|
+
: !Object.keys(value).length;
|
|
394
|
+
}
|
|
395
|
+
function clearDirtyField(container, key) {
|
|
396
|
+
if (Array.isArray(container)) {
|
|
397
|
+
container[key] = undefined;
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
delete container[key];
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function markFieldsDirty(data, fields = {}, fieldRefs) {
|
|
357
404
|
for (const key in data) {
|
|
358
405
|
const value = data[key];
|
|
359
|
-
|
|
406
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
407
|
+
if (isTraversable(value) &&
|
|
408
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
360
409
|
fields[key] = Array.isArray(value) ? [] : {};
|
|
361
|
-
markFieldsDirty(value, fields[key]);
|
|
410
|
+
markFieldsDirty(value, fields[key], fieldRef);
|
|
411
|
+
if (isEmptyDirtyContainer(fields[key])) {
|
|
412
|
+
clearDirtyField(fields, key);
|
|
413
|
+
}
|
|
362
414
|
}
|
|
363
415
|
else if (!isUndefined(value)) {
|
|
364
416
|
fields[key] = true;
|
|
@@ -366,80 +418,80 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
366
418
|
}
|
|
367
419
|
return fields;
|
|
368
420
|
}
|
|
369
|
-
function
|
|
370
|
-
if (value === false) {
|
|
371
|
-
return undefined;
|
|
372
|
-
}
|
|
373
|
-
if (value === true) {
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
if (Array.isArray(value)) {
|
|
377
|
-
const result = value.map((value) => pruneDirtyFields(value));
|
|
378
|
-
return (result.some((value) => value !== undefined) ? result : undefined);
|
|
379
|
-
}
|
|
380
|
-
if (isObject(value)) {
|
|
381
|
-
const result = {};
|
|
382
|
-
for (const key in value) {
|
|
383
|
-
const pruned = pruneDirtyFields(value[key]);
|
|
384
|
-
if (!isUndefined(pruned)) {
|
|
385
|
-
result[key] = pruned;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return (Object.keys(result).length ? result : undefined);
|
|
389
|
-
}
|
|
390
|
-
return undefined;
|
|
391
|
-
}
|
|
392
|
-
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
421
|
+
function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
|
|
393
422
|
if (!dirtyFieldsFromValues) {
|
|
394
|
-
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
423
|
+
dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
|
|
395
424
|
}
|
|
396
425
|
for (const key in data) {
|
|
397
426
|
const value = data[key];
|
|
398
|
-
|
|
427
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
428
|
+
if (isTraversable(value) &&
|
|
429
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
399
430
|
if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
|
|
400
|
-
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
|
|
431
|
+
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
|
|
401
432
|
}
|
|
402
433
|
else {
|
|
403
|
-
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
|
|
434
|
+
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
|
|
435
|
+
}
|
|
436
|
+
if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
|
|
437
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
404
438
|
}
|
|
405
439
|
}
|
|
440
|
+
else if (deepEqual(value, formValues[key])) {
|
|
441
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
442
|
+
}
|
|
406
443
|
else {
|
|
407
|
-
|
|
408
|
-
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
444
|
+
dirtyFieldsFromValues[key] = true;
|
|
409
445
|
}
|
|
410
446
|
}
|
|
411
|
-
return
|
|
447
|
+
return dirtyFieldsFromValues;
|
|
412
448
|
}
|
|
413
449
|
|
|
414
450
|
var getEventValue = (event) => isObject(event) && event.target
|
|
415
451
|
? isCheckBoxInput(event.target)
|
|
416
452
|
? event.target.checked
|
|
417
|
-
: event.target
|
|
453
|
+
: isFileInput(event.target)
|
|
454
|
+
? event.target.files
|
|
455
|
+
: event.target.value
|
|
418
456
|
: event;
|
|
419
457
|
|
|
458
|
+
var getFieldArrayItemNames = (names, name) => {
|
|
459
|
+
const segments = name.split('.');
|
|
460
|
+
const matches = [];
|
|
461
|
+
let prefix = segments[0];
|
|
462
|
+
for (let i = 1; i < segments.length; prefix += '.' + segments[i++]) {
|
|
463
|
+
if (!isNaN(+segments[i]) && names.has(prefix)) {
|
|
464
|
+
matches.push(`${prefix}.${segments[i]}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return matches;
|
|
468
|
+
};
|
|
469
|
+
|
|
420
470
|
const defaultResult = {
|
|
421
471
|
value: false,
|
|
422
472
|
isValid: false,
|
|
423
473
|
};
|
|
424
474
|
const validResult = { value: true, isValid: true };
|
|
425
475
|
var getCheckboxValue = (options) => {
|
|
426
|
-
if (Array.isArray(options)) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
return
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
return
|
|
476
|
+
if (!Array.isArray(options)) {
|
|
477
|
+
return defaultResult;
|
|
478
|
+
}
|
|
479
|
+
if (options.length > 1) {
|
|
480
|
+
const values = options
|
|
481
|
+
.filter((option) => option && option.checked && !option.disabled)
|
|
482
|
+
.map((option) => option.value);
|
|
483
|
+
return { value: values, isValid: !!values.length };
|
|
484
|
+
}
|
|
485
|
+
const option = options[0];
|
|
486
|
+
if (!option || !option.checked || option.disabled) {
|
|
487
|
+
return defaultResult;
|
|
488
|
+
}
|
|
489
|
+
if (!option.attributes || !('value' in option.attributes)) {
|
|
490
|
+
return validResult;
|
|
491
|
+
}
|
|
492
|
+
return isUndefined(option.value) || option.value === ''
|
|
493
|
+
? validResult
|
|
494
|
+
: { value: option.value, isValid: true };
|
|
443
495
|
};
|
|
444
496
|
|
|
445
497
|
var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
|
|
@@ -483,7 +535,7 @@ function getFieldValue(_f) {
|
|
|
483
535
|
if (isCheckBoxInput(ref)) {
|
|
484
536
|
return getCheckboxValue(_f.refs).value;
|
|
485
537
|
}
|
|
486
|
-
return getFieldValueAs(
|
|
538
|
+
return getFieldValueAs(ref.value, _f);
|
|
487
539
|
}
|
|
488
540
|
|
|
489
541
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
@@ -540,10 +592,11 @@ var hasPromiseValidation = (fieldReference) => {
|
|
|
540
592
|
|
|
541
593
|
var hasValidation = (options) => options.mount &&
|
|
542
594
|
(options.required ||
|
|
543
|
-
options.
|
|
544
|
-
options.
|
|
545
|
-
options.
|
|
546
|
-
options.
|
|
595
|
+
(!isUndefined(options.required) && options.required !== false) ||
|
|
596
|
+
!isUndefined(options.min) ||
|
|
597
|
+
!isUndefined(options.max) ||
|
|
598
|
+
!isUndefined(options.maxLength) ||
|
|
599
|
+
!isUndefined(options.minLength) ||
|
|
547
600
|
options.pattern ||
|
|
548
601
|
options.validate);
|
|
549
602
|
|
|
@@ -563,27 +616,30 @@ var isWatched = (name, _names, isBlurEvent) => {
|
|
|
563
616
|
return false;
|
|
564
617
|
};
|
|
565
618
|
|
|
566
|
-
const iterateFieldsByAction = (fields, action, fieldsNames
|
|
619
|
+
const iterateFieldsByAction = (fields, action, fieldsNames) => {
|
|
567
620
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
568
|
-
|
|
621
|
+
if (key === '_f') {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
const field = fieldsNames ? get(fields, key) : fields[key];
|
|
569
625
|
if (field) {
|
|
570
|
-
const { _f
|
|
626
|
+
const { _f } = field;
|
|
571
627
|
if (_f) {
|
|
572
|
-
if (_f.refs && _f.refs[0] && action(_f.refs[0],
|
|
628
|
+
if (_f.refs && _f.refs[0] && action(_f.refs[0], _f.name)) {
|
|
573
629
|
return true;
|
|
574
630
|
}
|
|
575
|
-
else if (_f.ref && action(_f.ref, _f.name)
|
|
631
|
+
else if (_f.ref && action(_f.ref, _f.name)) {
|
|
576
632
|
return true;
|
|
577
633
|
}
|
|
578
634
|
else {
|
|
579
|
-
if (iterateFieldsByAction(
|
|
580
|
-
|
|
635
|
+
if (iterateFieldsByAction(field, action)) {
|
|
636
|
+
return true;
|
|
581
637
|
}
|
|
582
638
|
}
|
|
583
639
|
}
|
|
584
|
-
else if (isObject(
|
|
585
|
-
if (iterateFieldsByAction(
|
|
586
|
-
|
|
640
|
+
else if (isObject(field) || Array.isArray(field)) {
|
|
641
|
+
if (iterateFieldsByAction(field, action)) {
|
|
642
|
+
return true;
|
|
587
643
|
}
|
|
588
644
|
}
|
|
589
645
|
}
|
|
@@ -593,7 +649,7 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
|
593
649
|
|
|
594
650
|
function schemaErrorLookup(errors, _fields, name) {
|
|
595
651
|
const error = get(errors, name);
|
|
596
|
-
if (error ||
|
|
652
|
+
if (error?.type || error?.message || Array.isArray(error)) {
|
|
597
653
|
return {
|
|
598
654
|
error,
|
|
599
655
|
name,
|
|
@@ -628,8 +684,7 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
628
684
|
|
|
629
685
|
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
630
686
|
updateFormState(formStateData);
|
|
631
|
-
const
|
|
632
|
-
const keys = Object.keys(formState);
|
|
687
|
+
const keys = Object.keys(formStateData).filter((key) => key !== 'name');
|
|
633
688
|
return (!keys.length ||
|
|
634
689
|
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
635
690
|
keys.find((key) => _proxyFormState[key] ===
|
|
@@ -661,7 +716,12 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
661
716
|
return true;
|
|
662
717
|
};
|
|
663
718
|
|
|
664
|
-
var unsetEmptyArray = (ref, name) =>
|
|
719
|
+
var unsetEmptyArray = (ref, name) => {
|
|
720
|
+
const array = get(ref, name);
|
|
721
|
+
!compact(array).length &&
|
|
722
|
+
!array?.root &&
|
|
723
|
+
unset(ref, name);
|
|
724
|
+
};
|
|
665
725
|
|
|
666
726
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
667
727
|
const existingErrors = get(errors, name);
|
|
@@ -691,7 +751,7 @@ var getValueAndMessage = (validationData) => isObject(validationData) && !isRege
|
|
|
691
751
|
};
|
|
692
752
|
|
|
693
753
|
var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
|
|
694
|
-
const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f;
|
|
754
|
+
const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, _c, } = field._f;
|
|
695
755
|
const inputValue = get(formValues, name);
|
|
696
756
|
if (!mount || disabledFieldNames.has(name)) {
|
|
697
757
|
return {};
|
|
@@ -701,7 +761,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
701
761
|
if (shouldUseNativeValidation && inputRef.reportValidity) {
|
|
702
762
|
const validityMessage = isBoolean(message) ? '' : message || '';
|
|
703
763
|
if (refs) {
|
|
704
|
-
refs.forEach((ref) => ref.setCustomValidity
|
|
764
|
+
refs.forEach((ref) => isFunction(ref.setCustomValidity) &&
|
|
765
|
+
ref.setCustomValidity(validityMessage));
|
|
705
766
|
}
|
|
706
767
|
else {
|
|
707
768
|
inputRef.setCustomValidity(validityMessage);
|
|
@@ -716,7 +777,7 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
716
777
|
const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
|
|
717
778
|
isUndefined(ref.value) &&
|
|
718
779
|
isUndefined(inputValue)) ||
|
|
719
|
-
(isHTMLElement(ref) && ref.value === '') ||
|
|
780
|
+
(isHTMLElement(ref) && ref.value === '' && !_c) ||
|
|
720
781
|
inputValue === '' ||
|
|
721
782
|
(Array.isArray(inputValue) && !inputValue.length);
|
|
722
783
|
const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
|
|
@@ -757,7 +818,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
757
818
|
let exceedMin;
|
|
758
819
|
const maxOutput = getValueAndMessage(max);
|
|
759
820
|
const minOutput = getValueAndMessage(min);
|
|
760
|
-
if (!isNullOrUndefined(inputValue) &&
|
|
821
|
+
if (!isNullOrUndefined(inputValue) &&
|
|
822
|
+
!isDateObject(inputValue) &&
|
|
823
|
+
!isNaN(inputValue)) {
|
|
761
824
|
const valueNumber = ref.valueAsNumber ||
|
|
762
825
|
(inputValue ? +inputValue : inputValue);
|
|
763
826
|
if (!isNullOrUndefined(maxOutput.value)) {
|
|
@@ -854,7 +917,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
854
917
|
...validateError,
|
|
855
918
|
...appendErrorsCurry(key, validateError.message),
|
|
856
919
|
};
|
|
857
|
-
|
|
920
|
+
if (!validateAllFieldCriteria) {
|
|
921
|
+
setCustomValidity(validateError.message);
|
|
922
|
+
}
|
|
858
923
|
if (validateAllFieldCriteria) {
|
|
859
924
|
error[name] = validationResult;
|
|
860
925
|
}
|
|
@@ -871,7 +936,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
871
936
|
}
|
|
872
937
|
}
|
|
873
938
|
}
|
|
874
|
-
|
|
939
|
+
const fieldError = error[name];
|
|
940
|
+
setCustomValidity(fieldError ? fieldError.message : true);
|
|
875
941
|
return error;
|
|
876
942
|
};
|
|
877
943
|
|
|
@@ -880,7 +946,14 @@ const defaultOptions = {
|
|
|
880
946
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
881
947
|
shouldFocusError: true,
|
|
882
948
|
};
|
|
883
|
-
const
|
|
949
|
+
const updateDirtyFields = (dirtyFields, nextDirtyFields) => {
|
|
950
|
+
for (const key in dirtyFields) {
|
|
951
|
+
if (!(key in nextDirtyFields)) {
|
|
952
|
+
delete dirtyFields[key];
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
Object.assign(dirtyFields, nextDirtyFields);
|
|
956
|
+
};
|
|
884
957
|
const DEFAULT_FORM_STATE = {
|
|
885
958
|
submitCount: 0,
|
|
886
959
|
isDirty: false,
|
|
@@ -914,6 +987,7 @@ function createFormControl(props = {}) {
|
|
|
914
987
|
: cloneObject(_defaultValues);
|
|
915
988
|
let _state = {
|
|
916
989
|
action: false,
|
|
990
|
+
actionArrayLengths: new Map(),
|
|
917
991
|
mount: false,
|
|
918
992
|
watch: false,
|
|
919
993
|
keepIsValid: false,
|
|
@@ -926,8 +1000,8 @@ function createFormControl(props = {}) {
|
|
|
926
1000
|
watch: new Set(),
|
|
927
1001
|
registerName: new Set(),
|
|
928
1002
|
};
|
|
929
|
-
|
|
930
|
-
|
|
1003
|
+
const delayErrorCallbacks = {};
|
|
1004
|
+
const timers = {};
|
|
931
1005
|
let _valuesSubscriberCount = 0;
|
|
932
1006
|
let _validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
933
1007
|
let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
@@ -946,27 +1020,40 @@ function createFormControl(props = {}) {
|
|
|
946
1020
|
let _proxySubscribeFormState = {
|
|
947
1021
|
..._proxyFormState,
|
|
948
1022
|
};
|
|
1023
|
+
const _isTracked = (...keys) => keys.some((key) => _proxyFormState[key] || _proxySubscribeFormState[key]);
|
|
949
1024
|
const _subjects = {
|
|
950
1025
|
array: createSubject(),
|
|
951
1026
|
state: createSubject(),
|
|
952
1027
|
};
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1028
|
+
let _setValidCallId = 0;
|
|
1029
|
+
let _resetCallId = 0;
|
|
1030
|
+
let shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
|
|
1031
|
+
const debounce = (name, callback) => (wait) => {
|
|
1032
|
+
clearTimeout(timers[name]);
|
|
1033
|
+
timers[name] = setTimeout(callback, wait);
|
|
1034
|
+
};
|
|
1035
|
+
const cancelDelayedError = (name) => {
|
|
1036
|
+
clearTimeout(timers[name]);
|
|
1037
|
+
delete timers[name];
|
|
1038
|
+
delete delayErrorCallbacks[name];
|
|
1039
|
+
};
|
|
1040
|
+
const cancelDelayedErrorTree = (name) => {
|
|
1041
|
+
cancelDelayedError(name);
|
|
1042
|
+
const prefix = `${name}.`;
|
|
1043
|
+
for (const key of Object.keys(delayErrorCallbacks)) {
|
|
1044
|
+
key.startsWith(prefix) && cancelDelayedError(key);
|
|
1045
|
+
}
|
|
957
1046
|
};
|
|
958
1047
|
const _setValid = async (shouldUpdateValid) => {
|
|
959
1048
|
if (_state.keepIsValid) {
|
|
960
1049
|
return;
|
|
961
1050
|
}
|
|
962
|
-
if (!_options.disabled &&
|
|
963
|
-
|
|
964
|
-
_proxySubscribeFormState.isValid ||
|
|
965
|
-
shouldUpdateValid)) {
|
|
1051
|
+
if (!_options.disabled && (_isTracked('isValid') || shouldUpdateValid)) {
|
|
1052
|
+
const callId = ++_setValidCallId;
|
|
966
1053
|
let isValid;
|
|
967
1054
|
if (_options.resolver) {
|
|
968
1055
|
isValid = isEmptyObject((await _runSchema()).errors);
|
|
969
|
-
_updateIsValidating();
|
|
1056
|
+
callId === _setValidCallId && _updateIsValidating();
|
|
970
1057
|
}
|
|
971
1058
|
else {
|
|
972
1059
|
isValid = await executeBuiltInValidation({
|
|
@@ -975,7 +1062,7 @@ function createFormControl(props = {}) {
|
|
|
975
1062
|
eventType: EVENTS.VALID,
|
|
976
1063
|
});
|
|
977
1064
|
}
|
|
978
|
-
if (isValid !== _formState.isValid) {
|
|
1065
|
+
if (callId === _setValidCallId && isValid !== _formState.isValid) {
|
|
979
1066
|
_subjects.state.next({
|
|
980
1067
|
isValid,
|
|
981
1068
|
});
|
|
@@ -983,12 +1070,8 @@ function createFormControl(props = {}) {
|
|
|
983
1070
|
}
|
|
984
1071
|
};
|
|
985
1072
|
const _updateIsValidating = (names, isValidating) => {
|
|
986
|
-
if (!_options.disabled &&
|
|
987
|
-
(
|
|
988
|
-
_proxyFormState.validatingFields ||
|
|
989
|
-
_proxySubscribeFormState.isValidating ||
|
|
990
|
-
_proxySubscribeFormState.validatingFields)) {
|
|
991
|
-
(names || Array.from(_names.mount)).forEach((name) => {
|
|
1073
|
+
if (!_options.disabled && _isTracked('isValidating', 'validatingFields')) {
|
|
1074
|
+
(names || _names.mount).forEach((name) => {
|
|
992
1075
|
if (name) {
|
|
993
1076
|
isValidating
|
|
994
1077
|
? set(_formState.validatingFields, name, isValidating)
|
|
@@ -1002,35 +1085,50 @@ function createFormControl(props = {}) {
|
|
|
1002
1085
|
}
|
|
1003
1086
|
};
|
|
1004
1087
|
const _updateDirtyFields = () => {
|
|
1005
|
-
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1088
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
1006
1089
|
};
|
|
1007
1090
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1008
1091
|
if (args && method && !_options.disabled) {
|
|
1009
1092
|
_state.action = true;
|
|
1010
|
-
|
|
1011
|
-
|
|
1093
|
+
const fields = get(_fields, name);
|
|
1094
|
+
if (!_state.actionArrayLengths.has(name)) {
|
|
1095
|
+
_state.actionArrayLengths.set(name, Array.isArray(fields) ? fields.length : 0);
|
|
1096
|
+
}
|
|
1097
|
+
if (shouldUpdateFieldsAndState && Array.isArray(fields)) {
|
|
1098
|
+
const fieldValues = method(fields, args.argA, args.argB);
|
|
1012
1099
|
shouldSetValues && set(_fields, name, fieldValues);
|
|
1013
1100
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const
|
|
1101
|
+
const fieldArrayErrors = get(_formState.errors, name);
|
|
1102
|
+
if (shouldUpdateFieldsAndState && Array.isArray(fieldArrayErrors)) {
|
|
1103
|
+
const rootError = fieldArrayErrors.root;
|
|
1104
|
+
const errors = method(fieldArrayErrors, args.argA, args.argB) || fieldArrayErrors;
|
|
1105
|
+
if (rootError) {
|
|
1106
|
+
errors.root = rootError;
|
|
1107
|
+
}
|
|
1017
1108
|
shouldSetValues && set(_formState.errors, name, errors);
|
|
1018
1109
|
unsetEmptyArray(_formState.errors, name);
|
|
1019
1110
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
|
|
1111
|
+
const touchedFieldsArray = get(_formState.touchedFields, name);
|
|
1112
|
+
const shouldUpdateTouchedFields = shouldUpdateFieldsAndState && Array.isArray(touchedFieldsArray);
|
|
1113
|
+
if (shouldUpdateTouchedFields) {
|
|
1114
|
+
const touchedFields = method(touchedFieldsArray, args.argA, args.argB);
|
|
1025
1115
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1026
1116
|
}
|
|
1027
|
-
|
|
1117
|
+
const dirtyFieldsArray = get(_formState.dirtyFields, name);
|
|
1118
|
+
if (shouldUpdateFieldsAndState && Array.isArray(dirtyFieldsArray)) {
|
|
1119
|
+
const dirtyFields = method(dirtyFieldsArray, args.argA, args.argB) || dirtyFieldsArray;
|
|
1120
|
+
shouldSetValues && set(_formState.dirtyFields, name, dirtyFields);
|
|
1121
|
+
}
|
|
1122
|
+
if (_isTracked('dirtyFields')) {
|
|
1028
1123
|
_updateDirtyFields();
|
|
1029
1124
|
}
|
|
1030
1125
|
_subjects.state.next({
|
|
1031
1126
|
name,
|
|
1032
1127
|
isDirty: _getDirty(name, values),
|
|
1033
1128
|
dirtyFields: _formState.dirtyFields,
|
|
1129
|
+
...(shouldUpdateTouchedFields && {
|
|
1130
|
+
touchedFields: _formState.touchedFields,
|
|
1131
|
+
}),
|
|
1034
1132
|
errors: _formState.errors,
|
|
1035
1133
|
isValid: _formState.isValid,
|
|
1036
1134
|
});
|
|
@@ -1047,11 +1145,14 @@ function createFormControl(props = {}) {
|
|
|
1047
1145
|
});
|
|
1048
1146
|
};
|
|
1049
1147
|
const _setErrors = (errors) => {
|
|
1148
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1149
|
+
const hasErrors = !isEmptyObject(errors);
|
|
1050
1150
|
_formState.errors = errors;
|
|
1051
1151
|
_subjects.state.next({
|
|
1052
1152
|
errors: _formState.errors,
|
|
1053
|
-
isValid: false,
|
|
1153
|
+
...(hasErrors ? { isValid: false } : {}),
|
|
1054
1154
|
});
|
|
1155
|
+
!hasErrors && _state.mount && _setValid();
|
|
1055
1156
|
};
|
|
1056
1157
|
const hasExplicitNullIntermediate = (name) => {
|
|
1057
1158
|
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
@@ -1069,10 +1170,46 @@ function createFormControl(props = {}) {
|
|
|
1069
1170
|
}
|
|
1070
1171
|
return false;
|
|
1071
1172
|
};
|
|
1173
|
+
const isStaleArrayField = (name) => {
|
|
1174
|
+
if (!_state.actionArrayLengths.size) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
1178
|
+
let node = _formValues;
|
|
1179
|
+
let path = '';
|
|
1180
|
+
let ownerDepth = -1;
|
|
1181
|
+
let ownerPreActionLength = 0;
|
|
1182
|
+
for (let i = 0; i < segments.length; i++) {
|
|
1183
|
+
if (isNullOrUndefined(node)) {
|
|
1184
|
+
return false;
|
|
1185
|
+
}
|
|
1186
|
+
const key = segments[i];
|
|
1187
|
+
path = path ? `${path}.${key}` : key;
|
|
1188
|
+
if (Array.isArray(node) && +key >= node.length) {
|
|
1189
|
+
return ownerDepth === -1
|
|
1190
|
+
? false
|
|
1191
|
+
: i === ownerDepth
|
|
1192
|
+
? +key < ownerPreActionLength
|
|
1193
|
+
: true;
|
|
1194
|
+
}
|
|
1195
|
+
if (_state.actionArrayLengths.has(path)) {
|
|
1196
|
+
ownerDepth = i + 1;
|
|
1197
|
+
ownerPreActionLength = _state.actionArrayLengths.get(path);
|
|
1198
|
+
}
|
|
1199
|
+
node = node[key];
|
|
1200
|
+
if (isUndefined(node) &&
|
|
1201
|
+
ownerDepth !== -1 &&
|
|
1202
|
+
i > ownerDepth &&
|
|
1203
|
+
+segments[ownerDepth] < ownerPreActionLength) {
|
|
1204
|
+
return true;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
return false;
|
|
1208
|
+
};
|
|
1072
1209
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1073
1210
|
const field = get(_fields, name);
|
|
1074
1211
|
if (field) {
|
|
1075
|
-
if (hasExplicitNullIntermediate(name)) {
|
|
1212
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayField(name)) {
|
|
1076
1213
|
return;
|
|
1077
1214
|
}
|
|
1078
1215
|
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
@@ -1083,10 +1220,16 @@ function createFormControl(props = {}) {
|
|
|
1083
1220
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1084
1221
|
: setFieldValue(name, defaultValue);
|
|
1085
1222
|
if (_state.mount && !_state.action) {
|
|
1086
|
-
|
|
1223
|
+
if (_options.resolver &&
|
|
1224
|
+
_isTracked('isValidating', 'validatingFields')) {
|
|
1225
|
+
Promise.resolve().then(() => _setValid());
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
_setValid();
|
|
1229
|
+
}
|
|
1087
1230
|
if (wasUnsetInFormValues &&
|
|
1088
1231
|
_formState.isDirty &&
|
|
1089
|
-
(
|
|
1232
|
+
_isTracked('isDirty')) {
|
|
1090
1233
|
const isDirty = _getDirty();
|
|
1091
1234
|
if (!isDirty) {
|
|
1092
1235
|
_formState.isDirty = false;
|
|
@@ -1108,10 +1251,12 @@ function createFormControl(props = {}) {
|
|
|
1108
1251
|
const output = {
|
|
1109
1252
|
name,
|
|
1110
1253
|
};
|
|
1111
|
-
|
|
1254
|
+
// an explicit programmatic update (e.g. setValue with shouldDirty: true)
|
|
1255
|
+
// opts into dirty tracking even when the form is disabled
|
|
1256
|
+
if (!_options.disabled || shouldDirty === true) {
|
|
1112
1257
|
if (!isBlurEvent || shouldDirty) {
|
|
1113
1258
|
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1114
|
-
if (
|
|
1259
|
+
if (_isTracked('isDirty')) {
|
|
1115
1260
|
isPreviousDirty = _formState.isDirty;
|
|
1116
1261
|
_formState.isDirty = output.isDirty =
|
|
1117
1262
|
!isCurrentFieldPristine || _getDirty();
|
|
@@ -1119,7 +1264,7 @@ function createFormControl(props = {}) {
|
|
|
1119
1264
|
}
|
|
1120
1265
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1121
1266
|
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1122
|
-
_formState.dirtyFields
|
|
1267
|
+
updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
|
|
1123
1268
|
}
|
|
1124
1269
|
else {
|
|
1125
1270
|
isCurrentFieldPristine
|
|
@@ -1129,8 +1274,7 @@ function createFormControl(props = {}) {
|
|
|
1129
1274
|
output.dirtyFields = _formState.dirtyFields;
|
|
1130
1275
|
shouldUpdateField =
|
|
1131
1276
|
shouldUpdateField ||
|
|
1132
|
-
((
|
|
1133
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
1277
|
+
(_isTracked('dirtyFields') &&
|
|
1134
1278
|
isPreviousDirty !== !isCurrentFieldPristine);
|
|
1135
1279
|
}
|
|
1136
1280
|
if (isBlurEvent) {
|
|
@@ -1140,8 +1284,7 @@ function createFormControl(props = {}) {
|
|
|
1140
1284
|
output.touchedFields = _formState.touchedFields;
|
|
1141
1285
|
shouldUpdateField =
|
|
1142
1286
|
shouldUpdateField ||
|
|
1143
|
-
((
|
|
1144
|
-
_proxySubscribeFormState.touchedFields) &&
|
|
1287
|
+
(_isTracked('touchedFields') &&
|
|
1145
1288
|
isPreviousFieldTouched !== isBlurEvent);
|
|
1146
1289
|
}
|
|
1147
1290
|
}
|
|
@@ -1151,16 +1294,15 @@ function createFormControl(props = {}) {
|
|
|
1151
1294
|
};
|
|
1152
1295
|
const shouldRenderByError = (name, isValid, error, fieldState) => {
|
|
1153
1296
|
const previousFieldError = get(_formState.errors, name);
|
|
1154
|
-
const shouldUpdateValid = (
|
|
1297
|
+
const shouldUpdateValid = _isTracked('isValid') &&
|
|
1155
1298
|
isBoolean(isValid) &&
|
|
1156
1299
|
_formState.isValid !== isValid;
|
|
1157
1300
|
if (_options.delayError && error) {
|
|
1158
|
-
|
|
1159
|
-
|
|
1301
|
+
delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
|
|
1302
|
+
delayErrorCallbacks[name](_options.delayError);
|
|
1160
1303
|
}
|
|
1161
1304
|
else {
|
|
1162
|
-
|
|
1163
|
-
delayErrorCallback = null;
|
|
1305
|
+
cancelDelayedError(name);
|
|
1164
1306
|
error
|
|
1165
1307
|
? set(_formState.errors, name, error)
|
|
1166
1308
|
: unset(_formState.errors, name);
|
|
@@ -1175,10 +1317,6 @@ function createFormControl(props = {}) {
|
|
|
1175
1317
|
errors: _formState.errors,
|
|
1176
1318
|
name,
|
|
1177
1319
|
};
|
|
1178
|
-
_formState = {
|
|
1179
|
-
..._formState,
|
|
1180
|
-
...updatedFormState,
|
|
1181
|
-
};
|
|
1182
1320
|
_subjects.state.next(updatedFormState);
|
|
1183
1321
|
}
|
|
1184
1322
|
};
|
|
@@ -1187,55 +1325,76 @@ function createFormControl(props = {}) {
|
|
|
1187
1325
|
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1188
1326
|
};
|
|
1189
1327
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1328
|
+
const resetCallId = _resetCallId;
|
|
1190
1329
|
const { errors } = await _runSchema(names);
|
|
1330
|
+
if (resetCallId !== _resetCallId) {
|
|
1331
|
+
return errors;
|
|
1332
|
+
}
|
|
1191
1333
|
_updateIsValidating(names);
|
|
1192
1334
|
if (names) {
|
|
1193
1335
|
for (const name of names) {
|
|
1194
1336
|
const error = get(errors, name);
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1337
|
+
cancelDelayedErrorTree(name);
|
|
1338
|
+
const isFieldArrayRootError = _names.array.has(name) &&
|
|
1339
|
+
isObject(error) &&
|
|
1340
|
+
!Object.keys(error).some((key) => !Number.isNaN(Number(key)));
|
|
1341
|
+
const field = get(_fields, name);
|
|
1342
|
+
const hasNestedFields = isObject(field) && Object.keys(field).some((key) => key !== '_f');
|
|
1343
|
+
isFieldArrayRootError
|
|
1344
|
+
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
1345
|
+
: error?.type ||
|
|
1346
|
+
error?.message ||
|
|
1347
|
+
Array.isArray(error) ||
|
|
1348
|
+
(isObject(error) && hasNestedFields)
|
|
1349
|
+
? set(_formState.errors, name, error)
|
|
1350
|
+
: unset(_formState.errors, name);
|
|
1202
1351
|
}
|
|
1203
1352
|
_formState.errors = { ..._formState.errors };
|
|
1204
1353
|
}
|
|
1205
1354
|
else {
|
|
1355
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1206
1356
|
_formState.errors = errors;
|
|
1207
1357
|
}
|
|
1208
1358
|
return errors;
|
|
1209
1359
|
};
|
|
1210
1360
|
const validateForm = async ({ name, eventType, }) => {
|
|
1211
|
-
if (
|
|
1212
|
-
const
|
|
1361
|
+
if (_options.validate) {
|
|
1362
|
+
const resetCallId = _resetCallId;
|
|
1363
|
+
const result = await _options.validate({
|
|
1213
1364
|
formValues: _formValues,
|
|
1214
1365
|
formState: _formState,
|
|
1215
1366
|
name,
|
|
1216
1367
|
eventType,
|
|
1217
1368
|
});
|
|
1369
|
+
if (resetCallId !== _resetCallId) {
|
|
1370
|
+
return true;
|
|
1371
|
+
}
|
|
1218
1372
|
if (isObject(result)) {
|
|
1373
|
+
let isValid = true;
|
|
1374
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1219
1375
|
for (const key in result) {
|
|
1220
1376
|
const error = result[key];
|
|
1221
1377
|
if (error) {
|
|
1378
|
+
isValid = false;
|
|
1222
1379
|
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1223
1380
|
message: isString(error.message) ? error.message : '',
|
|
1224
1381
|
type: error.type || INPUT_VALIDATION_RULES.validate,
|
|
1225
1382
|
});
|
|
1226
1383
|
}
|
|
1227
1384
|
}
|
|
1385
|
+
return isValid;
|
|
1228
1386
|
}
|
|
1229
1387
|
else if (isString(result) || !result) {
|
|
1230
1388
|
setError(FORM_ERROR_TYPE, {
|
|
1231
1389
|
message: result || '',
|
|
1232
1390
|
type: INPUT_VALIDATION_RULES.validate,
|
|
1233
1391
|
});
|
|
1392
|
+
return false;
|
|
1234
1393
|
}
|
|
1235
1394
|
else {
|
|
1236
1395
|
clearErrors(FORM_ERROR_TYPE);
|
|
1396
|
+
return true;
|
|
1237
1397
|
}
|
|
1238
|
-
return result;
|
|
1239
1398
|
}
|
|
1240
1399
|
return true;
|
|
1241
1400
|
};
|
|
@@ -1243,7 +1402,8 @@ function createFormControl(props = {}) {
|
|
|
1243
1402
|
valid: true,
|
|
1244
1403
|
runRootValidation: false,
|
|
1245
1404
|
}, }) => {
|
|
1246
|
-
|
|
1405
|
+
const resetCallId = _resetCallId;
|
|
1406
|
+
if (_options.validate && !context.runRootValidation) {
|
|
1247
1407
|
context.runRootValidation = true;
|
|
1248
1408
|
const result = await validateForm({
|
|
1249
1409
|
name,
|
|
@@ -1263,14 +1423,14 @@ function createFormControl(props = {}) {
|
|
|
1263
1423
|
if (_f) {
|
|
1264
1424
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
1265
1425
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
1266
|
-
const shouldTrackIsValidatingState =
|
|
1267
|
-
_proxyFormState.isValidating ||
|
|
1268
|
-
_proxySubscribeFormState.validatingFields ||
|
|
1269
|
-
_proxySubscribeFormState.isValidating;
|
|
1426
|
+
const shouldTrackIsValidatingState = _isTracked('isValidating', 'validatingFields');
|
|
1270
1427
|
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1271
1428
|
_updateIsValidating([_f.name], true);
|
|
1272
1429
|
}
|
|
1273
1430
|
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1431
|
+
if (resetCallId !== _resetCallId) {
|
|
1432
|
+
return context.valid;
|
|
1433
|
+
}
|
|
1274
1434
|
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1275
1435
|
_updateIsValidating([_f.name]);
|
|
1276
1436
|
}
|
|
@@ -1280,12 +1440,14 @@ function createFormControl(props = {}) {
|
|
|
1280
1440
|
break;
|
|
1281
1441
|
}
|
|
1282
1442
|
}
|
|
1283
|
-
!onlyCheckValid
|
|
1284
|
-
(
|
|
1443
|
+
if (!onlyCheckValid) {
|
|
1444
|
+
cancelDelayedError(_f.name);
|
|
1445
|
+
get(fieldError, _f.name)
|
|
1285
1446
|
? isFieldArrayRoot
|
|
1286
1447
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1287
1448
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1288
|
-
: unset(_formState.errors, _f.name)
|
|
1449
|
+
: unset(_formState.errors, _f.name);
|
|
1450
|
+
}
|
|
1289
1451
|
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1290
1452
|
break;
|
|
1291
1453
|
}
|
|
@@ -1313,20 +1475,17 @@ function createFormControl(props = {}) {
|
|
|
1313
1475
|
}
|
|
1314
1476
|
_names.unMount = new Set();
|
|
1315
1477
|
};
|
|
1316
|
-
const _getDirty = (name, data) =>
|
|
1317
|
-
(
|
|
1318
|
-
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1478
|
+
const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
|
|
1479
|
+
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1319
1480
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
1320
1481
|
...(_state.mount
|
|
1321
1482
|
? _formValues
|
|
1322
|
-
: isUndefined(defaultValue)
|
|
1483
|
+
: isUndefined(defaultValue) || isString(names)
|
|
1323
1484
|
? _defaultValues
|
|
1324
|
-
:
|
|
1325
|
-
? { [names]: defaultValue }
|
|
1326
|
-
: defaultValue),
|
|
1485
|
+
: defaultValue),
|
|
1327
1486
|
}, isGlobal, defaultValue);
|
|
1328
1487
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
1329
|
-
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
|
|
1488
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
1330
1489
|
const field = get(_fields, name);
|
|
1331
1490
|
let fieldValue = value;
|
|
1332
1491
|
if (field) {
|
|
@@ -1364,7 +1523,7 @@ function createFormControl(props = {}) {
|
|
|
1364
1523
|
}
|
|
1365
1524
|
else {
|
|
1366
1525
|
fieldReference.ref.value = fieldValue;
|
|
1367
|
-
if (!fieldReference.ref.type && !skipRender) {
|
|
1526
|
+
if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
|
|
1368
1527
|
_subjects.state.next({
|
|
1369
1528
|
name,
|
|
1370
1529
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
@@ -1374,13 +1533,36 @@ function createFormControl(props = {}) {
|
|
|
1374
1533
|
}
|
|
1375
1534
|
}
|
|
1376
1535
|
(options.shouldDirty || options.shouldTouch) &&
|
|
1377
|
-
updateTouchAndDirty(name,
|
|
1378
|
-
|
|
1536
|
+
updateTouchAndDirty(name, field &&
|
|
1537
|
+
field._f &&
|
|
1538
|
+
!field._f.disabled &&
|
|
1539
|
+
(field._f.valueAsNumber ||
|
|
1540
|
+
field._f.valueAsDate ||
|
|
1541
|
+
field._f.setValueAs)
|
|
1542
|
+
? getFieldValueAs(value, field._f)
|
|
1543
|
+
: fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
|
|
1544
|
+
options.shouldValidate &&
|
|
1545
|
+
trigger(name, {
|
|
1546
|
+
delayError: options.delayError,
|
|
1547
|
+
});
|
|
1548
|
+
if (options.shouldValidate &&
|
|
1549
|
+
field &&
|
|
1550
|
+
field._f &&
|
|
1551
|
+
field._f.deps &&
|
|
1552
|
+
(!Array.isArray(field._f.deps) || field._f.deps.length > 0)) {
|
|
1553
|
+
trigger(field._f.deps);
|
|
1554
|
+
}
|
|
1379
1555
|
};
|
|
1380
|
-
const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
|
|
1556
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
1557
|
+
if (_names.array.has(name)) {
|
|
1558
|
+
_subjects.array.next({
|
|
1559
|
+
name,
|
|
1560
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1381
1563
|
for (const fieldKey in value) {
|
|
1382
1564
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1383
|
-
|
|
1565
|
+
continue;
|
|
1384
1566
|
}
|
|
1385
1567
|
const fieldValue = value[fieldKey];
|
|
1386
1568
|
const fieldName = name + '.' + fieldKey;
|
|
@@ -1389,8 +1571,8 @@ function createFormControl(props = {}) {
|
|
|
1389
1571
|
isObject(fieldValue) ||
|
|
1390
1572
|
(field && !field._f)) &&
|
|
1391
1573
|
!isDateObject(fieldValue)
|
|
1392
|
-
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
|
|
1393
|
-
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
|
|
1574
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
|
|
1575
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
|
|
1394
1576
|
}
|
|
1395
1577
|
};
|
|
1396
1578
|
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
@@ -1407,11 +1589,7 @@ function createFormControl(props = {}) {
|
|
|
1407
1589
|
name,
|
|
1408
1590
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1409
1591
|
});
|
|
1410
|
-
if ((
|
|
1411
|
-
_proxyFormState.dirtyFields ||
|
|
1412
|
-
_proxySubscribeFormState.isDirty ||
|
|
1413
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
1414
|
-
options.shouldDirty) {
|
|
1592
|
+
if (_isTracked('isDirty', 'dirtyFields') && options.shouldDirty) {
|
|
1415
1593
|
_updateDirtyFields();
|
|
1416
1594
|
if (!skipStateEmit) {
|
|
1417
1595
|
_subjects.state.next({
|
|
@@ -1421,15 +1599,20 @@ function createFormControl(props = {}) {
|
|
|
1421
1599
|
});
|
|
1422
1600
|
}
|
|
1423
1601
|
}
|
|
1602
|
+
options.shouldValidate &&
|
|
1603
|
+
trigger(name, {
|
|
1604
|
+
delayError: options.delayError,
|
|
1605
|
+
});
|
|
1424
1606
|
}
|
|
1425
1607
|
else {
|
|
1426
1608
|
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
1427
1609
|
isEmptyObject(cloneValue);
|
|
1610
|
+
const skipValueRender = !isValueUnchanged && !skipStateEmit;
|
|
1428
1611
|
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
1429
|
-
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
|
|
1612
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
1430
1613
|
}
|
|
1431
1614
|
else {
|
|
1432
|
-
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
|
|
1615
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
1433
1616
|
}
|
|
1434
1617
|
}
|
|
1435
1618
|
if (!isValueUnchanged && !skipStateEmit) {
|
|
@@ -1440,6 +1623,11 @@ function createFormControl(props = {}) {
|
|
|
1440
1623
|
name: _state.mount || watched ? name : undefined,
|
|
1441
1624
|
values,
|
|
1442
1625
|
});
|
|
1626
|
+
if (!isFieldArray) {
|
|
1627
|
+
for (const itemName of getFieldArrayItemNames(_names.array, name)) {
|
|
1628
|
+
_subjects.state.next({ name: itemName, values });
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1443
1631
|
}
|
|
1444
1632
|
};
|
|
1445
1633
|
const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
|
|
@@ -1452,10 +1640,9 @@ function createFormControl(props = {}) {
|
|
|
1452
1640
|
..._formValues,
|
|
1453
1641
|
...updatedFormValues,
|
|
1454
1642
|
};
|
|
1455
|
-
const flattenedUpdates = flatten(updatedFormValues);
|
|
1456
1643
|
for (const fieldName of _names.mount) {
|
|
1457
|
-
if (fieldName
|
|
1458
|
-
_setValue(fieldName,
|
|
1644
|
+
if (has(updatedFormValues, fieldName)) {
|
|
1645
|
+
_setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
|
|
1459
1646
|
}
|
|
1460
1647
|
}
|
|
1461
1648
|
_subjects.state.next({
|
|
@@ -1489,18 +1676,19 @@ function createFormControl(props = {}) {
|
|
|
1489
1676
|
: getEventValue(event);
|
|
1490
1677
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1491
1678
|
const hasNoValidationEffect = !hasValidation(field._f) &&
|
|
1492
|
-
!
|
|
1679
|
+
!_options.validate &&
|
|
1493
1680
|
!_options.resolver &&
|
|
1494
1681
|
!get(_formState.errors, name) &&
|
|
1495
1682
|
!field._f.deps;
|
|
1496
1683
|
const shouldSkipValidation = hasNoValidationEffect ||
|
|
1497
1684
|
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
1498
1685
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
1499
|
-
set(_formValues, name, fieldValue);
|
|
1686
|
+
set(_formValues, name, cloneObject(fieldValue));
|
|
1500
1687
|
if (isBlurEvent) {
|
|
1501
1688
|
if (!target || !target.readOnly) {
|
|
1502
1689
|
field._f.onBlur && field._f.onBlur(event);
|
|
1503
|
-
|
|
1690
|
+
const pendingDelayError = delayErrorCallbacks[name];
|
|
1691
|
+
pendingDelayError && pendingDelayError(0);
|
|
1504
1692
|
}
|
|
1505
1693
|
}
|
|
1506
1694
|
else if (field._f.onChange) {
|
|
@@ -1518,7 +1706,7 @@ function createFormControl(props = {}) {
|
|
|
1518
1706
|
});
|
|
1519
1707
|
if (shouldSkipValidation) {
|
|
1520
1708
|
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
1521
|
-
(
|
|
1709
|
+
_isTracked('isValid')) {
|
|
1522
1710
|
if (_options.mode === 'onBlur') {
|
|
1523
1711
|
if (isBlurEvent) {
|
|
1524
1712
|
_setValid();
|
|
@@ -1531,7 +1719,7 @@ function createFormControl(props = {}) {
|
|
|
1531
1719
|
return (shouldRender &&
|
|
1532
1720
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1533
1721
|
}
|
|
1534
|
-
if (!_options.resolver &&
|
|
1722
|
+
if (!_options.resolver && _options.validate) {
|
|
1535
1723
|
await validateForm({
|
|
1536
1724
|
name: name,
|
|
1537
1725
|
eventType: event.type,
|
|
@@ -1539,7 +1727,11 @@ function createFormControl(props = {}) {
|
|
|
1539
1727
|
}
|
|
1540
1728
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1541
1729
|
if (_options.resolver) {
|
|
1730
|
+
const resetCallId = _resetCallId;
|
|
1542
1731
|
const { errors } = await _runSchema([name]);
|
|
1732
|
+
if (resetCallId !== _resetCallId) {
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1543
1735
|
_updateIsValidating([name]);
|
|
1544
1736
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1545
1737
|
if (!isFieldValueUpdated) {
|
|
@@ -1553,22 +1745,28 @@ function createFormControl(props = {}) {
|
|
|
1553
1745
|
isValid = isEmptyObject(errors);
|
|
1554
1746
|
}
|
|
1555
1747
|
else {
|
|
1748
|
+
const resetCallId = _resetCallId;
|
|
1556
1749
|
_updateIsValidating([name], true);
|
|
1557
1750
|
error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
|
|
1751
|
+
if (resetCallId !== _resetCallId) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1558
1754
|
_updateIsValidating([name]);
|
|
1559
1755
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1560
1756
|
if (isFieldValueUpdated) {
|
|
1561
1757
|
if (error) {
|
|
1562
1758
|
isValid = false;
|
|
1563
1759
|
}
|
|
1564
|
-
else if (
|
|
1565
|
-
_proxySubscribeFormState.isValid) {
|
|
1760
|
+
else if (_isTracked('isValid')) {
|
|
1566
1761
|
isValid = await executeBuiltInValidation({
|
|
1567
1762
|
fields: _fields,
|
|
1568
1763
|
onlyCheckValid: true,
|
|
1569
1764
|
name: name,
|
|
1570
1765
|
eventType: event.type,
|
|
1571
1766
|
});
|
|
1767
|
+
if (resetCallId !== _resetCallId) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1572
1770
|
}
|
|
1573
1771
|
}
|
|
1574
1772
|
}
|
|
@@ -1592,11 +1790,15 @@ function createFormControl(props = {}) {
|
|
|
1592
1790
|
let validationResult;
|
|
1593
1791
|
const fieldNames = convertToArrayPayload(name);
|
|
1594
1792
|
if (_options.resolver) {
|
|
1793
|
+
const resetCallId = _resetCallId;
|
|
1595
1794
|
const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
|
|
1596
1795
|
isValid = isEmptyObject(errors);
|
|
1597
1796
|
validationResult = name
|
|
1598
1797
|
? !fieldNames.some((name) => get(errors, name))
|
|
1599
1798
|
: isValid;
|
|
1799
|
+
if (resetCallId !== _resetCallId) {
|
|
1800
|
+
return validationResult;
|
|
1801
|
+
}
|
|
1600
1802
|
}
|
|
1601
1803
|
else if (name) {
|
|
1602
1804
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
@@ -1615,13 +1817,32 @@ function createFormControl(props = {}) {
|
|
|
1615
1817
|
eventType: EVENTS.TRIGGER,
|
|
1616
1818
|
});
|
|
1617
1819
|
}
|
|
1820
|
+
if (options.delayError && _options.delayError && isString(name)) {
|
|
1821
|
+
const error = get(_formState.errors, name);
|
|
1822
|
+
if (error) {
|
|
1823
|
+
unset(_formState.errors, name);
|
|
1824
|
+
delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
|
|
1825
|
+
delayErrorCallbacks[name](_options.delayError);
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
cancelDelayedError(name);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
if (options.shouldTouch) {
|
|
1832
|
+
for (const fieldName of name ? fieldNames : _names.mount) {
|
|
1833
|
+
!_names.array.has(fieldName) &&
|
|
1834
|
+
set(_formState.touchedFields, fieldName, true);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1618
1837
|
_subjects.state.next({
|
|
1619
1838
|
...(!isString(name) ||
|
|
1620
|
-
((
|
|
1621
|
-
isValid !== _formState.isValid)
|
|
1839
|
+
(_isTracked('isValid') && isValid !== _formState.isValid)
|
|
1622
1840
|
? {}
|
|
1623
1841
|
: { name }),
|
|
1624
1842
|
...(_options.resolver || !name ? { isValid } : {}),
|
|
1843
|
+
...(options.shouldTouch && _isTracked('touchedFields')
|
|
1844
|
+
? { touchedFields: _formState.touchedFields }
|
|
1845
|
+
: {}),
|
|
1625
1846
|
errors: _formState.errors,
|
|
1626
1847
|
});
|
|
1627
1848
|
options.shouldFocus &&
|
|
@@ -1642,18 +1863,28 @@ function createFormControl(props = {}) {
|
|
|
1642
1863
|
? get(values, fieldNames)
|
|
1643
1864
|
: fieldNames.map((name) => get(values, name));
|
|
1644
1865
|
};
|
|
1645
|
-
const
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1866
|
+
const getErrors = (fieldNames) => isUndefined(fieldNames)
|
|
1867
|
+
? { ..._formState.errors }
|
|
1868
|
+
: isString(fieldNames)
|
|
1869
|
+
? get(_formState.errors, fieldNames)
|
|
1870
|
+
: fieldNames.map((name) => get(_formState.errors, name));
|
|
1871
|
+
const getFieldState = (name, formState) => {
|
|
1872
|
+
const targetFormState = formState || _formState;
|
|
1873
|
+
const error = get(targetFormState.errors, name);
|
|
1874
|
+
return {
|
|
1875
|
+
invalid: !!error,
|
|
1876
|
+
isDirty: !!get(targetFormState.dirtyFields, name),
|
|
1877
|
+
error,
|
|
1878
|
+
isValidating: !!get(targetFormState.validatingFields, name),
|
|
1879
|
+
isTouched: !!get(targetFormState.touchedFields, name),
|
|
1880
|
+
};
|
|
1881
|
+
};
|
|
1652
1882
|
const clearErrors = (name) => {
|
|
1653
1883
|
const names = name ? convertToArrayPayload(name) : undefined;
|
|
1654
|
-
names?.forEach((inputName) => unset(_formState.errors, inputName));
|
|
1655
1884
|
if (names) {
|
|
1656
1885
|
names.forEach((inputName) => {
|
|
1886
|
+
cancelDelayedErrorTree(inputName);
|
|
1887
|
+
unset(_formState.errors, inputName);
|
|
1657
1888
|
_subjects.state.next({
|
|
1658
1889
|
name: inputName,
|
|
1659
1890
|
errors: _formState.errors,
|
|
@@ -1661,15 +1892,18 @@ function createFormControl(props = {}) {
|
|
|
1661
1892
|
});
|
|
1662
1893
|
}
|
|
1663
1894
|
else {
|
|
1895
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1896
|
+
_formState.errors = {};
|
|
1664
1897
|
_subjects.state.next({
|
|
1665
|
-
errors:
|
|
1898
|
+
errors: _formState.errors,
|
|
1666
1899
|
});
|
|
1667
1900
|
}
|
|
1668
1901
|
};
|
|
1669
1902
|
const setError = (name, error, options) => {
|
|
1903
|
+
cancelDelayedErrorTree(name);
|
|
1670
1904
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
1671
1905
|
const currentError = get(_formState.errors, name) || {};
|
|
1672
|
-
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
1906
|
+
const { ref: currentRef, message, type, types, ...restOfErrorTree } = currentError;
|
|
1673
1907
|
set(_formState.errors, name, {
|
|
1674
1908
|
...restOfErrorTree,
|
|
1675
1909
|
...error,
|
|
@@ -1753,11 +1987,15 @@ function createFormControl(props = {}) {
|
|
|
1753
1987
|
for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
|
|
1754
1988
|
_names.mount.delete(fieldName);
|
|
1755
1989
|
_names.array.delete(fieldName);
|
|
1990
|
+
_names.disabled.delete(fieldName);
|
|
1756
1991
|
if (!options.keepValue) {
|
|
1757
1992
|
unset(_fields, fieldName);
|
|
1758
1993
|
unset(_formValues, fieldName);
|
|
1759
1994
|
}
|
|
1760
|
-
!options.keepError
|
|
1995
|
+
if (!options.keepError) {
|
|
1996
|
+
cancelDelayedErrorTree(fieldName);
|
|
1997
|
+
unset(_formState.errors, fieldName);
|
|
1998
|
+
}
|
|
1761
1999
|
!options.keepDirty && unset(_formState.dirtyFields, fieldName);
|
|
1762
2000
|
!options.keepTouched && unset(_formState.touchedFields, fieldName);
|
|
1763
2001
|
!options.keepIsValidating &&
|
|
@@ -1766,12 +2004,16 @@ function createFormControl(props = {}) {
|
|
|
1766
2004
|
!options.keepDefaultValue &&
|
|
1767
2005
|
unset(_defaultValues, fieldName);
|
|
1768
2006
|
}
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
2007
|
+
_valuesSubscriberCount &&
|
|
2008
|
+
_subjects.state.next({
|
|
2009
|
+
values: cloneObject(_formValues),
|
|
2010
|
+
});
|
|
1772
2011
|
_subjects.state.next({
|
|
1773
2012
|
..._formState,
|
|
1774
|
-
...(
|
|
2013
|
+
...(options.keepDirty ? {} : { isDirty: _getDirty() }),
|
|
2014
|
+
...(options.keepIsValidating
|
|
2015
|
+
? {}
|
|
2016
|
+
: { isValidating: !isEmptyObject(_formState.validatingFields) }),
|
|
1775
2017
|
});
|
|
1776
2018
|
!options.keepIsValid && _setValid();
|
|
1777
2019
|
};
|
|
@@ -1800,6 +2042,14 @@ function createFormControl(props = {}) {
|
|
|
1800
2042
|
},
|
|
1801
2043
|
});
|
|
1802
2044
|
_names.mount.add(name);
|
|
2045
|
+
if (field && field._f) {
|
|
2046
|
+
const nextField = get(_fields, name);
|
|
2047
|
+
for (const rule of REGISTER_VALIDATION_RULES) {
|
|
2048
|
+
if (!(rule in options)) {
|
|
2049
|
+
delete nextField._f[rule];
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
1803
2053
|
if (field && !shouldRevalidateRemount) {
|
|
1804
2054
|
_setDisabledField({
|
|
1805
2055
|
disabled: isBoolean(options.disabled)
|
|
@@ -1846,20 +2096,23 @@ function createFormControl(props = {}) {
|
|
|
1846
2096
|
: fieldRef === field._f.ref) {
|
|
1847
2097
|
return;
|
|
1848
2098
|
}
|
|
2099
|
+
const newField = {
|
|
2100
|
+
...field._f,
|
|
2101
|
+
};
|
|
2102
|
+
if (radioOrCheckbox) {
|
|
2103
|
+
newField.refs = [
|
|
2104
|
+
...refs.filter(live),
|
|
2105
|
+
fieldRef,
|
|
2106
|
+
...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
|
|
2107
|
+
];
|
|
2108
|
+
newField.ref = { type: fieldRef.type, name };
|
|
2109
|
+
}
|
|
2110
|
+
else {
|
|
2111
|
+
newField.ref = fieldRef;
|
|
2112
|
+
delete newField.refs;
|
|
2113
|
+
}
|
|
1849
2114
|
set(_fields, name, {
|
|
1850
|
-
_f:
|
|
1851
|
-
...field._f,
|
|
1852
|
-
...(radioOrCheckbox
|
|
1853
|
-
? {
|
|
1854
|
-
refs: [
|
|
1855
|
-
...refs.filter(live),
|
|
1856
|
-
fieldRef,
|
|
1857
|
-
...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
|
|
1858
|
-
],
|
|
1859
|
-
ref: { type: fieldRef.type, name },
|
|
1860
|
-
}
|
|
1861
|
-
: { ref: fieldRef }),
|
|
1862
|
-
},
|
|
2115
|
+
_f: newField,
|
|
1863
2116
|
});
|
|
1864
2117
|
updateValidAndValue(name, false, undefined, fieldRef);
|
|
1865
2118
|
}
|
|
@@ -1891,10 +2144,11 @@ function createFormControl(props = {}) {
|
|
|
1891
2144
|
});
|
|
1892
2145
|
}
|
|
1893
2146
|
}
|
|
1894
|
-
}, 0
|
|
2147
|
+
}, 0);
|
|
1895
2148
|
}
|
|
1896
2149
|
};
|
|
1897
2150
|
const handleSubmit = (onValid, onInvalid) => async (e) => {
|
|
2151
|
+
let result = undefined;
|
|
1898
2152
|
let onValidError = undefined;
|
|
1899
2153
|
if (e) {
|
|
1900
2154
|
e.preventDefault && e.preventDefault();
|
|
@@ -1906,29 +2160,38 @@ function createFormControl(props = {}) {
|
|
|
1906
2160
|
isSubmitting: true,
|
|
1907
2161
|
});
|
|
1908
2162
|
if (_options.resolver) {
|
|
2163
|
+
const resetCallId = _resetCallId;
|
|
1909
2164
|
const { errors, values } = await _runSchema();
|
|
2165
|
+
if (resetCallId !== _resetCallId) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
1910
2168
|
_updateIsValidating();
|
|
2169
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1911
2170
|
_formState.errors = errors;
|
|
1912
2171
|
fieldValues = cloneObject(values);
|
|
1913
2172
|
}
|
|
1914
2173
|
else {
|
|
2174
|
+
const resetCallId = _resetCallId;
|
|
1915
2175
|
await executeBuiltInValidation({
|
|
1916
2176
|
fields: _fields,
|
|
1917
2177
|
eventType: EVENTS.SUBMIT,
|
|
1918
2178
|
});
|
|
2179
|
+
if (resetCallId !== _resetCallId) {
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
1919
2183
|
}
|
|
1920
2184
|
if (_names.disabled.size) {
|
|
1921
2185
|
for (const name of _names.disabled) {
|
|
1922
2186
|
unset(fieldValues, name);
|
|
1923
2187
|
}
|
|
1924
2188
|
}
|
|
1925
|
-
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
1926
2189
|
if (isEmptyObject(_formState.errors)) {
|
|
1927
2190
|
_subjects.state.next({
|
|
1928
2191
|
errors: {},
|
|
1929
2192
|
});
|
|
1930
2193
|
try {
|
|
1931
|
-
await onValid(fieldValues, e);
|
|
2194
|
+
result = await onValid(fieldValues, e);
|
|
1932
2195
|
}
|
|
1933
2196
|
catch (error) {
|
|
1934
2197
|
onValidError = error;
|
|
@@ -1951,9 +2214,11 @@ function createFormControl(props = {}) {
|
|
|
1951
2214
|
if (onValidError) {
|
|
1952
2215
|
throw onValidError;
|
|
1953
2216
|
}
|
|
2217
|
+
return result;
|
|
1954
2218
|
};
|
|
1955
2219
|
const resetField = (name, options = {}) => {
|
|
1956
2220
|
if (get(_fields, name)) {
|
|
2221
|
+
unset(_formState.validatingFields, name);
|
|
1957
2222
|
if (isUndefined(options.defaultValue)) {
|
|
1958
2223
|
setValue(name, cloneObject(get(_defaultValues, name)));
|
|
1959
2224
|
}
|
|
@@ -1971,17 +2236,24 @@ function createFormControl(props = {}) {
|
|
|
1971
2236
|
: _getDirty();
|
|
1972
2237
|
}
|
|
1973
2238
|
if (!options.keepError) {
|
|
2239
|
+
cancelDelayedErrorTree(name);
|
|
1974
2240
|
unset(_formState.errors, name);
|
|
1975
|
-
|
|
2241
|
+
_setValid();
|
|
1976
2242
|
}
|
|
1977
|
-
_subjects.state.next({
|
|
2243
|
+
_subjects.state.next({
|
|
2244
|
+
..._formState,
|
|
2245
|
+
isValidating: !isEmptyObject(_formState.validatingFields),
|
|
2246
|
+
});
|
|
1978
2247
|
}
|
|
1979
2248
|
};
|
|
1980
2249
|
const _reset = (formValues, keepStateOptions = {}) => {
|
|
2250
|
+
_resetCallId++;
|
|
1981
2251
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
1982
2252
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
1983
2253
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
1984
2254
|
const values = cloneUpdatedValues;
|
|
2255
|
+
const fieldRefs = _fields;
|
|
2256
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1985
2257
|
if (!keepStateOptions.keepDefaultValues) {
|
|
1986
2258
|
_defaultValues = updatedValues;
|
|
1987
2259
|
}
|
|
@@ -1989,9 +2261,9 @@ function createFormControl(props = {}) {
|
|
|
1989
2261
|
if (keepStateOptions.keepDirtyValues) {
|
|
1990
2262
|
const fieldsToCheck = new Set([
|
|
1991
2263
|
..._names.mount,
|
|
1992
|
-
...
|
|
2264
|
+
...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
|
|
1993
2265
|
]);
|
|
1994
|
-
for (const fieldName of
|
|
2266
|
+
for (const fieldName of fieldsToCheck) {
|
|
1995
2267
|
const isDirty = get(_formState.dirtyFields, fieldName);
|
|
1996
2268
|
const existingValue = get(_formValues, fieldName);
|
|
1997
2269
|
const newValue = get(values, fieldName);
|
|
@@ -2070,6 +2342,7 @@ function createFormControl(props = {}) {
|
|
|
2070
2342
|
_state.watch = !!_options.shouldUnregister;
|
|
2071
2343
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
2072
2344
|
_state.action = false;
|
|
2345
|
+
_state.actionArrayLengths.clear();
|
|
2073
2346
|
if (!keepStateOptions.keepErrors) {
|
|
2074
2347
|
_formState.errors = {};
|
|
2075
2348
|
}
|
|
@@ -2092,16 +2365,22 @@ function createFormControl(props = {}) {
|
|
|
2092
2365
|
? {}
|
|
2093
2366
|
: keepStateOptions.keepDirtyValues
|
|
2094
2367
|
? keepStateOptions.keepDefaultValues && _formValues
|
|
2095
|
-
? getDirtyFields(_defaultValues, _formValues)
|
|
2368
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
2096
2369
|
: _formState.dirtyFields
|
|
2097
2370
|
: keepStateOptions.keepDefaultValues && formValues
|
|
2098
|
-
? getDirtyFields(_defaultValues, formValues)
|
|
2371
|
+
? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
|
|
2099
2372
|
: keepStateOptions.keepDirty
|
|
2100
2373
|
? _formState.dirtyFields
|
|
2101
|
-
:
|
|
2374
|
+
: keepStateOptions.keepValues
|
|
2375
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
2376
|
+
: {},
|
|
2102
2377
|
touchedFields: keepStateOptions.keepTouched
|
|
2103
2378
|
? _formState.touchedFields
|
|
2104
2379
|
: {},
|
|
2380
|
+
...(!keepStateOptions.keepIsValidating &&
|
|
2381
|
+
(_formState.isValidating || !isEmptyObject(_formState.validatingFields))
|
|
2382
|
+
? { validatingFields: {}, isValidating: false }
|
|
2383
|
+
: null),
|
|
2105
2384
|
errors: keepStateOptions.keepErrors ? _formState.errors : {},
|
|
2106
2385
|
isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
|
|
2107
2386
|
? _formState.isSubmitSuccessful
|
|
@@ -2142,6 +2421,7 @@ function createFormControl(props = {}) {
|
|
|
2142
2421
|
...formState,
|
|
2143
2422
|
};
|
|
2144
2423
|
};
|
|
2424
|
+
_subjects.state.subscribe({ next: _setFormState });
|
|
2145
2425
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
2146
2426
|
_options.defaultValues().then((values) => {
|
|
2147
2427
|
reset(values, _options.resetOptions);
|
|
@@ -2152,7 +2432,7 @@ function createFormControl(props = {}) {
|
|
|
2152
2432
|
const resetDefaultValues = (values, options = {}) => {
|
|
2153
2433
|
_defaultValues = cloneObject(values);
|
|
2154
2434
|
if (!options.keepDirty) {
|
|
2155
|
-
const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
2435
|
+
const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
2156
2436
|
_formState.dirtyFields = newDirtyFields;
|
|
2157
2437
|
_formState.isDirty = !isEmptyObject(newDirtyFields);
|
|
2158
2438
|
}
|
|
@@ -2222,6 +2502,8 @@ function createFormControl(props = {}) {
|
|
|
2222
2502
|
};
|
|
2223
2503
|
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2224
2504
|
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2505
|
+
shouldDisplayAllAssociatedErrors =
|
|
2506
|
+
_options.criteriaMode === VALIDATION_MODE.all;
|
|
2225
2507
|
},
|
|
2226
2508
|
},
|
|
2227
2509
|
subscribe,
|
|
@@ -2232,6 +2514,7 @@ function createFormControl(props = {}) {
|
|
|
2232
2514
|
setValue,
|
|
2233
2515
|
setValues,
|
|
2234
2516
|
getValues,
|
|
2517
|
+
getErrors,
|
|
2235
2518
|
reset,
|
|
2236
2519
|
resetField,
|
|
2237
2520
|
resetDefaultValues,
|