react-hook-form 8.0.0-beta.2 → 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 -20
- 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 +37 -0
- package/dist/fieldArray.d.ts.map +1 -0
- 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 +2952 -2347
- 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/{getFieldArrayParentNames.d.ts → getFieldArrayItemNames.d.ts} +1 -1
- 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/hasPromiseValidation.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/index.d.ts +2 -3
- package/dist/logic/index.d.ts.map +1 -1
- package/dist/logic/isNameInFieldArray.d.ts +4 -0
- package/dist/logic/isNameInFieldArray.d.ts.map +1 -0
- package/dist/logic/isWatched.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/skipValidation.d.ts +1 -4
- package/dist/logic/skipValidation.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/updateFieldArrayRootError.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +767 -340
- 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/fieldArray.d.ts +25 -1
- package/dist/types/fieldArray.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 +152 -57
- 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/useIsomorphicLayoutEffect.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/get.d.ts.map +1 -1
- package/dist/utils/has.d.ts +3 -0
- package/dist/utils/has.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/isKey.d.ts.map +1 -1
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/set.d.ts.map +1 -1
- package/dist/utils/stringToPath.d.ts.map +1 -1
- package/dist/utils/unset.d.ts.map +1 -1
- 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 +30 -27
- package/dist/formStateSubscribe.d.ts +0 -7
- package/dist/formStateSubscribe.d.ts.map +0 -1
- package/dist/logic/getFieldArrayParentNames.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
|
+
];
|
|
34
43
|
const FORM_ERROR_TYPE = 'form';
|
|
35
44
|
const ROOT_ERROR_TYPE = 'root';
|
|
36
|
-
|
|
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
|
-
};
|
|
45
|
+
const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
|
|
51
46
|
|
|
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,9 +105,25 @@ 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);
|
|
126
|
+
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
112
127
|
if (object1 === object2) {
|
|
113
128
|
return true;
|
|
114
129
|
}
|
|
@@ -123,11 +138,25 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
|
|
|
123
138
|
if (keys1.length !== keys2.length) {
|
|
124
139
|
return false;
|
|
125
140
|
}
|
|
126
|
-
if (
|
|
141
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
142
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
143
|
+
return Object.is(object1, object2);
|
|
144
|
+
}
|
|
145
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const visitedPairs = visited.get(object1);
|
|
149
|
+
if (visitedPairs && visitedPairs.has(object2)) {
|
|
127
150
|
return true;
|
|
128
151
|
}
|
|
129
|
-
|
|
130
|
-
|
|
152
|
+
if (visitedPairs) {
|
|
153
|
+
visitedPairs.add(object2);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
const ws = new WeakSet();
|
|
157
|
+
ws.add(object2);
|
|
158
|
+
visited.set(object1, ws);
|
|
159
|
+
}
|
|
131
160
|
for (const key of keys1) {
|
|
132
161
|
const val1 = object1[key];
|
|
133
162
|
if (!(key in object2)) {
|
|
@@ -148,16 +177,15 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
|
|
|
148
177
|
}
|
|
149
178
|
|
|
150
179
|
function extractFormValues(fieldsState, formValues) {
|
|
151
|
-
const values = {};
|
|
180
|
+
const values = (Array.isArray(fieldsState) ? [] : {});
|
|
152
181
|
for (const key in fieldsState) {
|
|
153
182
|
if (fieldsState.hasOwnProperty(key)) {
|
|
154
183
|
const fieldState = fieldsState[key];
|
|
155
184
|
const fieldValue = formValues[key];
|
|
156
|
-
if (fieldState &&
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
185
|
+
if (fieldState &&
|
|
186
|
+
(isObject(fieldState) || Array.isArray(fieldState)) &&
|
|
187
|
+
fieldValue) {
|
|
188
|
+
values[key] = extractFormValues(fieldState, fieldValue);
|
|
161
189
|
}
|
|
162
190
|
else if (fieldsState[key]) {
|
|
163
191
|
values[key] = fieldValue;
|
|
@@ -167,17 +195,22 @@ function extractFormValues(fieldsState, formValues) {
|
|
|
167
195
|
return values;
|
|
168
196
|
}
|
|
169
197
|
|
|
170
|
-
|
|
198
|
+
const IS_KEY_RE = /^\w*$/;
|
|
199
|
+
var isKey = (value) => IS_KEY_RE.test(value);
|
|
171
200
|
|
|
172
201
|
var isUndefined = (val) => val === undefined;
|
|
173
202
|
|
|
174
|
-
|
|
203
|
+
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
204
|
+
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
175
205
|
|
|
176
206
|
var get = (object, path, defaultValue) => {
|
|
177
207
|
if (!path || !isObject(object)) {
|
|
178
208
|
return defaultValue;
|
|
179
209
|
}
|
|
180
210
|
const paths = isKey(path) ? [path] : stringToPath(path);
|
|
211
|
+
if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
|
|
212
|
+
return defaultValue;
|
|
213
|
+
}
|
|
181
214
|
const result = paths.reduce((result, key) => {
|
|
182
215
|
return isNullOrUndefined(result) ? undefined : result[key];
|
|
183
216
|
}, object);
|
|
@@ -188,6 +221,24 @@ var get = (object, path, defaultValue) => {
|
|
|
188
221
|
: result;
|
|
189
222
|
};
|
|
190
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
|
+
|
|
191
242
|
var isBoolean = (value) => typeof value === 'boolean';
|
|
192
243
|
|
|
193
244
|
var isCheckBoxInput = (element) => element.type === 'checkbox';
|
|
@@ -234,7 +285,7 @@ var set = (object, path, value) => {
|
|
|
234
285
|
? []
|
|
235
286
|
: {};
|
|
236
287
|
}
|
|
237
|
-
if (key
|
|
288
|
+
if (PROTOTYPE_KEYWORDS.includes(key)) {
|
|
238
289
|
return;
|
|
239
290
|
}
|
|
240
291
|
object[key] = newValue;
|
|
@@ -243,7 +294,7 @@ var set = (object, path, value) => {
|
|
|
243
294
|
};
|
|
244
295
|
|
|
245
296
|
function baseGet(object, updatePath) {
|
|
246
|
-
const length = updatePath.
|
|
297
|
+
const length = updatePath.length - 1;
|
|
247
298
|
let index = 0;
|
|
248
299
|
while (index < length) {
|
|
249
300
|
if (isNullOrUndefined(object)) {
|
|
@@ -273,6 +324,9 @@ function unset(object, path) {
|
|
|
273
324
|
: isKey(path)
|
|
274
325
|
? [path]
|
|
275
326
|
: stringToPath(path);
|
|
327
|
+
if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
|
|
328
|
+
return object;
|
|
329
|
+
}
|
|
276
330
|
const childObject = paths.length === 1 ? object : baseGet(object, paths);
|
|
277
331
|
const index = paths.length - 1;
|
|
278
332
|
const key = paths[index];
|
|
@@ -287,6 +341,24 @@ function unset(object, path) {
|
|
|
287
341
|
return object;
|
|
288
342
|
}
|
|
289
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
|
+
|
|
290
362
|
var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
|
|
291
363
|
if (isString(names)) {
|
|
292
364
|
isGlobal && _names.watch.add(names);
|
|
@@ -294,7 +366,7 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
294
366
|
}
|
|
295
367
|
if (Array.isArray(names)) {
|
|
296
368
|
return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
|
|
297
|
-
get(formValues, fieldName)));
|
|
369
|
+
get(formValues, fieldName, get(defaultValue, fieldName))));
|
|
298
370
|
}
|
|
299
371
|
isGlobal && (_names.watchAll = true);
|
|
300
372
|
return formValues;
|
|
@@ -312,12 +384,33 @@ var objectHasFunction = (data) => {
|
|
|
312
384
|
function isTraversable(value) {
|
|
313
385
|
return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
|
|
314
386
|
}
|
|
315
|
-
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) {
|
|
316
404
|
for (const key in data) {
|
|
317
405
|
const value = data[key];
|
|
318
|
-
|
|
406
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
407
|
+
if (isTraversable(value) &&
|
|
408
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
319
409
|
fields[key] = Array.isArray(value) ? [] : {};
|
|
320
|
-
markFieldsDirty(value, fields[key]);
|
|
410
|
+
markFieldsDirty(value, fields[key], fieldRef);
|
|
411
|
+
if (isEmptyDirtyContainer(fields[key])) {
|
|
412
|
+
clearDirtyField(fields, key);
|
|
413
|
+
}
|
|
321
414
|
}
|
|
322
415
|
else if (!isUndefined(value)) {
|
|
323
416
|
fields[key] = true;
|
|
@@ -325,63 +418,51 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
325
418
|
}
|
|
326
419
|
return fields;
|
|
327
420
|
}
|
|
328
|
-
function
|
|
329
|
-
if (value === false) {
|
|
330
|
-
return undefined;
|
|
331
|
-
}
|
|
332
|
-
if (value === true) {
|
|
333
|
-
return true;
|
|
334
|
-
}
|
|
335
|
-
if (Array.isArray(value)) {
|
|
336
|
-
const result = value.map((value) => pruneDirtyFields(value));
|
|
337
|
-
return (result.some((value) => value !== undefined) ? result : undefined);
|
|
338
|
-
}
|
|
339
|
-
if (isObject(value)) {
|
|
340
|
-
const result = {};
|
|
341
|
-
for (const key in value) {
|
|
342
|
-
const pruned = pruneDirtyFields(value[key]);
|
|
343
|
-
if (!isUndefined(pruned)) {
|
|
344
|
-
result[key] = pruned;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return (Object.keys(result).length ? result : undefined);
|
|
348
|
-
}
|
|
349
|
-
return undefined;
|
|
350
|
-
}
|
|
351
|
-
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
421
|
+
function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
|
|
352
422
|
if (!dirtyFieldsFromValues) {
|
|
353
|
-
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
423
|
+
dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
|
|
354
424
|
}
|
|
355
425
|
for (const key in data) {
|
|
356
426
|
const value = data[key];
|
|
357
|
-
|
|
427
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
428
|
+
if (isTraversable(value) &&
|
|
429
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
358
430
|
if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
|
|
359
|
-
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
|
|
431
|
+
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
|
|
360
432
|
}
|
|
361
433
|
else {
|
|
362
|
-
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
|
|
434
|
+
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
|
|
363
435
|
}
|
|
436
|
+
if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
|
|
437
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
else if (deepEqual(value, formValues[key])) {
|
|
441
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
364
442
|
}
|
|
365
443
|
else {
|
|
366
|
-
|
|
367
|
-
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
444
|
+
dirtyFieldsFromValues[key] = true;
|
|
368
445
|
}
|
|
369
446
|
}
|
|
370
|
-
return
|
|
447
|
+
return dirtyFieldsFromValues;
|
|
371
448
|
}
|
|
372
449
|
|
|
373
450
|
var getEventValue = (event) => isObject(event) && event.target
|
|
374
451
|
? isCheckBoxInput(event.target)
|
|
375
452
|
? event.target.checked
|
|
376
|
-
: event.target
|
|
453
|
+
: isFileInput(event.target)
|
|
454
|
+
? event.target.files
|
|
455
|
+
: event.target.value
|
|
377
456
|
: event;
|
|
378
457
|
|
|
379
|
-
var
|
|
380
|
-
const
|
|
458
|
+
var getFieldArrayItemNames = (names, name) => {
|
|
459
|
+
const segments = name.split('.');
|
|
381
460
|
const matches = [];
|
|
382
|
-
let prefix =
|
|
383
|
-
for (let i = 1; i <
|
|
384
|
-
!isNaN(+
|
|
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
|
+
}
|
|
385
466
|
}
|
|
386
467
|
return matches;
|
|
387
468
|
};
|
|
@@ -392,23 +473,25 @@ const defaultResult = {
|
|
|
392
473
|
};
|
|
393
474
|
const validResult = { value: true, isValid: true };
|
|
394
475
|
var getCheckboxValue = (options) => {
|
|
395
|
-
if (Array.isArray(options)) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
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 };
|
|
412
495
|
};
|
|
413
496
|
|
|
414
497
|
var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
|
|
@@ -452,7 +535,7 @@ function getFieldValue(_f) {
|
|
|
452
535
|
if (isCheckBoxInput(ref)) {
|
|
453
536
|
return getCheckboxValue(_f.refs).value;
|
|
454
537
|
}
|
|
455
|
-
return getFieldValueAs(
|
|
538
|
+
return getFieldValueAs(ref.value, _f);
|
|
456
539
|
}
|
|
457
540
|
|
|
458
541
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
@@ -490,49 +573,73 @@ var getValidationModes = (mode) => ({
|
|
|
490
573
|
});
|
|
491
574
|
|
|
492
575
|
const ASYNC_FUNCTION = 'AsyncFunction';
|
|
493
|
-
var hasPromiseValidation = (fieldReference) =>
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
576
|
+
var hasPromiseValidation = (fieldReference) => {
|
|
577
|
+
if (!fieldReference || !fieldReference.validate)
|
|
578
|
+
return false;
|
|
579
|
+
if (isFunction(fieldReference.validate)) {
|
|
580
|
+
return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
|
|
581
|
+
}
|
|
582
|
+
if (isObject(fieldReference.validate)) {
|
|
583
|
+
for (const key in fieldReference.validate) {
|
|
584
|
+
if (fieldReference.validate[key].constructor
|
|
585
|
+
.name === ASYNC_FUNCTION) {
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
};
|
|
499
592
|
|
|
500
593
|
var hasValidation = (options) => options.mount &&
|
|
501
594
|
(options.required ||
|
|
502
|
-
options.
|
|
503
|
-
options.
|
|
504
|
-
options.
|
|
505
|
-
options.
|
|
595
|
+
(!isUndefined(options.required) && options.required !== false) ||
|
|
596
|
+
!isUndefined(options.min) ||
|
|
597
|
+
!isUndefined(options.max) ||
|
|
598
|
+
!isUndefined(options.maxLength) ||
|
|
599
|
+
!isUndefined(options.minLength) ||
|
|
506
600
|
options.pattern ||
|
|
507
601
|
options.validate);
|
|
508
602
|
|
|
509
|
-
var
|
|
510
|
-
(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
603
|
+
var isNameInFieldArray = (names, name) => name
|
|
604
|
+
.split('.')
|
|
605
|
+
.some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
|
|
606
|
+
|
|
607
|
+
var isWatched = (name, _names, isBlurEvent) => {
|
|
608
|
+
if (isBlurEvent)
|
|
609
|
+
return false;
|
|
610
|
+
if (_names.watchAll || _names.watch.has(name))
|
|
611
|
+
return true;
|
|
612
|
+
for (const watchName of _names.watch) {
|
|
613
|
+
if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
return false;
|
|
617
|
+
};
|
|
514
618
|
|
|
515
|
-
const iterateFieldsByAction = (fields, action, fieldsNames
|
|
619
|
+
const iterateFieldsByAction = (fields, action, fieldsNames) => {
|
|
516
620
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
517
|
-
|
|
621
|
+
if (key === '_f') {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
const field = fieldsNames ? get(fields, key) : fields[key];
|
|
518
625
|
if (field) {
|
|
519
|
-
const { _f
|
|
626
|
+
const { _f } = field;
|
|
520
627
|
if (_f) {
|
|
521
|
-
if (_f.refs && _f.refs[0] && action(_f.refs[0],
|
|
628
|
+
if (_f.refs && _f.refs[0] && action(_f.refs[0], _f.name)) {
|
|
522
629
|
return true;
|
|
523
630
|
}
|
|
524
|
-
else if (_f.ref && action(_f.ref, _f.name)
|
|
631
|
+
else if (_f.ref && action(_f.ref, _f.name)) {
|
|
525
632
|
return true;
|
|
526
633
|
}
|
|
527
634
|
else {
|
|
528
|
-
if (iterateFieldsByAction(
|
|
529
|
-
|
|
635
|
+
if (iterateFieldsByAction(field, action)) {
|
|
636
|
+
return true;
|
|
530
637
|
}
|
|
531
638
|
}
|
|
532
639
|
}
|
|
533
|
-
else if (isObject(
|
|
534
|
-
if (iterateFieldsByAction(
|
|
535
|
-
|
|
640
|
+
else if (isObject(field) || Array.isArray(field)) {
|
|
641
|
+
if (iterateFieldsByAction(field, action)) {
|
|
642
|
+
return true;
|
|
536
643
|
}
|
|
537
644
|
}
|
|
538
645
|
}
|
|
@@ -542,7 +649,7 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
|
542
649
|
|
|
543
650
|
function schemaErrorLookup(errors, _fields, name) {
|
|
544
651
|
const error = get(errors, name);
|
|
545
|
-
if (error ||
|
|
652
|
+
if (error?.type || error?.message || Array.isArray(error)) {
|
|
546
653
|
return {
|
|
547
654
|
error,
|
|
548
655
|
name,
|
|
@@ -577,11 +684,10 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
577
684
|
|
|
578
685
|
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
579
686
|
updateFormState(formStateData);
|
|
580
|
-
const
|
|
581
|
-
return (
|
|
582
|
-
(isRoot &&
|
|
583
|
-
|
|
584
|
-
Object.keys(formState).find((key) => _proxyFormState[key] ===
|
|
687
|
+
const keys = Object.keys(formStateData).filter((key) => key !== 'name');
|
|
688
|
+
return (!keys.length ||
|
|
689
|
+
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
690
|
+
keys.find((key) => _proxyFormState[key] ===
|
|
585
691
|
(!isRoot || VALIDATION_MODE.all)));
|
|
586
692
|
};
|
|
587
693
|
|
|
@@ -590,7 +696,7 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
|
|
|
590
696
|
name === signalName ||
|
|
591
697
|
convertToArrayPayload(name).some((currentName) => currentName &&
|
|
592
698
|
(exact
|
|
593
|
-
? currentName === signalName
|
|
699
|
+
? currentName === signalName || currentName.startsWith(signalName + '.')
|
|
594
700
|
: currentName.startsWith(signalName) ||
|
|
595
701
|
signalName.startsWith(currentName)));
|
|
596
702
|
|
|
@@ -610,10 +716,16 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
610
716
|
return true;
|
|
611
717
|
};
|
|
612
718
|
|
|
613
|
-
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
|
+
};
|
|
614
725
|
|
|
615
726
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
616
|
-
const
|
|
727
|
+
const existingErrors = get(errors, name);
|
|
728
|
+
const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
|
|
617
729
|
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
618
730
|
set(errors, name, fieldArrayErrors);
|
|
619
731
|
return errors;
|
|
@@ -639,7 +751,7 @@ var getValueAndMessage = (validationData) => isObject(validationData) && !isRege
|
|
|
639
751
|
};
|
|
640
752
|
|
|
641
753
|
var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
|
|
642
|
-
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;
|
|
643
755
|
const inputValue = get(formValues, name);
|
|
644
756
|
if (!mount || disabledFieldNames.has(name)) {
|
|
645
757
|
return {};
|
|
@@ -647,7 +759,14 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
647
759
|
const inputRef = refs ? refs[0] : ref;
|
|
648
760
|
const setCustomValidity = (message) => {
|
|
649
761
|
if (shouldUseNativeValidation && inputRef.reportValidity) {
|
|
650
|
-
|
|
762
|
+
const validityMessage = isBoolean(message) ? '' : message || '';
|
|
763
|
+
if (refs) {
|
|
764
|
+
refs.forEach((ref) => isFunction(ref.setCustomValidity) &&
|
|
765
|
+
ref.setCustomValidity(validityMessage));
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
inputRef.setCustomValidity(validityMessage);
|
|
769
|
+
}
|
|
651
770
|
inputRef.reportValidity();
|
|
652
771
|
}
|
|
653
772
|
};
|
|
@@ -658,10 +777,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
658
777
|
const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
|
|
659
778
|
isUndefined(ref.value) &&
|
|
660
779
|
isUndefined(inputValue)) ||
|
|
661
|
-
(isHTMLElement(ref) && ref.value === '') ||
|
|
780
|
+
(isHTMLElement(ref) && ref.value === '' && !_c) ||
|
|
662
781
|
inputValue === '' ||
|
|
663
|
-
(Array.isArray(inputValue) && !inputValue.length)
|
|
664
|
-
(valueAsNumber && typeof inputValue === 'number' && isNaN(inputValue));
|
|
782
|
+
(Array.isArray(inputValue) && !inputValue.length);
|
|
665
783
|
const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
|
|
666
784
|
const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
|
|
667
785
|
const message = exceedMax ? maxLengthMessage : minLengthMessage;
|
|
@@ -700,7 +818,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
700
818
|
let exceedMin;
|
|
701
819
|
const maxOutput = getValueAndMessage(max);
|
|
702
820
|
const minOutput = getValueAndMessage(min);
|
|
703
|
-
if (!isNullOrUndefined(inputValue) &&
|
|
821
|
+
if (!isNullOrUndefined(inputValue) &&
|
|
822
|
+
!isDateObject(inputValue) &&
|
|
823
|
+
!isNaN(inputValue)) {
|
|
704
824
|
const valueNumber = ref.valueAsNumber ||
|
|
705
825
|
(inputValue ? +inputValue : inputValue);
|
|
706
826
|
if (!isNullOrUndefined(maxOutput.value)) {
|
|
@@ -797,7 +917,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
797
917
|
...validateError,
|
|
798
918
|
...appendErrorsCurry(key, validateError.message),
|
|
799
919
|
};
|
|
800
|
-
|
|
920
|
+
if (!validateAllFieldCriteria) {
|
|
921
|
+
setCustomValidity(validateError.message);
|
|
922
|
+
}
|
|
801
923
|
if (validateAllFieldCriteria) {
|
|
802
924
|
error[name] = validationResult;
|
|
803
925
|
}
|
|
@@ -814,7 +936,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
814
936
|
}
|
|
815
937
|
}
|
|
816
938
|
}
|
|
817
|
-
|
|
939
|
+
const fieldError = error[name];
|
|
940
|
+
setCustomValidity(fieldError ? fieldError.message : true);
|
|
818
941
|
return error;
|
|
819
942
|
};
|
|
820
943
|
|
|
@@ -823,6 +946,14 @@ const defaultOptions = {
|
|
|
823
946
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
824
947
|
shouldFocusError: true,
|
|
825
948
|
};
|
|
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
|
+
};
|
|
826
957
|
const DEFAULT_FORM_STATE = {
|
|
827
958
|
submitCount: 0,
|
|
828
959
|
isDirty: false,
|
|
@@ -856,6 +987,7 @@ function createFormControl(props = {}) {
|
|
|
856
987
|
: cloneObject(_defaultValues);
|
|
857
988
|
let _state = {
|
|
858
989
|
action: false,
|
|
990
|
+
actionArrayLengths: new Map(),
|
|
859
991
|
mount: false,
|
|
860
992
|
watch: false,
|
|
861
993
|
keepIsValid: false,
|
|
@@ -868,8 +1000,11 @@ function createFormControl(props = {}) {
|
|
|
868
1000
|
watch: new Set(),
|
|
869
1001
|
registerName: new Set(),
|
|
870
1002
|
};
|
|
871
|
-
|
|
872
|
-
|
|
1003
|
+
const delayErrorCallbacks = {};
|
|
1004
|
+
const timers = {};
|
|
1005
|
+
let _valuesSubscriberCount = 0;
|
|
1006
|
+
let _validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1007
|
+
let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
873
1008
|
const defaultProxyFormState = {
|
|
874
1009
|
isDirty: false,
|
|
875
1010
|
dirtyFields: false,
|
|
@@ -885,27 +1020,40 @@ function createFormControl(props = {}) {
|
|
|
885
1020
|
let _proxySubscribeFormState = {
|
|
886
1021
|
..._proxyFormState,
|
|
887
1022
|
};
|
|
1023
|
+
const _isTracked = (...keys) => keys.some((key) => _proxyFormState[key] || _proxySubscribeFormState[key]);
|
|
888
1024
|
const _subjects = {
|
|
889
1025
|
array: createSubject(),
|
|
890
1026
|
state: createSubject(),
|
|
891
1027
|
};
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
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
|
+
}
|
|
896
1046
|
};
|
|
897
1047
|
const _setValid = async (shouldUpdateValid) => {
|
|
898
1048
|
if (_state.keepIsValid) {
|
|
899
1049
|
return;
|
|
900
1050
|
}
|
|
901
|
-
if (!_options.disabled &&
|
|
902
|
-
|
|
903
|
-
_proxySubscribeFormState.isValid ||
|
|
904
|
-
shouldUpdateValid)) {
|
|
1051
|
+
if (!_options.disabled && (_isTracked('isValid') || shouldUpdateValid)) {
|
|
1052
|
+
const callId = ++_setValidCallId;
|
|
905
1053
|
let isValid;
|
|
906
1054
|
if (_options.resolver) {
|
|
907
1055
|
isValid = isEmptyObject((await _runSchema()).errors);
|
|
908
|
-
_updateIsValidating();
|
|
1056
|
+
callId === _setValidCallId && _updateIsValidating();
|
|
909
1057
|
}
|
|
910
1058
|
else {
|
|
911
1059
|
isValid = await executeBuiltInValidation({
|
|
@@ -914,7 +1062,7 @@ function createFormControl(props = {}) {
|
|
|
914
1062
|
eventType: EVENTS.VALID,
|
|
915
1063
|
});
|
|
916
1064
|
}
|
|
917
|
-
if (isValid !== _formState.isValid) {
|
|
1065
|
+
if (callId === _setValidCallId && isValid !== _formState.isValid) {
|
|
918
1066
|
_subjects.state.next({
|
|
919
1067
|
isValid,
|
|
920
1068
|
});
|
|
@@ -922,12 +1070,8 @@ function createFormControl(props = {}) {
|
|
|
922
1070
|
}
|
|
923
1071
|
};
|
|
924
1072
|
const _updateIsValidating = (names, isValidating) => {
|
|
925
|
-
if (!_options.disabled &&
|
|
926
|
-
(
|
|
927
|
-
_proxyFormState.validatingFields ||
|
|
928
|
-
_proxySubscribeFormState.isValidating ||
|
|
929
|
-
_proxySubscribeFormState.validatingFields)) {
|
|
930
|
-
(names || Array.from(_names.mount)).forEach((name) => {
|
|
1073
|
+
if (!_options.disabled && _isTracked('isValidating', 'validatingFields')) {
|
|
1074
|
+
(names || _names.mount).forEach((name) => {
|
|
931
1075
|
if (name) {
|
|
932
1076
|
isValidating
|
|
933
1077
|
? set(_formState.validatingFields, name, isValidating)
|
|
@@ -941,35 +1085,50 @@ function createFormControl(props = {}) {
|
|
|
941
1085
|
}
|
|
942
1086
|
};
|
|
943
1087
|
const _updateDirtyFields = () => {
|
|
944
|
-
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1088
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
945
1089
|
};
|
|
946
1090
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
947
1091
|
if (args && method && !_options.disabled) {
|
|
948
1092
|
_state.action = true;
|
|
949
|
-
|
|
950
|
-
|
|
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);
|
|
951
1099
|
shouldSetValues && set(_fields, name, fieldValues);
|
|
952
1100
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
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
|
+
}
|
|
956
1108
|
shouldSetValues && set(_formState.errors, name, errors);
|
|
957
1109
|
unsetEmptyArray(_formState.errors, name);
|
|
958
1110
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
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);
|
|
964
1115
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
965
1116
|
}
|
|
966
|
-
|
|
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')) {
|
|
967
1123
|
_updateDirtyFields();
|
|
968
1124
|
}
|
|
969
1125
|
_subjects.state.next({
|
|
970
1126
|
name,
|
|
971
1127
|
isDirty: _getDirty(name, values),
|
|
972
1128
|
dirtyFields: _formState.dirtyFields,
|
|
1129
|
+
...(shouldUpdateTouchedFields && {
|
|
1130
|
+
touchedFields: _formState.touchedFields,
|
|
1131
|
+
}),
|
|
973
1132
|
errors: _formState.errors,
|
|
974
1133
|
isValid: _formState.isValid,
|
|
975
1134
|
});
|
|
@@ -980,16 +1139,20 @@ function createFormControl(props = {}) {
|
|
|
980
1139
|
};
|
|
981
1140
|
const updateErrors = (name, error) => {
|
|
982
1141
|
set(_formState.errors, name, error);
|
|
1142
|
+
_formState.errors = { ..._formState.errors };
|
|
983
1143
|
_subjects.state.next({
|
|
984
1144
|
errors: _formState.errors,
|
|
985
1145
|
});
|
|
986
1146
|
};
|
|
987
1147
|
const _setErrors = (errors) => {
|
|
1148
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1149
|
+
const hasErrors = !isEmptyObject(errors);
|
|
988
1150
|
_formState.errors = errors;
|
|
989
1151
|
_subjects.state.next({
|
|
990
1152
|
errors: _formState.errors,
|
|
991
|
-
isValid: false,
|
|
1153
|
+
...(hasErrors ? { isValid: false } : {}),
|
|
992
1154
|
});
|
|
1155
|
+
!hasErrors && _state.mount && _setValid();
|
|
993
1156
|
};
|
|
994
1157
|
const hasExplicitNullIntermediate = (name) => {
|
|
995
1158
|
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
@@ -1007,10 +1170,46 @@ function createFormControl(props = {}) {
|
|
|
1007
1170
|
}
|
|
1008
1171
|
return false;
|
|
1009
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
|
+
};
|
|
1010
1209
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1011
1210
|
const field = get(_fields, name);
|
|
1012
1211
|
if (field) {
|
|
1013
|
-
if (hasExplicitNullIntermediate(name)) {
|
|
1212
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayField(name)) {
|
|
1014
1213
|
return;
|
|
1015
1214
|
}
|
|
1016
1215
|
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
@@ -1021,22 +1220,28 @@ function createFormControl(props = {}) {
|
|
|
1021
1220
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1022
1221
|
: setFieldValue(name, defaultValue);
|
|
1023
1222
|
if (_state.mount && !_state.action) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1223
|
+
if (_options.resolver &&
|
|
1224
|
+
_isTracked('isValidating', 'validatingFields')) {
|
|
1225
|
+
Promise.resolve().then(() => _setValid());
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
_setValid();
|
|
1229
|
+
}
|
|
1031
1230
|
if (wasUnsetInFormValues &&
|
|
1032
1231
|
_formState.isDirty &&
|
|
1033
|
-
(
|
|
1232
|
+
_isTracked('isDirty')) {
|
|
1034
1233
|
const isDirty = _getDirty();
|
|
1035
1234
|
if (!isDirty) {
|
|
1036
1235
|
_formState.isDirty = false;
|
|
1037
1236
|
_subjects.state.next({ ..._formState });
|
|
1038
1237
|
}
|
|
1039
1238
|
}
|
|
1239
|
+
if (props.shouldUnregister &&
|
|
1240
|
+
wasUnsetInFormValues &&
|
|
1241
|
+
!isUndefined(get(_formValues, name)) &&
|
|
1242
|
+
isWatched(name, _names)) {
|
|
1243
|
+
_state.watch = true;
|
|
1244
|
+
}
|
|
1040
1245
|
}
|
|
1041
1246
|
}
|
|
1042
1247
|
};
|
|
@@ -1046,17 +1251,20 @@ function createFormControl(props = {}) {
|
|
|
1046
1251
|
const output = {
|
|
1047
1252
|
name,
|
|
1048
1253
|
};
|
|
1049
|
-
|
|
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) {
|
|
1050
1257
|
if (!isBlurEvent || shouldDirty) {
|
|
1051
|
-
|
|
1258
|
+
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1259
|
+
if (_isTracked('isDirty')) {
|
|
1052
1260
|
isPreviousDirty = _formState.isDirty;
|
|
1053
|
-
_formState.isDirty = output.isDirty =
|
|
1261
|
+
_formState.isDirty = output.isDirty =
|
|
1262
|
+
!isCurrentFieldPristine || _getDirty();
|
|
1054
1263
|
shouldUpdateField = isPreviousDirty !== output.isDirty;
|
|
1055
1264
|
}
|
|
1056
|
-
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1057
1265
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1058
1266
|
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1059
|
-
_formState.dirtyFields
|
|
1267
|
+
updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
|
|
1060
1268
|
}
|
|
1061
1269
|
else {
|
|
1062
1270
|
isCurrentFieldPristine
|
|
@@ -1066,8 +1274,7 @@ function createFormControl(props = {}) {
|
|
|
1066
1274
|
output.dirtyFields = _formState.dirtyFields;
|
|
1067
1275
|
shouldUpdateField =
|
|
1068
1276
|
shouldUpdateField ||
|
|
1069
|
-
((
|
|
1070
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
1277
|
+
(_isTracked('dirtyFields') &&
|
|
1071
1278
|
isPreviousDirty !== !isCurrentFieldPristine);
|
|
1072
1279
|
}
|
|
1073
1280
|
if (isBlurEvent) {
|
|
@@ -1077,8 +1284,7 @@ function createFormControl(props = {}) {
|
|
|
1077
1284
|
output.touchedFields = _formState.touchedFields;
|
|
1078
1285
|
shouldUpdateField =
|
|
1079
1286
|
shouldUpdateField ||
|
|
1080
|
-
((
|
|
1081
|
-
_proxySubscribeFormState.touchedFields) &&
|
|
1287
|
+
(_isTracked('touchedFields') &&
|
|
1082
1288
|
isPreviousFieldTouched !== isBlurEvent);
|
|
1083
1289
|
}
|
|
1084
1290
|
}
|
|
@@ -1088,19 +1294,19 @@ function createFormControl(props = {}) {
|
|
|
1088
1294
|
};
|
|
1089
1295
|
const shouldRenderByError = (name, isValid, error, fieldState) => {
|
|
1090
1296
|
const previousFieldError = get(_formState.errors, name);
|
|
1091
|
-
const shouldUpdateValid = (
|
|
1297
|
+
const shouldUpdateValid = _isTracked('isValid') &&
|
|
1092
1298
|
isBoolean(isValid) &&
|
|
1093
1299
|
_formState.isValid !== isValid;
|
|
1094
1300
|
if (_options.delayError && error) {
|
|
1095
|
-
|
|
1096
|
-
|
|
1301
|
+
delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
|
|
1302
|
+
delayErrorCallbacks[name](_options.delayError);
|
|
1097
1303
|
}
|
|
1098
1304
|
else {
|
|
1099
|
-
|
|
1100
|
-
delayErrorCallback = null;
|
|
1305
|
+
cancelDelayedError(name);
|
|
1101
1306
|
error
|
|
1102
1307
|
? set(_formState.errors, name, error)
|
|
1103
1308
|
: unset(_formState.errors, name);
|
|
1309
|
+
_formState.errors = { ..._formState.errors };
|
|
1104
1310
|
}
|
|
1105
1311
|
if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
|
|
1106
1312
|
!isEmptyObject(fieldState) ||
|
|
@@ -1111,10 +1317,6 @@ function createFormControl(props = {}) {
|
|
|
1111
1317
|
errors: _formState.errors,
|
|
1112
1318
|
name,
|
|
1113
1319
|
};
|
|
1114
|
-
_formState = {
|
|
1115
|
-
..._formState,
|
|
1116
|
-
...updatedFormState,
|
|
1117
|
-
};
|
|
1118
1320
|
_subjects.state.next(updatedFormState);
|
|
1119
1321
|
}
|
|
1120
1322
|
};
|
|
@@ -1123,52 +1325,76 @@ function createFormControl(props = {}) {
|
|
|
1123
1325
|
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1124
1326
|
};
|
|
1125
1327
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1328
|
+
const resetCallId = _resetCallId;
|
|
1126
1329
|
const { errors } = await _runSchema(names);
|
|
1330
|
+
if (resetCallId !== _resetCallId) {
|
|
1331
|
+
return errors;
|
|
1332
|
+
}
|
|
1127
1333
|
_updateIsValidating(names);
|
|
1128
1334
|
if (names) {
|
|
1129
1335
|
for (const name of names) {
|
|
1130
1336
|
const error = get(errors, name);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
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);
|
|
1351
|
+
}
|
|
1352
|
+
_formState.errors = { ..._formState.errors };
|
|
1137
1353
|
}
|
|
1138
1354
|
else {
|
|
1355
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1139
1356
|
_formState.errors = errors;
|
|
1140
1357
|
}
|
|
1141
1358
|
return errors;
|
|
1142
1359
|
};
|
|
1143
1360
|
const validateForm = async ({ name, eventType, }) => {
|
|
1144
|
-
if (
|
|
1145
|
-
const
|
|
1361
|
+
if (_options.validate) {
|
|
1362
|
+
const resetCallId = _resetCallId;
|
|
1363
|
+
const result = await _options.validate({
|
|
1146
1364
|
formValues: _formValues,
|
|
1147
1365
|
formState: _formState,
|
|
1148
1366
|
name,
|
|
1149
1367
|
eventType,
|
|
1150
1368
|
});
|
|
1369
|
+
if (resetCallId !== _resetCallId) {
|
|
1370
|
+
return true;
|
|
1371
|
+
}
|
|
1151
1372
|
if (isObject(result)) {
|
|
1373
|
+
let isValid = true;
|
|
1374
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1152
1375
|
for (const key in result) {
|
|
1153
1376
|
const error = result[key];
|
|
1154
1377
|
if (error) {
|
|
1378
|
+
isValid = false;
|
|
1155
1379
|
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1156
1380
|
message: isString(error.message) ? error.message : '',
|
|
1157
1381
|
type: error.type || INPUT_VALIDATION_RULES.validate,
|
|
1158
1382
|
});
|
|
1159
1383
|
}
|
|
1160
1384
|
}
|
|
1385
|
+
return isValid;
|
|
1161
1386
|
}
|
|
1162
1387
|
else if (isString(result) || !result) {
|
|
1163
1388
|
setError(FORM_ERROR_TYPE, {
|
|
1164
1389
|
message: result || '',
|
|
1165
1390
|
type: INPUT_VALIDATION_RULES.validate,
|
|
1166
1391
|
});
|
|
1392
|
+
return false;
|
|
1167
1393
|
}
|
|
1168
1394
|
else {
|
|
1169
1395
|
clearErrors(FORM_ERROR_TYPE);
|
|
1396
|
+
return true;
|
|
1170
1397
|
}
|
|
1171
|
-
return result;
|
|
1172
1398
|
}
|
|
1173
1399
|
return true;
|
|
1174
1400
|
};
|
|
@@ -1176,7 +1402,8 @@ function createFormControl(props = {}) {
|
|
|
1176
1402
|
valid: true,
|
|
1177
1403
|
runRootValidation: false,
|
|
1178
1404
|
}, }) => {
|
|
1179
|
-
|
|
1405
|
+
const resetCallId = _resetCallId;
|
|
1406
|
+
if (_options.validate && !context.runRootValidation) {
|
|
1180
1407
|
context.runRootValidation = true;
|
|
1181
1408
|
const result = await validateForm({
|
|
1182
1409
|
name,
|
|
@@ -1196,14 +1423,14 @@ function createFormControl(props = {}) {
|
|
|
1196
1423
|
if (_f) {
|
|
1197
1424
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
1198
1425
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
1199
|
-
const shouldTrackIsValidatingState =
|
|
1200
|
-
_proxyFormState.isValidating ||
|
|
1201
|
-
_proxySubscribeFormState.validatingFields ||
|
|
1202
|
-
_proxySubscribeFormState.isValidating;
|
|
1426
|
+
const shouldTrackIsValidatingState = _isTracked('isValidating', 'validatingFields');
|
|
1203
1427
|
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1204
1428
|
_updateIsValidating([_f.name], true);
|
|
1205
1429
|
}
|
|
1206
1430
|
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1431
|
+
if (resetCallId !== _resetCallId) {
|
|
1432
|
+
return context.valid;
|
|
1433
|
+
}
|
|
1207
1434
|
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1208
1435
|
_updateIsValidating([_f.name]);
|
|
1209
1436
|
}
|
|
@@ -1213,12 +1440,14 @@ function createFormControl(props = {}) {
|
|
|
1213
1440
|
break;
|
|
1214
1441
|
}
|
|
1215
1442
|
}
|
|
1216
|
-
!onlyCheckValid
|
|
1217
|
-
(
|
|
1443
|
+
if (!onlyCheckValid) {
|
|
1444
|
+
cancelDelayedError(_f.name);
|
|
1445
|
+
get(fieldError, _f.name)
|
|
1218
1446
|
? isFieldArrayRoot
|
|
1219
1447
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1220
1448
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1221
|
-
: unset(_formState.errors, _f.name)
|
|
1449
|
+
: unset(_formState.errors, _f.name);
|
|
1450
|
+
}
|
|
1222
1451
|
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1223
1452
|
break;
|
|
1224
1453
|
}
|
|
@@ -1246,20 +1475,17 @@ function createFormControl(props = {}) {
|
|
|
1246
1475
|
}
|
|
1247
1476
|
_names.unMount = new Set();
|
|
1248
1477
|
};
|
|
1249
|
-
const _getDirty = (name, data) =>
|
|
1250
|
-
(
|
|
1251
|
-
!deepEqual(getValues(), _defaultValues));
|
|
1478
|
+
const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
|
|
1479
|
+
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1252
1480
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
1253
1481
|
...(_state.mount
|
|
1254
1482
|
? _formValues
|
|
1255
|
-
: isUndefined(defaultValue)
|
|
1483
|
+
: isUndefined(defaultValue) || isString(names)
|
|
1256
1484
|
? _defaultValues
|
|
1257
|
-
:
|
|
1258
|
-
? { [names]: defaultValue }
|
|
1259
|
-
: defaultValue),
|
|
1485
|
+
: defaultValue),
|
|
1260
1486
|
}, isGlobal, defaultValue);
|
|
1261
1487
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
1262
|
-
const setFieldValue = (name, value, options = {}) => {
|
|
1488
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
1263
1489
|
const field = get(_fields, name);
|
|
1264
1490
|
let fieldValue = value;
|
|
1265
1491
|
if (field) {
|
|
@@ -1297,23 +1523,46 @@ function createFormControl(props = {}) {
|
|
|
1297
1523
|
}
|
|
1298
1524
|
else {
|
|
1299
1525
|
fieldReference.ref.value = fieldValue;
|
|
1300
|
-
if (!fieldReference.ref.type) {
|
|
1526
|
+
if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
|
|
1301
1527
|
_subjects.state.next({
|
|
1302
1528
|
name,
|
|
1303
|
-
values: cloneObject(_formValues),
|
|
1529
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1304
1530
|
});
|
|
1305
1531
|
}
|
|
1306
1532
|
}
|
|
1307
1533
|
}
|
|
1308
1534
|
}
|
|
1309
1535
|
(options.shouldDirty || options.shouldTouch) &&
|
|
1310
|
-
updateTouchAndDirty(name,
|
|
1311
|
-
|
|
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
|
+
}
|
|
1312
1555
|
};
|
|
1313
|
-
const setFieldValues = (name, value, options) => {
|
|
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
|
+
}
|
|
1314
1563
|
for (const fieldKey in value) {
|
|
1315
1564
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1316
|
-
|
|
1565
|
+
continue;
|
|
1317
1566
|
}
|
|
1318
1567
|
const fieldValue = value[fieldKey];
|
|
1319
1568
|
const fieldName = name + '.' + fieldKey;
|
|
@@ -1322,14 +1571,14 @@ function createFormControl(props = {}) {
|
|
|
1322
1571
|
isObject(fieldValue) ||
|
|
1323
1572
|
(field && !field._f)) &&
|
|
1324
1573
|
!isDateObject(fieldValue)
|
|
1325
|
-
? setFieldValues(fieldName, fieldValue, options)
|
|
1326
|
-
: setFieldValue(fieldName, fieldValue, options);
|
|
1574
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
|
|
1575
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
|
|
1327
1576
|
}
|
|
1328
1577
|
};
|
|
1329
|
-
const
|
|
1578
|
+
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
1330
1579
|
const field = get(_fields, name);
|
|
1331
1580
|
const isFieldArray = _names.array.has(name);
|
|
1332
|
-
const cloneValue = cloneObject(value);
|
|
1581
|
+
const cloneValue = skipClone ? value : cloneObject(value);
|
|
1333
1582
|
const previousValue = get(_formValues, name);
|
|
1334
1583
|
const isValueUnchanged = deepEqual(previousValue, cloneValue);
|
|
1335
1584
|
if (!isValueUnchanged) {
|
|
@@ -1338,47 +1587,51 @@ function createFormControl(props = {}) {
|
|
|
1338
1587
|
if (isFieldArray) {
|
|
1339
1588
|
_subjects.array.next({
|
|
1340
1589
|
name,
|
|
1341
|
-
values: cloneObject(_formValues),
|
|
1590
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1342
1591
|
});
|
|
1343
|
-
if ((
|
|
1344
|
-
_proxyFormState.dirtyFields ||
|
|
1345
|
-
_proxySubscribeFormState.isDirty ||
|
|
1346
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
1347
|
-
options.shouldDirty) {
|
|
1592
|
+
if (_isTracked('isDirty', 'dirtyFields') && options.shouldDirty) {
|
|
1348
1593
|
_updateDirtyFields();
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1594
|
+
if (!skipStateEmit) {
|
|
1595
|
+
_subjects.state.next({
|
|
1596
|
+
name,
|
|
1597
|
+
dirtyFields: _formState.dirtyFields,
|
|
1598
|
+
isDirty: _getDirty(name, cloneValue),
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1354
1601
|
}
|
|
1602
|
+
options.shouldValidate &&
|
|
1603
|
+
trigger(name, {
|
|
1604
|
+
delayError: options.delayError,
|
|
1605
|
+
});
|
|
1355
1606
|
}
|
|
1356
1607
|
else {
|
|
1357
1608
|
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
1358
1609
|
isEmptyObject(cloneValue);
|
|
1610
|
+
const skipValueRender = !isValueUnchanged && !skipStateEmit;
|
|
1359
1611
|
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
1360
|
-
setFieldValue(name, cloneValue, options);
|
|
1612
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
1361
1613
|
}
|
|
1362
1614
|
else {
|
|
1363
|
-
setFieldValues(name, cloneValue, options);
|
|
1615
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
1364
1616
|
}
|
|
1365
1617
|
}
|
|
1366
|
-
if (!isValueUnchanged) {
|
|
1618
|
+
if (!isValueUnchanged && !skipStateEmit) {
|
|
1367
1619
|
const watched = isWatched(name, _names);
|
|
1368
|
-
const values = cloneObject(_formValues);
|
|
1369
|
-
if (!isFieldArray) {
|
|
1370
|
-
for (const arrayName of getFieldArrayParentNames(_names.array, name)) {
|
|
1371
|
-
_subjects.array.next({ name: arrayName, values });
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1620
|
+
const values = skipClone ? _formValues : cloneObject(_formValues);
|
|
1374
1621
|
_subjects.state.next({
|
|
1375
1622
|
...(watched && _formState),
|
|
1376
1623
|
name: _state.mount || watched ? name : undefined,
|
|
1377
1624
|
values,
|
|
1378
1625
|
});
|
|
1626
|
+
if (!isFieldArray) {
|
|
1627
|
+
for (const itemName of getFieldArrayItemNames(_names.array, name)) {
|
|
1628
|
+
_subjects.state.next({ name: itemName, values });
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1379
1631
|
}
|
|
1380
1632
|
};
|
|
1381
|
-
const
|
|
1633
|
+
const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
|
|
1634
|
+
const setValues = (formValues, options = {}) => {
|
|
1382
1635
|
const updatedFormValues = isFunction(formValues)
|
|
1383
1636
|
? formValues(_formValues)
|
|
1384
1637
|
: formValues;
|
|
@@ -1388,9 +1641,19 @@ function createFormControl(props = {}) {
|
|
|
1388
1641
|
...updatedFormValues,
|
|
1389
1642
|
};
|
|
1390
1643
|
for (const fieldName of _names.mount) {
|
|
1391
|
-
|
|
1644
|
+
if (has(updatedFormValues, fieldName)) {
|
|
1645
|
+
_setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
_subjects.state.next({
|
|
1649
|
+
..._formState,
|
|
1650
|
+
name: undefined,
|
|
1651
|
+
type: undefined,
|
|
1652
|
+
...(_valuesSubscriberCount ? { values: _formValues } : {}),
|
|
1653
|
+
});
|
|
1654
|
+
if (options.shouldValidate) {
|
|
1655
|
+
_setValid();
|
|
1392
1656
|
}
|
|
1393
|
-
_subjects.state.next({ ..._formState, values: _formValues });
|
|
1394
1657
|
}
|
|
1395
1658
|
};
|
|
1396
1659
|
const onChange = async (event) => {
|
|
@@ -1405,8 +1668,6 @@ function createFormControl(props = {}) {
|
|
|
1405
1668
|
(isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
|
|
1406
1669
|
deepEqual(fieldValue, get(_formValues, name, fieldValue));
|
|
1407
1670
|
};
|
|
1408
|
-
const validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1409
|
-
const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1410
1671
|
if (field) {
|
|
1411
1672
|
let error;
|
|
1412
1673
|
let isValid;
|
|
@@ -1414,18 +1675,20 @@ function createFormControl(props = {}) {
|
|
|
1414
1675
|
? getFieldValue(field._f)
|
|
1415
1676
|
: getEventValue(event);
|
|
1416
1677
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1417
|
-
const
|
|
1418
|
-
!
|
|
1678
|
+
const hasNoValidationEffect = !hasValidation(field._f) &&
|
|
1679
|
+
!_options.validate &&
|
|
1419
1680
|
!_options.resolver &&
|
|
1420
1681
|
!get(_formState.errors, name) &&
|
|
1421
|
-
!field._f.deps
|
|
1422
|
-
|
|
1682
|
+
!field._f.deps;
|
|
1683
|
+
const shouldSkipValidation = hasNoValidationEffect ||
|
|
1684
|
+
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
1423
1685
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
1424
|
-
set(_formValues, name, fieldValue);
|
|
1686
|
+
set(_formValues, name, cloneObject(fieldValue));
|
|
1425
1687
|
if (isBlurEvent) {
|
|
1426
1688
|
if (!target || !target.readOnly) {
|
|
1427
1689
|
field._f.onBlur && field._f.onBlur(event);
|
|
1428
|
-
|
|
1690
|
+
const pendingDelayError = delayErrorCallbacks[name];
|
|
1691
|
+
pendingDelayError && pendingDelayError(0);
|
|
1429
1692
|
}
|
|
1430
1693
|
}
|
|
1431
1694
|
else if (field._f.onChange) {
|
|
@@ -1437,10 +1700,13 @@ function createFormControl(props = {}) {
|
|
|
1437
1700
|
_subjects.state.next({
|
|
1438
1701
|
name,
|
|
1439
1702
|
type: event.type,
|
|
1440
|
-
|
|
1703
|
+
...(_valuesSubscriberCount
|
|
1704
|
+
? { values: cloneObject(_formValues) }
|
|
1705
|
+
: {}),
|
|
1441
1706
|
});
|
|
1442
1707
|
if (shouldSkipValidation) {
|
|
1443
|
-
if (
|
|
1708
|
+
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
1709
|
+
_isTracked('isValid')) {
|
|
1444
1710
|
if (_options.mode === 'onBlur') {
|
|
1445
1711
|
if (isBlurEvent) {
|
|
1446
1712
|
_setValid();
|
|
@@ -1453,7 +1719,7 @@ function createFormControl(props = {}) {
|
|
|
1453
1719
|
return (shouldRender &&
|
|
1454
1720
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1455
1721
|
}
|
|
1456
|
-
if (!_options.resolver &&
|
|
1722
|
+
if (!_options.resolver && _options.validate) {
|
|
1457
1723
|
await validateForm({
|
|
1458
1724
|
name: name,
|
|
1459
1725
|
eventType: event.type,
|
|
@@ -1461,34 +1727,46 @@ function createFormControl(props = {}) {
|
|
|
1461
1727
|
}
|
|
1462
1728
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1463
1729
|
if (_options.resolver) {
|
|
1730
|
+
const resetCallId = _resetCallId;
|
|
1464
1731
|
const { errors } = await _runSchema([name]);
|
|
1732
|
+
if (resetCallId !== _resetCallId) {
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1465
1735
|
_updateIsValidating([name]);
|
|
1466
1736
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1467
|
-
if (isFieldValueUpdated) {
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
error = errorLookupResult.error;
|
|
1471
|
-
name = errorLookupResult.name;
|
|
1472
|
-
isValid = isEmptyObject(errors);
|
|
1737
|
+
if (!isFieldValueUpdated) {
|
|
1738
|
+
!isEmptyObject(fieldState) && _subjects.state.next(fieldState);
|
|
1739
|
+
return;
|
|
1473
1740
|
}
|
|
1741
|
+
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
|
1742
|
+
const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
|
|
1743
|
+
error = errorLookupResult.error;
|
|
1744
|
+
name = errorLookupResult.name;
|
|
1745
|
+
isValid = isEmptyObject(errors);
|
|
1474
1746
|
}
|
|
1475
1747
|
else {
|
|
1748
|
+
const resetCallId = _resetCallId;
|
|
1476
1749
|
_updateIsValidating([name], true);
|
|
1477
1750
|
error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
|
|
1751
|
+
if (resetCallId !== _resetCallId) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1478
1754
|
_updateIsValidating([name]);
|
|
1479
1755
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1480
1756
|
if (isFieldValueUpdated) {
|
|
1481
1757
|
if (error) {
|
|
1482
1758
|
isValid = false;
|
|
1483
1759
|
}
|
|
1484
|
-
else if (
|
|
1485
|
-
_proxySubscribeFormState.isValid) {
|
|
1760
|
+
else if (_isTracked('isValid')) {
|
|
1486
1761
|
isValid = await executeBuiltInValidation({
|
|
1487
1762
|
fields: _fields,
|
|
1488
1763
|
onlyCheckValid: true,
|
|
1489
1764
|
name: name,
|
|
1490
1765
|
eventType: event.type,
|
|
1491
1766
|
});
|
|
1767
|
+
if (resetCallId !== _resetCallId) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1492
1770
|
}
|
|
1493
1771
|
}
|
|
1494
1772
|
}
|
|
@@ -1512,11 +1790,15 @@ function createFormControl(props = {}) {
|
|
|
1512
1790
|
let validationResult;
|
|
1513
1791
|
const fieldNames = convertToArrayPayload(name);
|
|
1514
1792
|
if (_options.resolver) {
|
|
1793
|
+
const resetCallId = _resetCallId;
|
|
1515
1794
|
const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
|
|
1516
1795
|
isValid = isEmptyObject(errors);
|
|
1517
1796
|
validationResult = name
|
|
1518
1797
|
? !fieldNames.some((name) => get(errors, name))
|
|
1519
1798
|
: isValid;
|
|
1799
|
+
if (resetCallId !== _resetCallId) {
|
|
1800
|
+
return validationResult;
|
|
1801
|
+
}
|
|
1520
1802
|
}
|
|
1521
1803
|
else if (name) {
|
|
1522
1804
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
@@ -1535,13 +1817,32 @@ function createFormControl(props = {}) {
|
|
|
1535
1817
|
eventType: EVENTS.TRIGGER,
|
|
1536
1818
|
});
|
|
1537
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
|
+
}
|
|
1538
1837
|
_subjects.state.next({
|
|
1539
1838
|
...(!isString(name) ||
|
|
1540
|
-
((
|
|
1541
|
-
isValid !== _formState.isValid)
|
|
1839
|
+
(_isTracked('isValid') && isValid !== _formState.isValid)
|
|
1542
1840
|
? {}
|
|
1543
1841
|
: { name }),
|
|
1544
1842
|
...(_options.resolver || !name ? { isValid } : {}),
|
|
1843
|
+
...(options.shouldTouch && _isTracked('touchedFields')
|
|
1844
|
+
? { touchedFields: _formState.touchedFields }
|
|
1845
|
+
: {}),
|
|
1545
1846
|
errors: _formState.errors,
|
|
1546
1847
|
});
|
|
1547
1848
|
options.shouldFocus &&
|
|
@@ -1562,20 +1863,28 @@ function createFormControl(props = {}) {
|
|
|
1562
1863
|
? get(values, fieldNames)
|
|
1563
1864
|
: fieldNames.map((name) => get(values, name));
|
|
1564
1865
|
};
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
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
|
+
};
|
|
1572
1882
|
const clearErrors = (name) => {
|
|
1573
1883
|
const names = name ? convertToArrayPayload(name) : undefined;
|
|
1574
|
-
names?.forEach((inputName) => unset(_formState.errors, inputName));
|
|
1575
1884
|
if (names) {
|
|
1576
|
-
// Emit for each cleared field with the field name so that
|
|
1577
|
-
// shouldSubscribeByName can filter and avoid broad re-renders
|
|
1578
1885
|
names.forEach((inputName) => {
|
|
1886
|
+
cancelDelayedErrorTree(inputName);
|
|
1887
|
+
unset(_formState.errors, inputName);
|
|
1579
1888
|
_subjects.state.next({
|
|
1580
1889
|
name: inputName,
|
|
1581
1890
|
errors: _formState.errors,
|
|
@@ -1583,17 +1892,18 @@ function createFormControl(props = {}) {
|
|
|
1583
1892
|
});
|
|
1584
1893
|
}
|
|
1585
1894
|
else {
|
|
1586
|
-
|
|
1895
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1896
|
+
_formState.errors = {};
|
|
1587
1897
|
_subjects.state.next({
|
|
1588
|
-
errors:
|
|
1898
|
+
errors: _formState.errors,
|
|
1589
1899
|
});
|
|
1590
1900
|
}
|
|
1591
1901
|
};
|
|
1592
1902
|
const setError = (name, error, options) => {
|
|
1903
|
+
cancelDelayedErrorTree(name);
|
|
1593
1904
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
1594
1905
|
const currentError = get(_formState.errors, name) || {};
|
|
1595
|
-
|
|
1596
|
-
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
1906
|
+
const { ref: currentRef, message, type, types, ...restOfErrorTree } = currentError;
|
|
1597
1907
|
set(_formState.errors, name, {
|
|
1598
1908
|
...restOfErrorTree,
|
|
1599
1909
|
...error,
|
|
@@ -1606,21 +1916,59 @@ function createFormControl(props = {}) {
|
|
|
1606
1916
|
});
|
|
1607
1917
|
options && options.shouldFocus && ref && ref.focus && ref.focus();
|
|
1608
1918
|
};
|
|
1609
|
-
const watch = (name, defaultValue) =>
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1919
|
+
const watch = (name, defaultValue) => {
|
|
1920
|
+
if (isFunction(name)) {
|
|
1921
|
+
_valuesSubscriberCount++;
|
|
1922
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
1923
|
+
next: (payload) => 'values' in payload &&
|
|
1924
|
+
name(payload.values || _getWatch(undefined, defaultValue), payload),
|
|
1925
|
+
});
|
|
1926
|
+
let called = false;
|
|
1927
|
+
return {
|
|
1928
|
+
unsubscribe: () => {
|
|
1929
|
+
if (called) {
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
called = true;
|
|
1933
|
+
_valuesSubscriberCount--;
|
|
1934
|
+
unsubscribe();
|
|
1935
|
+
},
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
return _getWatch(name, defaultValue, true);
|
|
1939
|
+
};
|
|
1940
|
+
const _subscribe = (props) => {
|
|
1941
|
+
const needsValues = !!props.formState?.values;
|
|
1942
|
+
if (needsValues) {
|
|
1943
|
+
_valuesSubscriberCount++;
|
|
1944
|
+
}
|
|
1945
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
1946
|
+
next: (formState) => {
|
|
1947
|
+
if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
|
|
1948
|
+
shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
|
|
1949
|
+
const snapshot = { ..._formValues };
|
|
1950
|
+
props.callback({
|
|
1951
|
+
values: snapshot,
|
|
1952
|
+
..._formState,
|
|
1953
|
+
...formState,
|
|
1954
|
+
defaultValues: _defaultValues,
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
});
|
|
1959
|
+
if (!needsValues) {
|
|
1960
|
+
return unsubscribe;
|
|
1961
|
+
}
|
|
1962
|
+
let called = false;
|
|
1963
|
+
return () => {
|
|
1964
|
+
if (called) {
|
|
1965
|
+
return;
|
|
1621
1966
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1967
|
+
called = true;
|
|
1968
|
+
_valuesSubscriberCount--;
|
|
1969
|
+
unsubscribe();
|
|
1970
|
+
};
|
|
1971
|
+
};
|
|
1624
1972
|
const subscribe = (props) => {
|
|
1625
1973
|
_state.mount = true;
|
|
1626
1974
|
_proxySubscribeFormState = {
|
|
@@ -1639,11 +1987,15 @@ function createFormControl(props = {}) {
|
|
|
1639
1987
|
for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
|
|
1640
1988
|
_names.mount.delete(fieldName);
|
|
1641
1989
|
_names.array.delete(fieldName);
|
|
1990
|
+
_names.disabled.delete(fieldName);
|
|
1642
1991
|
if (!options.keepValue) {
|
|
1643
1992
|
unset(_fields, fieldName);
|
|
1644
1993
|
unset(_formValues, fieldName);
|
|
1645
1994
|
}
|
|
1646
|
-
!options.keepError
|
|
1995
|
+
if (!options.keepError) {
|
|
1996
|
+
cancelDelayedErrorTree(fieldName);
|
|
1997
|
+
unset(_formState.errors, fieldName);
|
|
1998
|
+
}
|
|
1647
1999
|
!options.keepDirty && unset(_formState.dirtyFields, fieldName);
|
|
1648
2000
|
!options.keepTouched && unset(_formState.touchedFields, fieldName);
|
|
1649
2001
|
!options.keepIsValidating &&
|
|
@@ -1652,12 +2004,16 @@ function createFormControl(props = {}) {
|
|
|
1652
2004
|
!options.keepDefaultValue &&
|
|
1653
2005
|
unset(_defaultValues, fieldName);
|
|
1654
2006
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2007
|
+
_valuesSubscriberCount &&
|
|
2008
|
+
_subjects.state.next({
|
|
2009
|
+
values: cloneObject(_formValues),
|
|
2010
|
+
});
|
|
1658
2011
|
_subjects.state.next({
|
|
1659
2012
|
..._formState,
|
|
1660
|
-
...(
|
|
2013
|
+
...(options.keepDirty ? {} : { isDirty: _getDirty() }),
|
|
2014
|
+
...(options.keepIsValidating
|
|
2015
|
+
? {}
|
|
2016
|
+
: { isValidating: !isEmptyObject(_formState.validatingFields) }),
|
|
1661
2017
|
});
|
|
1662
2018
|
!options.keepIsValid && _setValid();
|
|
1663
2019
|
};
|
|
@@ -1686,6 +2042,14 @@ function createFormControl(props = {}) {
|
|
|
1686
2042
|
},
|
|
1687
2043
|
});
|
|
1688
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
|
+
}
|
|
1689
2053
|
if (field && !shouldRevalidateRemount) {
|
|
1690
2054
|
_setDisabledField({
|
|
1691
2055
|
disabled: isBoolean(options.disabled)
|
|
@@ -1732,20 +2096,23 @@ function createFormControl(props = {}) {
|
|
|
1732
2096
|
: fieldRef === field._f.ref) {
|
|
1733
2097
|
return;
|
|
1734
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
|
+
}
|
|
1735
2114
|
set(_fields, name, {
|
|
1736
|
-
_f:
|
|
1737
|
-
...field._f,
|
|
1738
|
-
...(radioOrCheckbox
|
|
1739
|
-
? {
|
|
1740
|
-
refs: [
|
|
1741
|
-
...refs.filter(live),
|
|
1742
|
-
fieldRef,
|
|
1743
|
-
...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
|
|
1744
|
-
],
|
|
1745
|
-
ref: { type: fieldRef.type, name },
|
|
1746
|
-
}
|
|
1747
|
-
: { ref: fieldRef }),
|
|
1748
|
-
},
|
|
2115
|
+
_f: newField,
|
|
1749
2116
|
});
|
|
1750
2117
|
updateValidAndValue(name, false, undefined, fieldRef);
|
|
1751
2118
|
}
|
|
@@ -1755,8 +2122,7 @@ function createFormControl(props = {}) {
|
|
|
1755
2122
|
field._f.mount = false;
|
|
1756
2123
|
}
|
|
1757
2124
|
(_options.shouldUnregister || options.shouldUnregister) &&
|
|
1758
|
-
!(
|
|
1759
|
-
_state.action) &&
|
|
2125
|
+
!(isNameInFieldArray(_names.array, name) && _state.action) &&
|
|
1760
2126
|
_names.unMount.add(name);
|
|
1761
2127
|
}
|
|
1762
2128
|
},
|
|
@@ -1778,10 +2144,11 @@ function createFormControl(props = {}) {
|
|
|
1778
2144
|
});
|
|
1779
2145
|
}
|
|
1780
2146
|
}
|
|
1781
|
-
}, 0
|
|
2147
|
+
}, 0);
|
|
1782
2148
|
}
|
|
1783
2149
|
};
|
|
1784
2150
|
const handleSubmit = (onValid, onInvalid) => async (e) => {
|
|
2151
|
+
let result = undefined;
|
|
1785
2152
|
let onValidError = undefined;
|
|
1786
2153
|
if (e) {
|
|
1787
2154
|
e.preventDefault && e.preventDefault();
|
|
@@ -1793,29 +2160,38 @@ function createFormControl(props = {}) {
|
|
|
1793
2160
|
isSubmitting: true,
|
|
1794
2161
|
});
|
|
1795
2162
|
if (_options.resolver) {
|
|
2163
|
+
const resetCallId = _resetCallId;
|
|
1796
2164
|
const { errors, values } = await _runSchema();
|
|
2165
|
+
if (resetCallId !== _resetCallId) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
1797
2168
|
_updateIsValidating();
|
|
2169
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1798
2170
|
_formState.errors = errors;
|
|
1799
2171
|
fieldValues = cloneObject(values);
|
|
1800
2172
|
}
|
|
1801
2173
|
else {
|
|
2174
|
+
const resetCallId = _resetCallId;
|
|
1802
2175
|
await executeBuiltInValidation({
|
|
1803
2176
|
fields: _fields,
|
|
1804
2177
|
eventType: EVENTS.SUBMIT,
|
|
1805
2178
|
});
|
|
2179
|
+
if (resetCallId !== _resetCallId) {
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
1806
2183
|
}
|
|
1807
2184
|
if (_names.disabled.size) {
|
|
1808
2185
|
for (const name of _names.disabled) {
|
|
1809
2186
|
unset(fieldValues, name);
|
|
1810
2187
|
}
|
|
1811
2188
|
}
|
|
1812
|
-
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
1813
2189
|
if (isEmptyObject(_formState.errors)) {
|
|
1814
2190
|
_subjects.state.next({
|
|
1815
2191
|
errors: {},
|
|
1816
2192
|
});
|
|
1817
2193
|
try {
|
|
1818
|
-
await onValid(fieldValues, e);
|
|
2194
|
+
result = await onValid(fieldValues, e);
|
|
1819
2195
|
}
|
|
1820
2196
|
catch (error) {
|
|
1821
2197
|
onValidError = error;
|
|
@@ -1838,9 +2214,11 @@ function createFormControl(props = {}) {
|
|
|
1838
2214
|
if (onValidError) {
|
|
1839
2215
|
throw onValidError;
|
|
1840
2216
|
}
|
|
2217
|
+
return result;
|
|
1841
2218
|
};
|
|
1842
2219
|
const resetField = (name, options = {}) => {
|
|
1843
2220
|
if (get(_fields, name)) {
|
|
2221
|
+
unset(_formState.validatingFields, name);
|
|
1844
2222
|
if (isUndefined(options.defaultValue)) {
|
|
1845
2223
|
setValue(name, cloneObject(get(_defaultValues, name)));
|
|
1846
2224
|
}
|
|
@@ -1858,17 +2236,24 @@ function createFormControl(props = {}) {
|
|
|
1858
2236
|
: _getDirty();
|
|
1859
2237
|
}
|
|
1860
2238
|
if (!options.keepError) {
|
|
2239
|
+
cancelDelayedErrorTree(name);
|
|
1861
2240
|
unset(_formState.errors, name);
|
|
1862
|
-
|
|
2241
|
+
_setValid();
|
|
1863
2242
|
}
|
|
1864
|
-
_subjects.state.next({
|
|
2243
|
+
_subjects.state.next({
|
|
2244
|
+
..._formState,
|
|
2245
|
+
isValidating: !isEmptyObject(_formState.validatingFields),
|
|
2246
|
+
});
|
|
1865
2247
|
}
|
|
1866
2248
|
};
|
|
1867
2249
|
const _reset = (formValues, keepStateOptions = {}) => {
|
|
2250
|
+
_resetCallId++;
|
|
1868
2251
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
1869
2252
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
1870
2253
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
1871
|
-
const values =
|
|
2254
|
+
const values = cloneUpdatedValues;
|
|
2255
|
+
const fieldRefs = _fields;
|
|
2256
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
1872
2257
|
if (!keepStateOptions.keepDefaultValues) {
|
|
1873
2258
|
_defaultValues = updatedValues;
|
|
1874
2259
|
}
|
|
@@ -1876,9 +2261,9 @@ function createFormControl(props = {}) {
|
|
|
1876
2261
|
if (keepStateOptions.keepDirtyValues) {
|
|
1877
2262
|
const fieldsToCheck = new Set([
|
|
1878
2263
|
..._names.mount,
|
|
1879
|
-
...
|
|
2264
|
+
...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
|
|
1880
2265
|
]);
|
|
1881
|
-
for (const fieldName of
|
|
2266
|
+
for (const fieldName of fieldsToCheck) {
|
|
1882
2267
|
const isDirty = get(_formState.dirtyFields, fieldName);
|
|
1883
2268
|
const existingValue = get(_formValues, fieldName);
|
|
1884
2269
|
const newValue = get(values, fieldName);
|
|
@@ -1917,15 +2302,25 @@ function createFormControl(props = {}) {
|
|
|
1917
2302
|
_fields = {};
|
|
1918
2303
|
}
|
|
1919
2304
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
2305
|
+
if (_options.shouldUnregister) {
|
|
2306
|
+
_formValues = keepStateOptions.keepDefaultValues
|
|
1922
2307
|
? cloneObject(_defaultValues)
|
|
1923
|
-
: {}
|
|
1924
|
-
|
|
2308
|
+
: {};
|
|
2309
|
+
if (keepStateOptions.keepFieldsRef) {
|
|
2310
|
+
for (const fieldName of _names.mount) {
|
|
2311
|
+
set(_formValues, fieldName, get(values, fieldName));
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
else {
|
|
2316
|
+
_formValues = cloneObject(values);
|
|
2317
|
+
}
|
|
1925
2318
|
_subjects.array.next({
|
|
1926
2319
|
values: { ...values },
|
|
1927
2320
|
});
|
|
1928
2321
|
_subjects.state.next({
|
|
2322
|
+
name: undefined,
|
|
2323
|
+
type: undefined,
|
|
1929
2324
|
values: { ...values },
|
|
1930
2325
|
});
|
|
1931
2326
|
}
|
|
@@ -1947,9 +2342,7 @@ function createFormControl(props = {}) {
|
|
|
1947
2342
|
_state.watch = !!_options.shouldUnregister;
|
|
1948
2343
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
1949
2344
|
_state.action = false;
|
|
1950
|
-
|
|
1951
|
-
// This fixes the issue where form.reset() causes validation errors on subsequent
|
|
1952
|
-
// submissions in Next.js 16 with Server Actions
|
|
2345
|
+
_state.actionArrayLengths.clear();
|
|
1953
2346
|
if (!keepStateOptions.keepErrors) {
|
|
1954
2347
|
_formState.errors = {};
|
|
1955
2348
|
}
|
|
@@ -1961,8 +2354,10 @@ function createFormControl(props = {}) {
|
|
|
1961
2354
|
? false
|
|
1962
2355
|
: keepStateOptions.keepDirty
|
|
1963
2356
|
? _formState.isDirty
|
|
1964
|
-
:
|
|
1965
|
-
|
|
2357
|
+
: keepStateOptions.keepValues
|
|
2358
|
+
? _getDirty()
|
|
2359
|
+
: !!(keepStateOptions.keepDefaultValues &&
|
|
2360
|
+
!deepEqual(formValues, _defaultValues)),
|
|
1966
2361
|
isSubmitted: keepStateOptions.keepIsSubmitted
|
|
1967
2362
|
? _formState.isSubmitted
|
|
1968
2363
|
: false,
|
|
@@ -1970,16 +2365,22 @@ function createFormControl(props = {}) {
|
|
|
1970
2365
|
? {}
|
|
1971
2366
|
: keepStateOptions.keepDirtyValues
|
|
1972
2367
|
? keepStateOptions.keepDefaultValues && _formValues
|
|
1973
|
-
? getDirtyFields(_defaultValues, _formValues)
|
|
2368
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
1974
2369
|
: _formState.dirtyFields
|
|
1975
2370
|
: keepStateOptions.keepDefaultValues && formValues
|
|
1976
|
-
? getDirtyFields(_defaultValues, formValues)
|
|
2371
|
+
? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
|
|
1977
2372
|
: keepStateOptions.keepDirty
|
|
1978
2373
|
? _formState.dirtyFields
|
|
1979
|
-
:
|
|
2374
|
+
: keepStateOptions.keepValues
|
|
2375
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
2376
|
+
: {},
|
|
1980
2377
|
touchedFields: keepStateOptions.keepTouched
|
|
1981
2378
|
? _formState.touchedFields
|
|
1982
2379
|
: {},
|
|
2380
|
+
...(!keepStateOptions.keepIsValidating &&
|
|
2381
|
+
(_formState.isValidating || !isEmptyObject(_formState.validatingFields))
|
|
2382
|
+
? { validatingFields: {}, isValidating: false }
|
|
2383
|
+
: null),
|
|
1983
2384
|
errors: keepStateOptions.keepErrors ? _formState.errors : {},
|
|
1984
2385
|
isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
|
|
1985
2386
|
? _formState.isSubmitSuccessful
|
|
@@ -1999,8 +2400,6 @@ function createFormControl(props = {}) {
|
|
|
1999
2400
|
? fieldReference.refs[0]
|
|
2000
2401
|
: fieldReference.ref;
|
|
2001
2402
|
if (fieldRef.focus) {
|
|
2002
|
-
// Use setTimeout to ensure focus happens after any pending state updates
|
|
2003
|
-
// This fixes the issue where setFocus doesn't work immediately after setError
|
|
2004
2403
|
setTimeout(() => {
|
|
2005
2404
|
fieldRef.focus();
|
|
2006
2405
|
options.shouldSelect &&
|
|
@@ -2011,11 +2410,18 @@ function createFormControl(props = {}) {
|
|
|
2011
2410
|
}
|
|
2012
2411
|
};
|
|
2013
2412
|
const _setFormState = (updatedFormState) => {
|
|
2413
|
+
// `name`, `type`, and `values` describe the event that produced this
|
|
2414
|
+
// update, not the form's persisted state (they aren't part of
|
|
2415
|
+
// `FormState`). Merging them in would leak a stale `name`/`type` from
|
|
2416
|
+
// one event into a later, unrelated notification that doesn't specify
|
|
2417
|
+
// its own.
|
|
2418
|
+
const { name, type, values, ...formState } = updatedFormState;
|
|
2014
2419
|
_formState = {
|
|
2015
2420
|
..._formState,
|
|
2016
|
-
...
|
|
2421
|
+
...formState,
|
|
2017
2422
|
};
|
|
2018
2423
|
};
|
|
2424
|
+
_subjects.state.subscribe({ next: _setFormState });
|
|
2019
2425
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
2020
2426
|
_options.defaultValues().then((values) => {
|
|
2021
2427
|
reset(values, _options.resetOptions);
|
|
@@ -2023,6 +2429,21 @@ function createFormControl(props = {}) {
|
|
|
2023
2429
|
isLoading: false,
|
|
2024
2430
|
});
|
|
2025
2431
|
});
|
|
2432
|
+
const resetDefaultValues = (values, options = {}) => {
|
|
2433
|
+
_defaultValues = cloneObject(values);
|
|
2434
|
+
if (!options.keepDirty) {
|
|
2435
|
+
const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
2436
|
+
_formState.dirtyFields = newDirtyFields;
|
|
2437
|
+
_formState.isDirty = !isEmptyObject(newDirtyFields);
|
|
2438
|
+
}
|
|
2439
|
+
if (!options.keepIsValid) {
|
|
2440
|
+
_setValid();
|
|
2441
|
+
}
|
|
2442
|
+
_subjects.state.next({
|
|
2443
|
+
..._formState,
|
|
2444
|
+
defaultValues: _defaultValues,
|
|
2445
|
+
});
|
|
2446
|
+
};
|
|
2026
2447
|
const methods = {
|
|
2027
2448
|
control: {
|
|
2028
2449
|
register,
|
|
@@ -2079,6 +2500,10 @@ function createFormControl(props = {}) {
|
|
|
2079
2500
|
..._options,
|
|
2080
2501
|
...value,
|
|
2081
2502
|
};
|
|
2503
|
+
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2504
|
+
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2505
|
+
shouldDisplayAllAssociatedErrors =
|
|
2506
|
+
_options.criteriaMode === VALIDATION_MODE.all;
|
|
2082
2507
|
},
|
|
2083
2508
|
},
|
|
2084
2509
|
subscribe,
|
|
@@ -2089,8 +2514,10 @@ function createFormControl(props = {}) {
|
|
|
2089
2514
|
setValue,
|
|
2090
2515
|
setValues,
|
|
2091
2516
|
getValues,
|
|
2517
|
+
getErrors,
|
|
2092
2518
|
reset,
|
|
2093
2519
|
resetField,
|
|
2520
|
+
resetDefaultValues,
|
|
2094
2521
|
clearErrors,
|
|
2095
2522
|
unregister,
|
|
2096
2523
|
setError,
|