@vritti/quantum-ui 0.5.3 → 0.5.5
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/LICENSE +21 -0
- package/dist/IconSelect.js +2 -2
- package/dist/UploadFile.js +24 -10
- package/dist/UploadFile.js.map +1 -1
- package/dist/assets/quantum-ui.css +4 -0
- package/dist/field.js +1 -1
- package/dist/field.js.map +1 -1
- package/dist/index.esm.js +1429 -810
- package/dist/index.esm.js.map +1 -1
- package/dist/index37.js +2 -2
- package/dist/lib/components/DataTable/hooks/useDataTable.d.ts +2 -2
- package/dist/lib/components/DataTable/hooks/useDataTable.d.ts.map +1 -1
- package/dist/lib/components/Select/types.d.ts +2 -1
- package/dist/lib/components/Select/types.d.ts.map +1 -1
- package/dist/lib/components/UploadFile/UploadFile.d.ts +1 -1
- package/dist/lib/components/UploadFile/UploadFile.d.ts.map +1 -1
- package/dist/schemas.js +2897 -1035
- package/dist/schemas.js.map +1 -1
- package/dist/shadcn/shadcnForm/form.d.ts +2 -2
- package/dist/shadcn/shadcnForm/form.d.ts.map +1 -1
- package/dist/upload.js +16 -1
- package/dist/upload.js.map +1 -1
- package/dist/useDataTable.js +1 -1
- package/dist/useDataTable.js.map +1 -1
- package/dist/utils/zod.js +4480 -731
- package/dist/utils/zod.js.map +1 -1
- package/dist/youtube.js +23 -38
- package/dist/youtube.js.map +1 -1
- package/package.json +9 -8
package/dist/index.esm.js
CHANGED
|
@@ -2,6 +2,8 @@ import React__default from 'react';
|
|
|
2
2
|
|
|
3
3
|
var isCheckBoxInput = (element) => element.type === 'checkbox';
|
|
4
4
|
|
|
5
|
+
var isFileInput = (element) => element.type === 'file';
|
|
6
|
+
|
|
5
7
|
var isDateObject = (value) => value instanceof Date;
|
|
6
8
|
|
|
7
9
|
var isNullOrUndefined = (value) => value == null;
|
|
@@ -15,23 +17,41 @@ var isObject = (value) => !isNullOrUndefined(value) &&
|
|
|
15
17
|
var getEventValue = (event) => isObject(event) && event.target
|
|
16
18
|
? isCheckBoxInput(event.target)
|
|
17
19
|
? event.target.checked
|
|
18
|
-
: event.target
|
|
20
|
+
: isFileInput(event.target)
|
|
21
|
+
? event.target.files
|
|
22
|
+
: event.target.value
|
|
19
23
|
: event;
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
26
|
+
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
27
|
+
|
|
28
|
+
function getNullAncestorValue(control, name) {
|
|
29
|
+
const segments = stringToPath(name);
|
|
30
|
+
let formValues = control._formValues;
|
|
31
|
+
let defaultValues = control._defaultValues;
|
|
32
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
33
|
+
const key = segments[i];
|
|
34
|
+
formValues = formValues == null ? formValues : formValues[key];
|
|
35
|
+
defaultValues = defaultValues == null ? defaultValues : defaultValues[key];
|
|
36
|
+
if (formValues === null || defaultValues === null) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
24
42
|
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
43
|
+
var isNameInFieldArray = (names, name) => name
|
|
44
|
+
.split('.')
|
|
45
|
+
.some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
|
|
29
46
|
|
|
30
47
|
var isWeb = typeof window !== 'undefined' &&
|
|
31
48
|
typeof window.HTMLElement !== 'undefined' &&
|
|
32
49
|
typeof document !== 'undefined';
|
|
33
50
|
|
|
34
51
|
function cloneObject(data) {
|
|
52
|
+
if (data === null || typeof data !== 'object') {
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
35
55
|
if (data instanceof Date) {
|
|
36
56
|
return new Date(data);
|
|
37
57
|
}
|
|
@@ -40,7 +60,7 @@ function cloneObject(data) {
|
|
|
40
60
|
return data;
|
|
41
61
|
}
|
|
42
62
|
const isArray = Array.isArray(data);
|
|
43
|
-
if (!isArray &&
|
|
63
|
+
if (!isArray && data.constructor !== Object) {
|
|
44
64
|
return data;
|
|
45
65
|
}
|
|
46
66
|
const copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
|
|
@@ -52,19 +72,49 @@ function cloneObject(data) {
|
|
|
52
72
|
return copy;
|
|
53
73
|
}
|
|
54
74
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
75
|
+
const EVENTS = {
|
|
76
|
+
BLUR: 'blur',
|
|
77
|
+
FOCUS_OUT: 'focusout',
|
|
78
|
+
CHANGE: 'change',
|
|
79
|
+
SUBMIT: 'submit',
|
|
80
|
+
TRIGGER: 'trigger',
|
|
81
|
+
VALID: 'valid',
|
|
82
|
+
};
|
|
83
|
+
const VALIDATION_MODE = {
|
|
84
|
+
onBlur: 'onBlur',
|
|
85
|
+
onChange: 'onChange',
|
|
86
|
+
onSubmit: 'onSubmit',
|
|
87
|
+
onTouched: 'onTouched',
|
|
88
|
+
all: 'all',
|
|
89
|
+
};
|
|
90
|
+
const INPUT_VALIDATION_RULES = {
|
|
91
|
+
max: 'max',
|
|
92
|
+
min: 'min',
|
|
93
|
+
maxLength: 'maxLength',
|
|
94
|
+
minLength: 'minLength',
|
|
95
|
+
pattern: 'pattern',
|
|
96
|
+
required: 'required',
|
|
97
|
+
validate: 'validate',
|
|
98
|
+
};
|
|
99
|
+
const ROOT_ERROR_TYPE = 'root';
|
|
100
|
+
const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
|
|
58
101
|
|
|
59
|
-
|
|
102
|
+
const IS_KEY_RE = /^\w*$/;
|
|
103
|
+
var isKey = (value) => IS_KEY_RE.test(value);
|
|
60
104
|
|
|
61
|
-
var
|
|
105
|
+
var isUndefined = (val) => val === undefined;
|
|
62
106
|
|
|
63
107
|
var get = (object, path, defaultValue) => {
|
|
64
108
|
if (!path || !isObject(object)) {
|
|
65
109
|
return defaultValue;
|
|
66
110
|
}
|
|
67
|
-
const
|
|
111
|
+
const paths = isKey(path) ? [path] : stringToPath(path);
|
|
112
|
+
if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
|
|
113
|
+
return defaultValue;
|
|
114
|
+
}
|
|
115
|
+
const result = paths.reduce((result, key) => {
|
|
116
|
+
return isNullOrUndefined(result) ? undefined : result[key];
|
|
117
|
+
}, object);
|
|
68
118
|
return isUndefined(result) || result === object
|
|
69
119
|
? isUndefined(object[path])
|
|
70
120
|
? defaultValue
|
|
@@ -93,7 +143,7 @@ var set = (object, path, value) => {
|
|
|
93
143
|
? []
|
|
94
144
|
: {};
|
|
95
145
|
}
|
|
96
|
-
if (key
|
|
146
|
+
if (PROTOTYPE_KEYWORDS.includes(key)) {
|
|
97
147
|
return;
|
|
98
148
|
}
|
|
99
149
|
object[key] = newValue;
|
|
@@ -101,28 +151,6 @@ var set = (object, path, value) => {
|
|
|
101
151
|
}
|
|
102
152
|
};
|
|
103
153
|
|
|
104
|
-
const EVENTS = {
|
|
105
|
-
BLUR: 'blur',
|
|
106
|
-
FOCUS_OUT: 'focusout',
|
|
107
|
-
CHANGE: 'change',
|
|
108
|
-
};
|
|
109
|
-
const VALIDATION_MODE = {
|
|
110
|
-
onBlur: 'onBlur',
|
|
111
|
-
onChange: 'onChange',
|
|
112
|
-
onSubmit: 'onSubmit',
|
|
113
|
-
onTouched: 'onTouched',
|
|
114
|
-
all: 'all',
|
|
115
|
-
};
|
|
116
|
-
const INPUT_VALIDATION_RULES = {
|
|
117
|
-
max: 'max',
|
|
118
|
-
min: 'min',
|
|
119
|
-
maxLength: 'maxLength',
|
|
120
|
-
minLength: 'minLength',
|
|
121
|
-
pattern: 'pattern',
|
|
122
|
-
required: 'required',
|
|
123
|
-
validate: 'validate',
|
|
124
|
-
};
|
|
125
|
-
|
|
126
154
|
/**
|
|
127
155
|
* Separate context for `control` to prevent unnecessary rerenders.
|
|
128
156
|
* Internal hooks that only need control use this instead of full form context.
|
|
@@ -135,9 +163,7 @@ HookFormControlContext.displayName = 'HookFormControlContext';
|
|
|
135
163
|
const useFormControlContext = () => React__default.useContext(HookFormControlContext);
|
|
136
164
|
|
|
137
165
|
var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
|
|
138
|
-
const result = {
|
|
139
|
-
defaultValues: control._defaultValues,
|
|
140
|
-
};
|
|
166
|
+
const result = {};
|
|
141
167
|
for (const key in formState) {
|
|
142
168
|
Object.defineProperty(result, key, {
|
|
143
169
|
get: () => {
|
|
@@ -153,15 +179,107 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
|
|
|
153
179
|
return result;
|
|
154
180
|
};
|
|
155
181
|
|
|
156
|
-
const useIsomorphicLayoutEffect =
|
|
182
|
+
const useIsomorphicLayoutEffect = isWeb
|
|
183
|
+
? React__default.useLayoutEffect
|
|
184
|
+
: React__default.useEffect;
|
|
185
|
+
|
|
186
|
+
var isPlainObject = (tempObject) => {
|
|
187
|
+
const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
|
|
188
|
+
return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
192
|
+
|
|
193
|
+
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
194
|
+
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
195
|
+
if (object1 === object2) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
199
|
+
return Object.is(object1, object2);
|
|
200
|
+
}
|
|
201
|
+
if (isDateObject(object1) && isDateObject(object2)) {
|
|
202
|
+
return Object.is(object1.getTime(), object2.getTime());
|
|
203
|
+
}
|
|
204
|
+
const keys1 = Object.keys(object1);
|
|
205
|
+
const keys2 = Object.keys(object2);
|
|
206
|
+
if (keys1.length !== keys2.length) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
210
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
211
|
+
return Object.is(object1, object2);
|
|
212
|
+
}
|
|
213
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
const visitedPairs = visited.get(object1);
|
|
217
|
+
if (visitedPairs && visitedPairs.has(object2)) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
if (visitedPairs) {
|
|
221
|
+
visitedPairs.add(object2);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const ws = new WeakSet();
|
|
225
|
+
ws.add(object2);
|
|
226
|
+
visited.set(object1, ws);
|
|
227
|
+
}
|
|
228
|
+
for (const key of keys1) {
|
|
229
|
+
const val1 = object1[key];
|
|
230
|
+
if (!(key in object2)) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
if (key !== 'ref') {
|
|
234
|
+
const val2 = object2[key];
|
|
235
|
+
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
236
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
237
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
238
|
+
? !deepEqual(val1, val2, visited)
|
|
239
|
+
: !Object.is(val1, val2)) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function useResyncOnReconnect(getInitialValue) {
|
|
248
|
+
const _connected = React__default.useRef(false);
|
|
249
|
+
const _initialized = React__default.useRef(false);
|
|
250
|
+
const _prevValue = React__default.useRef(undefined);
|
|
251
|
+
const _renderCount = React__default.useRef(0);
|
|
252
|
+
_renderCount.current++;
|
|
253
|
+
if (!_initialized.current && getInitialValue) {
|
|
254
|
+
_initialized.current = true;
|
|
255
|
+
_prevValue.current = cloneObject(getInitialValue());
|
|
256
|
+
}
|
|
257
|
+
const resyncIfNeeded = React__default.useCallback((enabled, getCurrentValue, setValue) => {
|
|
258
|
+
if (enabled &&
|
|
259
|
+
(_connected.current ||
|
|
260
|
+
(_initialized.current && _renderCount.current > 1))) {
|
|
261
|
+
const currentValue = getCurrentValue();
|
|
262
|
+
if (!deepEqual(_prevValue.current, currentValue)) {
|
|
263
|
+
setValue(currentValue);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
_connected.current = true;
|
|
267
|
+
}, []);
|
|
268
|
+
const snapshot = React__default.useCallback((enabled, getCurrentValue) => {
|
|
269
|
+
if (enabled) {
|
|
270
|
+
_prevValue.current = cloneObject(getCurrentValue());
|
|
271
|
+
}
|
|
272
|
+
}, []);
|
|
273
|
+
return { resyncIfNeeded, snapshot };
|
|
274
|
+
}
|
|
157
275
|
|
|
158
276
|
/**
|
|
159
|
-
*
|
|
277
|
+
* Subscribes to each form state and isolates re-renders at the custom hook level. It has its own scope for form state subscriptions, so it will not affect other useFormState or useForm instances. Using this hook can reduce the re-render impact on large and complex form applications.
|
|
160
278
|
*
|
|
161
279
|
* @remarks
|
|
162
280
|
* [API](https://react-hook-form.com/docs/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
|
|
163
281
|
*
|
|
164
|
-
* @param props -
|
|
282
|
+
* @param props - Include options to specify fields to subscribe to. {@link UseFormStateReturn}
|
|
165
283
|
*
|
|
166
284
|
* @example
|
|
167
285
|
* ```tsx
|
|
@@ -188,7 +306,11 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React__default
|
|
|
188
306
|
function useFormState(props) {
|
|
189
307
|
const formControl = useFormControlContext();
|
|
190
308
|
const { control = formControl, disabled, name, exact } = props || {};
|
|
191
|
-
const
|
|
309
|
+
const getCurrentFormState = () => ({
|
|
310
|
+
...control._formState,
|
|
311
|
+
defaultValues: control._defaultValues,
|
|
312
|
+
});
|
|
313
|
+
const [formState, updateFormState] = React__default.useState(getCurrentFormState);
|
|
192
314
|
const _localProxyFormState = React__default.useRef({
|
|
193
315
|
isDirty: false,
|
|
194
316
|
isLoading: false,
|
|
@@ -199,18 +321,27 @@ function useFormState(props) {
|
|
|
199
321
|
isValid: false,
|
|
200
322
|
errors: false,
|
|
201
323
|
});
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
324
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getCurrentFormState);
|
|
325
|
+
useIsomorphicLayoutEffect(() => {
|
|
326
|
+
resyncIfNeeded(!disabled, getCurrentFormState, updateFormState);
|
|
327
|
+
const unsubscribe = control._subscribe({
|
|
328
|
+
name,
|
|
329
|
+
formState: _localProxyFormState.current,
|
|
330
|
+
exact,
|
|
331
|
+
callback: (formState) => {
|
|
332
|
+
!disabled &&
|
|
333
|
+
updateFormState({
|
|
334
|
+
...control._formState,
|
|
335
|
+
...formState,
|
|
336
|
+
defaultValues: control._defaultValues,
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
return () => {
|
|
341
|
+
unsubscribe();
|
|
342
|
+
snapshot(!disabled, getCurrentFormState);
|
|
343
|
+
};
|
|
344
|
+
}, [name, disabled, exact, resyncIfNeeded, snapshot]);
|
|
214
345
|
React__default.useEffect(() => {
|
|
215
346
|
_localProxyFormState.current.isValid && control._setValid(true);
|
|
216
347
|
}, [control]);
|
|
@@ -226,52 +357,14 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
226
357
|
}
|
|
227
358
|
if (Array.isArray(names)) {
|
|
228
359
|
return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
|
|
229
|
-
get(formValues, fieldName)));
|
|
360
|
+
get(formValues, fieldName, get(defaultValue, fieldName))));
|
|
230
361
|
}
|
|
231
362
|
isGlobal && (_names.watchAll = true);
|
|
232
363
|
return formValues;
|
|
233
364
|
};
|
|
234
365
|
|
|
235
|
-
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
236
|
-
|
|
237
|
-
function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
|
|
238
|
-
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
239
|
-
return Object.is(object1, object2);
|
|
240
|
-
}
|
|
241
|
-
if (isDateObject(object1) && isDateObject(object2)) {
|
|
242
|
-
return Object.is(object1.getTime(), object2.getTime());
|
|
243
|
-
}
|
|
244
|
-
const keys1 = Object.keys(object1);
|
|
245
|
-
const keys2 = Object.keys(object2);
|
|
246
|
-
if (keys1.length !== keys2.length) {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
if (_internal_visited.has(object1) || _internal_visited.has(object2)) {
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
_internal_visited.add(object1);
|
|
253
|
-
_internal_visited.add(object2);
|
|
254
|
-
for (const key of keys1) {
|
|
255
|
-
const val1 = object1[key];
|
|
256
|
-
if (!keys2.includes(key)) {
|
|
257
|
-
return false;
|
|
258
|
-
}
|
|
259
|
-
if (key !== 'ref') {
|
|
260
|
-
const val2 = object2[key];
|
|
261
|
-
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
262
|
-
(isObject(val1) && isObject(val2)) ||
|
|
263
|
-
(Array.isArray(val1) && Array.isArray(val2))
|
|
264
|
-
? !deepEqual(val1, val2, _internal_visited)
|
|
265
|
-
: !Object.is(val1, val2)) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
366
|
/**
|
|
274
|
-
* Custom hook to subscribe to field
|
|
367
|
+
* Custom hook to subscribe to field changes and isolate re-rendering at the component level.
|
|
275
368
|
*
|
|
276
369
|
* @remarks
|
|
277
370
|
*
|
|
@@ -281,7 +374,7 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
|
|
|
281
374
|
* ```tsx
|
|
282
375
|
* const { control } = useForm();
|
|
283
376
|
* const values = useWatch({
|
|
284
|
-
* name: "fieldName"
|
|
377
|
+
* name: "fieldName",
|
|
285
378
|
* control,
|
|
286
379
|
* })
|
|
287
380
|
* ```
|
|
@@ -295,10 +388,11 @@ function useWatch(props) {
|
|
|
295
388
|
const _prevControl = React__default.useRef(control);
|
|
296
389
|
const _prevName = React__default.useRef(name);
|
|
297
390
|
_compute.current = compute;
|
|
298
|
-
const
|
|
391
|
+
const getInitialOutput = () => {
|
|
299
392
|
const defaultValue = control._getWatch(name, _defaultValue.current);
|
|
300
393
|
return _compute.current ? _compute.current(defaultValue) : defaultValue;
|
|
301
|
-
}
|
|
394
|
+
};
|
|
395
|
+
const [value, updateValue] = React__default.useState(getInitialOutput);
|
|
302
396
|
const getCurrentOutput = React__default.useCallback((values) => {
|
|
303
397
|
const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
|
|
304
398
|
return _compute.current ? _compute.current(formValues) : formValues;
|
|
@@ -318,24 +412,39 @@ function useWatch(props) {
|
|
|
318
412
|
}
|
|
319
413
|
}
|
|
320
414
|
}, [control._formValues, control._names, disabled, name]);
|
|
415
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getInitialOutput);
|
|
416
|
+
const _refreshValue = React__default.useRef(refreshValue);
|
|
417
|
+
_refreshValue.current = refreshValue;
|
|
418
|
+
const _getCurrentOutput = React__default.useRef(getCurrentOutput);
|
|
419
|
+
_getCurrentOutput.current = getCurrentOutput;
|
|
321
420
|
useIsomorphicLayoutEffect(() => {
|
|
322
421
|
if (_prevControl.current !== control ||
|
|
323
422
|
!deepEqual(_prevName.current, name)) {
|
|
324
423
|
_prevControl.current = control;
|
|
325
424
|
_prevName.current = name;
|
|
326
|
-
|
|
425
|
+
_refreshValue.current();
|
|
327
426
|
}
|
|
328
|
-
|
|
427
|
+
else {
|
|
428
|
+
resyncIfNeeded(!disabled, () => _getCurrentOutput.current(), (currentValue) => {
|
|
429
|
+
updateValue(currentValue);
|
|
430
|
+
_computeFormValues.current = currentValue;
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
const unsubscribe = control._subscribe({
|
|
329
434
|
name,
|
|
330
435
|
formState: {
|
|
331
436
|
values: true,
|
|
332
437
|
},
|
|
333
438
|
exact,
|
|
334
439
|
callback: (formState) => {
|
|
335
|
-
|
|
440
|
+
_refreshValue.current(formState.values);
|
|
336
441
|
},
|
|
337
442
|
});
|
|
338
|
-
|
|
443
|
+
return () => {
|
|
444
|
+
unsubscribe();
|
|
445
|
+
snapshot(!disabled, () => _getCurrentOutput.current());
|
|
446
|
+
};
|
|
447
|
+
}, [control, exact, name, disabled, resyncIfNeeded, snapshot]);
|
|
339
448
|
React__default.useEffect(() => control._removeUnmounted());
|
|
340
449
|
// If name or control changed for this render, synchronously reflect the
|
|
341
450
|
// latest value so callers (like useController) see the correct value
|
|
@@ -343,17 +452,17 @@ function useWatch(props) {
|
|
|
343
452
|
// Optimize: Check control reference first before expensive deepEqual
|
|
344
453
|
const controlChanged = _prevControl.current !== control;
|
|
345
454
|
const prevName = _prevName.current;
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
|
|
455
|
+
// `null`/`undefined` are valid watched values, so a boolean flag (rather
|
|
456
|
+
// than a sentinel return value) decides whether to return the freshly
|
|
457
|
+
// computed output instead of the possibly-stale state value.
|
|
458
|
+
const shouldReturnImmediate = React__default.useMemo(() => {
|
|
349
459
|
if (disabled) {
|
|
350
|
-
return
|
|
460
|
+
return false;
|
|
351
461
|
}
|
|
352
462
|
const nameChanged = !controlChanged && !deepEqual(prevName, name);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return computedOutput !== null ? computedOutput : value;
|
|
463
|
+
return controlChanged || nameChanged;
|
|
464
|
+
}, [disabled, controlChanged, name, prevName]);
|
|
465
|
+
return shouldReturnImmediate ? getCurrentOutput() : value;
|
|
357
466
|
}
|
|
358
467
|
|
|
359
468
|
/**
|
|
@@ -384,7 +493,12 @@ function useController(props) {
|
|
|
384
493
|
const formControl = useFormControlContext();
|
|
385
494
|
const { name, disabled, control = formControl, shouldUnregister, defaultValue, exact = true, } = props;
|
|
386
495
|
const isArrayField = isNameInFieldArray(control._names.array, name);
|
|
387
|
-
const defaultValueMemo = React__default.useMemo(() =>
|
|
496
|
+
const defaultValueMemo = React__default.useMemo(() => {
|
|
497
|
+
const resolved = get(control._formValues, name, get(control._defaultValues, name, defaultValue));
|
|
498
|
+
return isUndefined(resolved)
|
|
499
|
+
? getNullAncestorValue(control, name)
|
|
500
|
+
: resolved;
|
|
501
|
+
}, [control, name, defaultValue]);
|
|
388
502
|
const value = useWatch({
|
|
389
503
|
control,
|
|
390
504
|
name,
|
|
@@ -397,7 +511,7 @@ function useController(props) {
|
|
|
397
511
|
exact,
|
|
398
512
|
});
|
|
399
513
|
const _props = React__default.useRef(props);
|
|
400
|
-
const
|
|
514
|
+
const _proxyRef = React__default.useRef(null);
|
|
401
515
|
const _registerProps = React__default.useRef(control.register(name, {
|
|
402
516
|
...props.rules,
|
|
403
517
|
value,
|
|
@@ -426,13 +540,22 @@ function useController(props) {
|
|
|
426
540
|
get: () => get(formState.errors, name),
|
|
427
541
|
},
|
|
428
542
|
}), [formState, name]);
|
|
429
|
-
const onChange = React__default.useCallback((event) =>
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
543
|
+
const onChange = React__default.useCallback((event) => {
|
|
544
|
+
const value = getEventValue(event);
|
|
545
|
+
if (!get(control._fields, name)) {
|
|
546
|
+
_registerProps.current = control.register(name, {
|
|
547
|
+
..._props.current.rules,
|
|
548
|
+
value,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
return _registerProps.current.onChange({
|
|
552
|
+
target: {
|
|
553
|
+
value: getEventValue(event),
|
|
554
|
+
name: name,
|
|
555
|
+
},
|
|
556
|
+
type: EVENTS.CHANGE,
|
|
557
|
+
});
|
|
558
|
+
}, [name, control]);
|
|
436
559
|
const onBlur = React__default.useCallback(() => _registerProps.current.onBlur({
|
|
437
560
|
target: {
|
|
438
561
|
value: get(control._formValues, name),
|
|
@@ -441,15 +564,18 @@ function useController(props) {
|
|
|
441
564
|
type: EVENTS.BLUR,
|
|
442
565
|
}), [name, control._formValues]);
|
|
443
566
|
const ref = React__default.useCallback((elm) => {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
field._f.ref = {
|
|
567
|
+
if (elm) {
|
|
568
|
+
_proxyRef.current = {
|
|
447
569
|
focus: () => isFunction(elm.focus) && elm.focus(),
|
|
448
570
|
select: () => isFunction(elm.select) && elm.select(),
|
|
449
571
|
setCustomValidity: (message) => isFunction(elm.setCustomValidity) && elm.setCustomValidity(message),
|
|
450
572
|
reportValidity: () => isFunction(elm.reportValidity) && elm.reportValidity(),
|
|
451
573
|
};
|
|
452
574
|
}
|
|
575
|
+
const field = get(control._fields, name);
|
|
576
|
+
if (field && field._f && elm) {
|
|
577
|
+
field._f.ref = _proxyRef.current;
|
|
578
|
+
}
|
|
453
579
|
}, [control._fields, name]);
|
|
454
580
|
const field = React__default.useMemo(() => ({
|
|
455
581
|
name,
|
|
@@ -463,11 +589,7 @@ function useController(props) {
|
|
|
463
589
|
}), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
|
|
464
590
|
React__default.useEffect(() => {
|
|
465
591
|
const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
|
|
466
|
-
|
|
467
|
-
if (previousName && previousName !== name && !isArrayField) {
|
|
468
|
-
control.unregister(previousName);
|
|
469
|
-
}
|
|
470
|
-
control.register(name, {
|
|
592
|
+
_registerProps.current = control.register(name, {
|
|
471
593
|
..._props.current.rules,
|
|
472
594
|
...(isBoolean(_props.current.disabled)
|
|
473
595
|
? { disabled: _props.current.disabled }
|
|
@@ -481,14 +603,21 @@ function useController(props) {
|
|
|
481
603
|
};
|
|
482
604
|
updateMounted(name, true);
|
|
483
605
|
if (_shouldUnregisterField) {
|
|
484
|
-
const value = cloneObject(get(
|
|
606
|
+
const value = cloneObject(get(shouldUnregister
|
|
607
|
+
? control._defaultValues
|
|
608
|
+
: control._options.values || control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
|
|
485
609
|
set(control._defaultValues, name, value);
|
|
486
610
|
if (isUndefined(get(control._formValues, name))) {
|
|
487
611
|
set(control._formValues, name, value);
|
|
488
612
|
}
|
|
489
613
|
}
|
|
490
614
|
!isArrayField && control.register(name);
|
|
491
|
-
|
|
615
|
+
if (_proxyRef.current) {
|
|
616
|
+
const field = get(control._fields, name);
|
|
617
|
+
if (field && field._f) {
|
|
618
|
+
field._f.ref = _proxyRef.current;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
492
621
|
return () => {
|
|
493
622
|
(isArrayField
|
|
494
623
|
? _shouldUnregisterField && !control._state.action
|
|
@@ -554,95 +683,472 @@ function useController(props) {
|
|
|
554
683
|
*/
|
|
555
684
|
const Controller = (props) => props.render(useController(props));
|
|
556
685
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
*
|
|
565
|
-
* @param props - all useForm methods
|
|
566
|
-
*
|
|
567
|
-
* @example
|
|
568
|
-
* ```tsx
|
|
569
|
-
* function App() {
|
|
570
|
-
* const methods = useForm();
|
|
571
|
-
* const onSubmit = data => console.log(data);
|
|
572
|
-
*
|
|
573
|
-
* return (
|
|
574
|
-
* <FormProvider {...methods} >
|
|
575
|
-
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
576
|
-
* <NestedInput />
|
|
577
|
-
* <input type="submit" />
|
|
578
|
-
* </form>
|
|
579
|
-
* </FormProvider>
|
|
580
|
-
* );
|
|
581
|
-
* }
|
|
582
|
-
*
|
|
583
|
-
* function NestedInput() {
|
|
584
|
-
* const { register } = useFormContext(); // retrieve all hook methods
|
|
585
|
-
* return <input {...register("test")} />;
|
|
586
|
-
* }
|
|
587
|
-
* ```
|
|
588
|
-
*/
|
|
589
|
-
const FormProvider = (props) => {
|
|
590
|
-
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
591
|
-
return (React__default.createElement(HookFormContext.Provider, { value: React__default.useMemo(() => ({
|
|
592
|
-
watch,
|
|
593
|
-
getValues,
|
|
594
|
-
getFieldState,
|
|
595
|
-
setError,
|
|
596
|
-
clearErrors,
|
|
597
|
-
setValue,
|
|
598
|
-
trigger,
|
|
599
|
-
formState,
|
|
600
|
-
resetField,
|
|
601
|
-
reset,
|
|
602
|
-
handleSubmit,
|
|
603
|
-
unregister,
|
|
604
|
-
control,
|
|
605
|
-
register,
|
|
606
|
-
setFocus,
|
|
607
|
-
subscribe,
|
|
608
|
-
}), [
|
|
609
|
-
clearErrors,
|
|
610
|
-
control,
|
|
611
|
-
formState,
|
|
612
|
-
getFieldState,
|
|
613
|
-
getValues,
|
|
614
|
-
handleSubmit,
|
|
615
|
-
register,
|
|
616
|
-
reset,
|
|
617
|
-
resetField,
|
|
618
|
-
setError,
|
|
619
|
-
setFocus,
|
|
620
|
-
setValue,
|
|
621
|
-
subscribe,
|
|
622
|
-
trigger,
|
|
623
|
-
unregister,
|
|
624
|
-
watch,
|
|
625
|
-
]) },
|
|
626
|
-
React__default.createElement(HookFormControlContext.Provider, { value: control }, children)));
|
|
627
|
-
};
|
|
686
|
+
var getValidationModes = (mode) => ({
|
|
687
|
+
isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
|
|
688
|
+
isOnBlur: mode === VALIDATION_MODE.onBlur,
|
|
689
|
+
isOnChange: mode === VALIDATION_MODE.onChange,
|
|
690
|
+
isOnAll: mode === VALIDATION_MODE.all,
|
|
691
|
+
isOnTouch: mode === VALIDATION_MODE.onTouched,
|
|
692
|
+
});
|
|
628
693
|
|
|
629
|
-
var
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
694
|
+
var isWatched = (name, _names, isBlurEvent) => {
|
|
695
|
+
if (isBlurEvent)
|
|
696
|
+
return false;
|
|
697
|
+
if (_names.watchAll || _names.watch.has(name))
|
|
698
|
+
return true;
|
|
699
|
+
for (const watchName of _names.watch) {
|
|
700
|
+
if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
|
|
701
|
+
return true;
|
|
636
702
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
|
|
703
|
+
return false;
|
|
704
|
+
};
|
|
640
705
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
706
|
+
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
707
|
+
for (const key of fieldsNames || Object.keys(fields)) {
|
|
708
|
+
if (key === '_f') {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const field = fieldsNames ? get(fields, key) : fields[key];
|
|
712
|
+
if (field) {
|
|
713
|
+
const { _f } = field;
|
|
714
|
+
if (_f) {
|
|
715
|
+
if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
if (iterateFieldsByAction(field, action)) {
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
else if (isObject(field) || Array.isArray(field)) {
|
|
728
|
+
if (iterateFieldsByAction(field, action)) {
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
var updateFieldArrayRootError = (errors, error, name) => {
|
|
738
|
+
const existingErrors = get(errors, name);
|
|
739
|
+
const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
|
|
740
|
+
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
741
|
+
set(errors, name, fieldArrayErrors);
|
|
742
|
+
return errors;
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
|
|
746
|
+
|
|
747
|
+
var isHTMLElement = (value) => {
|
|
748
|
+
if (!isWeb) {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
const owner = value ? value.ownerDocument : 0;
|
|
752
|
+
return (value instanceof
|
|
753
|
+
(owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement));
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
var isRadioInput = (element) => element.type === 'radio';
|
|
757
|
+
|
|
758
|
+
var isRegex = (value) => value instanceof RegExp;
|
|
759
|
+
|
|
760
|
+
var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
|
|
761
|
+
? {
|
|
762
|
+
...errors[name],
|
|
763
|
+
types: {
|
|
764
|
+
...(errors[name] && errors[name].types ? errors[name].types : {}),
|
|
765
|
+
[type]: message || true,
|
|
766
|
+
},
|
|
767
|
+
}
|
|
768
|
+
: {};
|
|
769
|
+
|
|
770
|
+
const defaultResult = {
|
|
771
|
+
value: false,
|
|
772
|
+
isValid: false,
|
|
773
|
+
};
|
|
774
|
+
const validResult = { value: true, isValid: true };
|
|
775
|
+
var getCheckboxValue = (options) => {
|
|
776
|
+
if (!Array.isArray(options)) {
|
|
777
|
+
return defaultResult;
|
|
778
|
+
}
|
|
779
|
+
if (options.length > 1) {
|
|
780
|
+
const values = options
|
|
781
|
+
.filter((option) => option && option.checked && !option.disabled)
|
|
782
|
+
.map((option) => option.value);
|
|
783
|
+
return { value: values, isValid: !!values.length };
|
|
784
|
+
}
|
|
785
|
+
const option = options[0];
|
|
786
|
+
if (!option || !option.checked || option.disabled) {
|
|
787
|
+
return defaultResult;
|
|
788
|
+
}
|
|
789
|
+
if (!option.attributes || !('value' in option.attributes)) {
|
|
790
|
+
return validResult;
|
|
791
|
+
}
|
|
792
|
+
return isUndefined(option.value) || option.value === ''
|
|
793
|
+
? validResult
|
|
794
|
+
: { value: option.value, isValid: true };
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
const defaultReturn = {
|
|
798
|
+
isValid: false,
|
|
799
|
+
value: null,
|
|
800
|
+
};
|
|
801
|
+
var getRadioValue = (options) => Array.isArray(options)
|
|
802
|
+
? options.reduce((previous, option) => option && option.checked && !option.disabled
|
|
803
|
+
? {
|
|
804
|
+
isValid: true,
|
|
805
|
+
value: option.value,
|
|
806
|
+
}
|
|
807
|
+
: previous, defaultReturn)
|
|
808
|
+
: defaultReturn;
|
|
809
|
+
|
|
810
|
+
function getValidateError(result, ref, type = 'validate') {
|
|
811
|
+
if (isString(result) ||
|
|
812
|
+
(Array.isArray(result) && result.every(isString)) ||
|
|
813
|
+
(isBoolean(result) && !result)) {
|
|
814
|
+
return {
|
|
815
|
+
type,
|
|
816
|
+
message: isString(result) ? result : '',
|
|
817
|
+
ref,
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
var getValueAndMessage = (validationData) => isObject(validationData) && !isRegex(validationData)
|
|
823
|
+
? validationData
|
|
824
|
+
: {
|
|
825
|
+
value: validationData,
|
|
826
|
+
message: '',
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
|
|
830
|
+
const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f;
|
|
831
|
+
const inputValue = get(formValues, name);
|
|
832
|
+
if (!mount || disabledFieldNames.has(name)) {
|
|
833
|
+
return {};
|
|
834
|
+
}
|
|
835
|
+
const inputRef = refs ? refs[0] : ref;
|
|
836
|
+
const setCustomValidity = (message) => {
|
|
837
|
+
if (shouldUseNativeValidation && inputRef.reportValidity) {
|
|
838
|
+
const validityMessage = isBoolean(message) ? '' : message || '';
|
|
839
|
+
if (refs) {
|
|
840
|
+
refs.forEach((ref) => ref.setCustomValidity(validityMessage));
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
inputRef.setCustomValidity(validityMessage);
|
|
844
|
+
}
|
|
845
|
+
inputRef.reportValidity();
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
const error = {};
|
|
849
|
+
const isRadio = isRadioInput(ref);
|
|
850
|
+
const isCheckBox = isCheckBoxInput(ref);
|
|
851
|
+
const isRadioOrCheckbox = isRadio || isCheckBox;
|
|
852
|
+
const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
|
|
853
|
+
isUndefined(ref.value) &&
|
|
854
|
+
isUndefined(inputValue)) ||
|
|
855
|
+
(isHTMLElement(ref) && ref.value === '') ||
|
|
856
|
+
inputValue === '' ||
|
|
857
|
+
(Array.isArray(inputValue) && !inputValue.length);
|
|
858
|
+
const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
|
|
859
|
+
const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
|
|
860
|
+
const message = exceedMax ? maxLengthMessage : minLengthMessage;
|
|
861
|
+
error[name] = {
|
|
862
|
+
type: exceedMax ? maxType : minType,
|
|
863
|
+
message,
|
|
864
|
+
ref,
|
|
865
|
+
...appendErrorsCurry(exceedMax ? maxType : minType, message),
|
|
866
|
+
};
|
|
867
|
+
};
|
|
868
|
+
if (isFieldArray
|
|
869
|
+
? !Array.isArray(inputValue) || !inputValue.length
|
|
870
|
+
: required &&
|
|
871
|
+
((!isRadioOrCheckbox && (isEmpty || isNullOrUndefined(inputValue))) ||
|
|
872
|
+
(isBoolean(inputValue) && !inputValue) ||
|
|
873
|
+
(isCheckBox && !getCheckboxValue(refs).isValid) ||
|
|
874
|
+
(isRadio && !getRadioValue(refs).isValid))) {
|
|
875
|
+
const { value, message } = isString(required)
|
|
876
|
+
? { value: !!required, message: required }
|
|
877
|
+
: getValueAndMessage(required);
|
|
878
|
+
if (value) {
|
|
879
|
+
error[name] = {
|
|
880
|
+
type: INPUT_VALIDATION_RULES.required,
|
|
881
|
+
message,
|
|
882
|
+
ref: inputRef,
|
|
883
|
+
...appendErrorsCurry(INPUT_VALIDATION_RULES.required, message),
|
|
884
|
+
};
|
|
885
|
+
if (!validateAllFieldCriteria) {
|
|
886
|
+
setCustomValidity(message);
|
|
887
|
+
return error;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (!isEmpty && (!isNullOrUndefined(min) || !isNullOrUndefined(max))) {
|
|
892
|
+
let exceedMax;
|
|
893
|
+
let exceedMin;
|
|
894
|
+
const maxOutput = getValueAndMessage(max);
|
|
895
|
+
const minOutput = getValueAndMessage(min);
|
|
896
|
+
if (!isNullOrUndefined(inputValue) &&
|
|
897
|
+
!isDateObject(inputValue) &&
|
|
898
|
+
!isNaN(inputValue)) {
|
|
899
|
+
const valueNumber = ref.valueAsNumber ||
|
|
900
|
+
(inputValue ? +inputValue : inputValue);
|
|
901
|
+
if (!isNullOrUndefined(maxOutput.value)) {
|
|
902
|
+
exceedMax = valueNumber > maxOutput.value;
|
|
903
|
+
}
|
|
904
|
+
if (!isNullOrUndefined(minOutput.value)) {
|
|
905
|
+
exceedMin = valueNumber < minOutput.value;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
909
|
+
const valueDate = ref.valueAsDate || new Date(inputValue);
|
|
910
|
+
const convertTimeToDate = (time) => new Date(new Date().toDateString() + ' ' + time);
|
|
911
|
+
const isTime = ref.type == 'time';
|
|
912
|
+
const isWeek = ref.type == 'week';
|
|
913
|
+
if (isString(maxOutput.value) && inputValue) {
|
|
914
|
+
exceedMax = isTime
|
|
915
|
+
? convertTimeToDate(inputValue) > convertTimeToDate(maxOutput.value)
|
|
916
|
+
: isWeek
|
|
917
|
+
? inputValue > maxOutput.value
|
|
918
|
+
: valueDate > new Date(maxOutput.value);
|
|
919
|
+
}
|
|
920
|
+
if (isString(minOutput.value) && inputValue) {
|
|
921
|
+
exceedMin = isTime
|
|
922
|
+
? convertTimeToDate(inputValue) < convertTimeToDate(minOutput.value)
|
|
923
|
+
: isWeek
|
|
924
|
+
? inputValue < minOutput.value
|
|
925
|
+
: valueDate < new Date(minOutput.value);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
if (exceedMax || exceedMin) {
|
|
929
|
+
getMinMaxMessage(!!exceedMax, maxOutput.message, minOutput.message, INPUT_VALIDATION_RULES.max, INPUT_VALIDATION_RULES.min);
|
|
930
|
+
if (!validateAllFieldCriteria) {
|
|
931
|
+
setCustomValidity(error[name].message);
|
|
932
|
+
return error;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
if ((maxLength || minLength) &&
|
|
937
|
+
!isEmpty &&
|
|
938
|
+
(isString(inputValue) || (isFieldArray && Array.isArray(inputValue)))) {
|
|
939
|
+
const maxLengthOutput = getValueAndMessage(maxLength);
|
|
940
|
+
const minLengthOutput = getValueAndMessage(minLength);
|
|
941
|
+
const exceedMax = !isNullOrUndefined(maxLengthOutput.value) &&
|
|
942
|
+
inputValue.length > +maxLengthOutput.value;
|
|
943
|
+
const exceedMin = !isNullOrUndefined(minLengthOutput.value) &&
|
|
944
|
+
inputValue.length < +minLengthOutput.value;
|
|
945
|
+
if (exceedMax || exceedMin) {
|
|
946
|
+
getMinMaxMessage(exceedMax, maxLengthOutput.message, minLengthOutput.message);
|
|
947
|
+
if (!validateAllFieldCriteria) {
|
|
948
|
+
setCustomValidity(error[name].message);
|
|
949
|
+
return error;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
if (pattern && !isEmpty && isString(inputValue)) {
|
|
954
|
+
const { value: patternValue, message } = getValueAndMessage(pattern);
|
|
955
|
+
if (isRegex(patternValue) && !inputValue.match(patternValue)) {
|
|
956
|
+
error[name] = {
|
|
957
|
+
type: INPUT_VALIDATION_RULES.pattern,
|
|
958
|
+
message,
|
|
959
|
+
ref,
|
|
960
|
+
...appendErrorsCurry(INPUT_VALIDATION_RULES.pattern, message),
|
|
961
|
+
};
|
|
962
|
+
if (!validateAllFieldCriteria) {
|
|
963
|
+
setCustomValidity(message);
|
|
964
|
+
return error;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (validate) {
|
|
969
|
+
if (isFunction(validate)) {
|
|
970
|
+
const result = await validate(inputValue, formValues);
|
|
971
|
+
const validateError = getValidateError(result, inputRef);
|
|
972
|
+
if (validateError) {
|
|
973
|
+
error[name] = {
|
|
974
|
+
...validateError,
|
|
975
|
+
...appendErrorsCurry(INPUT_VALIDATION_RULES.validate, validateError.message),
|
|
976
|
+
};
|
|
977
|
+
if (!validateAllFieldCriteria) {
|
|
978
|
+
setCustomValidity(validateError.message);
|
|
979
|
+
return error;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
else if (isObject(validate)) {
|
|
984
|
+
let validationResult = {};
|
|
985
|
+
for (const key in validate) {
|
|
986
|
+
if (!isEmptyObject(validationResult) && !validateAllFieldCriteria) {
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
const validateError = getValidateError(await validate[key](inputValue, formValues), inputRef, key);
|
|
990
|
+
if (validateError) {
|
|
991
|
+
validationResult = {
|
|
992
|
+
...validateError,
|
|
993
|
+
...appendErrorsCurry(key, validateError.message),
|
|
994
|
+
};
|
|
995
|
+
setCustomValidity(validateError.message);
|
|
996
|
+
if (validateAllFieldCriteria) {
|
|
997
|
+
error[name] = validationResult;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
if (!isEmptyObject(validationResult)) {
|
|
1002
|
+
error[name] = {
|
|
1003
|
+
ref: inputRef,
|
|
1004
|
+
...validationResult,
|
|
1005
|
+
};
|
|
1006
|
+
if (!validateAllFieldCriteria) {
|
|
1007
|
+
return error;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const fieldError = error[name];
|
|
1013
|
+
setCustomValidity(fieldError ? fieldError.message : true);
|
|
1014
|
+
return error;
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
|
|
1018
|
+
|
|
1019
|
+
var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
|
|
1020
|
+
|
|
1021
|
+
function baseGet(object, updatePath) {
|
|
1022
|
+
const length = updatePath.length - 1;
|
|
1023
|
+
let index = 0;
|
|
1024
|
+
while (index < length) {
|
|
1025
|
+
if (isNullOrUndefined(object)) {
|
|
1026
|
+
object = undefined;
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1029
|
+
object = object[updatePath[index]];
|
|
1030
|
+
index++;
|
|
1031
|
+
}
|
|
1032
|
+
return object;
|
|
1033
|
+
}
|
|
1034
|
+
function isEmptyArray(obj) {
|
|
1035
|
+
for (const key in obj) {
|
|
1036
|
+
if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
function unset(object, path) {
|
|
1043
|
+
if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
|
|
1044
|
+
delete object[path];
|
|
1045
|
+
return object;
|
|
1046
|
+
}
|
|
1047
|
+
const paths = Array.isArray(path)
|
|
1048
|
+
? path
|
|
1049
|
+
: isKey(path)
|
|
1050
|
+
? [path]
|
|
1051
|
+
: stringToPath(path);
|
|
1052
|
+
if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
|
|
1053
|
+
return object;
|
|
1054
|
+
}
|
|
1055
|
+
const childObject = paths.length === 1 ? object : baseGet(object, paths);
|
|
1056
|
+
const index = paths.length - 1;
|
|
1057
|
+
const key = paths[index];
|
|
1058
|
+
if (childObject) {
|
|
1059
|
+
delete childObject[key];
|
|
1060
|
+
}
|
|
1061
|
+
if (index !== 0 &&
|
|
1062
|
+
((isObject(childObject) && isEmptyObject(childObject)) ||
|
|
1063
|
+
(Array.isArray(childObject) && isEmptyArray(childObject)))) {
|
|
1064
|
+
unset(object, paths.slice(0, -1));
|
|
1065
|
+
}
|
|
1066
|
+
return object;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
const HookFormContext = React__default.createContext(null);
|
|
1070
|
+
HookFormContext.displayName = 'HookFormContext';
|
|
1071
|
+
/**
|
|
1072
|
+
* A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
|
|
1073
|
+
*
|
|
1074
|
+
* @remarks
|
|
1075
|
+
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
1076
|
+
*
|
|
1077
|
+
* @param props - all useForm methods
|
|
1078
|
+
*
|
|
1079
|
+
* @example
|
|
1080
|
+
* ```tsx
|
|
1081
|
+
* function App() {
|
|
1082
|
+
* const methods = useForm();
|
|
1083
|
+
* const onSubmit = data => console.log(data);
|
|
1084
|
+
*
|
|
1085
|
+
* return (
|
|
1086
|
+
* <FormProvider {...methods} >
|
|
1087
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
1088
|
+
* <NestedInput />
|
|
1089
|
+
* <input type="submit" />
|
|
1090
|
+
* </form>
|
|
1091
|
+
* </FormProvider>
|
|
1092
|
+
* );
|
|
1093
|
+
* }
|
|
1094
|
+
*
|
|
1095
|
+
* function NestedInput() {
|
|
1096
|
+
* const { register } = useFormContext(); // retrieve all hook methods
|
|
1097
|
+
* return <input {...register("test")} />;
|
|
1098
|
+
* }
|
|
1099
|
+
* ```
|
|
1100
|
+
*/
|
|
1101
|
+
const FormProvider = ({ children, watch, getValues, getErrors, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
|
|
1102
|
+
const memoizedValue = React__default.useMemo(() => ({
|
|
1103
|
+
watch,
|
|
1104
|
+
getValues,
|
|
1105
|
+
getErrors,
|
|
1106
|
+
getFieldState,
|
|
1107
|
+
setError,
|
|
1108
|
+
clearErrors,
|
|
1109
|
+
setValue,
|
|
1110
|
+
setValues,
|
|
1111
|
+
trigger,
|
|
1112
|
+
formState,
|
|
1113
|
+
resetField,
|
|
1114
|
+
reset,
|
|
1115
|
+
resetDefaultValues,
|
|
1116
|
+
handleSubmit,
|
|
1117
|
+
unregister,
|
|
1118
|
+
control,
|
|
1119
|
+
register,
|
|
1120
|
+
setFocus,
|
|
1121
|
+
subscribe,
|
|
1122
|
+
}), [
|
|
1123
|
+
clearErrors,
|
|
1124
|
+
control,
|
|
1125
|
+
formState,
|
|
1126
|
+
getErrors,
|
|
1127
|
+
getFieldState,
|
|
1128
|
+
getValues,
|
|
1129
|
+
handleSubmit,
|
|
1130
|
+
register,
|
|
1131
|
+
reset,
|
|
1132
|
+
resetDefaultValues,
|
|
1133
|
+
resetField,
|
|
1134
|
+
setError,
|
|
1135
|
+
setFocus,
|
|
1136
|
+
setValue,
|
|
1137
|
+
setValues,
|
|
1138
|
+
subscribe,
|
|
1139
|
+
trigger,
|
|
1140
|
+
unregister,
|
|
1141
|
+
watch,
|
|
1142
|
+
]);
|
|
1143
|
+
return (React__default.createElement(HookFormContext.Provider, { value: memoizedValue },
|
|
1144
|
+
React__default.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
var createSubject = () => {
|
|
1148
|
+
let _observers = [];
|
|
1149
|
+
const next = (value) => {
|
|
1150
|
+
for (const observer of _observers) {
|
|
1151
|
+
observer.next && observer.next(value);
|
|
646
1152
|
}
|
|
647
1153
|
};
|
|
648
1154
|
const subscribe = (observer) => {
|
|
@@ -686,61 +1192,46 @@ function extractFormValues(fieldsState, formValues) {
|
|
|
686
1192
|
return values;
|
|
687
1193
|
}
|
|
688
1194
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
if (!isWeb) {
|
|
1195
|
+
const hasOwn = (value, key) => value !== null &&
|
|
1196
|
+
isObjectType(value) &&
|
|
1197
|
+
Object.prototype.hasOwnProperty.call(value, key);
|
|
1198
|
+
var has = (object, path) => {
|
|
1199
|
+
if (!path) {
|
|
695
1200
|
return false;
|
|
696
1201
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
(
|
|
1202
|
+
let result = object;
|
|
1203
|
+
for (const key of isKey(path) ? [path] : stringToPath(path)) {
|
|
1204
|
+
if (!hasOwn(result, key)) {
|
|
1205
|
+
// `get` also resolves a path held as a single literal key, eg `{ 'a.b': 1 }`
|
|
1206
|
+
return hasOwn(object, path);
|
|
1207
|
+
}
|
|
1208
|
+
result = result[key];
|
|
1209
|
+
}
|
|
1210
|
+
return true;
|
|
700
1211
|
};
|
|
701
1212
|
|
|
702
1213
|
var isMultipleSelect = (element) => element.type === `select-multiple`;
|
|
703
1214
|
|
|
704
|
-
var isRadioInput = (element) => element.type === 'radio';
|
|
705
|
-
|
|
706
1215
|
var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
|
|
707
1216
|
|
|
708
1217
|
var live = (ref) => isHTMLElement(ref) && ref.isConnected;
|
|
709
1218
|
|
|
710
|
-
function
|
|
711
|
-
|
|
712
|
-
let index = 0;
|
|
713
|
-
while (index < length) {
|
|
714
|
-
object = isUndefined(object) ? index++ : object[updatePath[index++]];
|
|
715
|
-
}
|
|
716
|
-
return object;
|
|
1219
|
+
function isDirtyContainer(value) {
|
|
1220
|
+
return Array.isArray(value) || isObject(value);
|
|
717
1221
|
}
|
|
718
|
-
function
|
|
719
|
-
for (const key in
|
|
720
|
-
|
|
721
|
-
|
|
1222
|
+
function collectDirtyFieldNames(dirtyTree, cachedDirtyFields, prefix = '', names = []) {
|
|
1223
|
+
for (const key in dirtyTree) {
|
|
1224
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1225
|
+
const value = dirtyTree[key];
|
|
1226
|
+
if (isDirtyContainer(value) &&
|
|
1227
|
+
isDirtyContainer(get(cachedDirtyFields, path))) {
|
|
1228
|
+
collectDirtyFieldNames(value, cachedDirtyFields, path, names);
|
|
1229
|
+
}
|
|
1230
|
+
else {
|
|
1231
|
+
names.push(path);
|
|
722
1232
|
}
|
|
723
1233
|
}
|
|
724
|
-
return
|
|
725
|
-
}
|
|
726
|
-
function unset(object, path) {
|
|
727
|
-
const paths = Array.isArray(path)
|
|
728
|
-
? path
|
|
729
|
-
: isKey(path)
|
|
730
|
-
? [path]
|
|
731
|
-
: stringToPath(path);
|
|
732
|
-
const childObject = paths.length === 1 ? object : baseGet(object, paths);
|
|
733
|
-
const index = paths.length - 1;
|
|
734
|
-
const key = paths[index];
|
|
735
|
-
if (childObject) {
|
|
736
|
-
delete childObject[key];
|
|
737
|
-
}
|
|
738
|
-
if (index !== 0 &&
|
|
739
|
-
((isObject(childObject) && isEmptyObject(childObject)) ||
|
|
740
|
-
(Array.isArray(childObject) && isEmptyArray(childObject)))) {
|
|
741
|
-
unset(object, paths.slice(0, -1));
|
|
742
|
-
}
|
|
743
|
-
return object;
|
|
1234
|
+
return names;
|
|
744
1235
|
}
|
|
745
1236
|
|
|
746
1237
|
var objectHasFunction = (data) => {
|
|
@@ -755,12 +1246,33 @@ var objectHasFunction = (data) => {
|
|
|
755
1246
|
function isTraversable(value) {
|
|
756
1247
|
return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
|
|
757
1248
|
}
|
|
758
|
-
function
|
|
1249
|
+
function isRegisteredLeaf(fieldRef) {
|
|
1250
|
+
return !!(fieldRef && '_f' in fieldRef);
|
|
1251
|
+
}
|
|
1252
|
+
function isEmptyDirtyContainer(value) {
|
|
1253
|
+
return Array.isArray(value)
|
|
1254
|
+
? !value.some((item) => !isUndefined(item))
|
|
1255
|
+
: !Object.keys(value).length;
|
|
1256
|
+
}
|
|
1257
|
+
function clearDirtyField(container, key) {
|
|
1258
|
+
if (Array.isArray(container)) {
|
|
1259
|
+
container[key] = undefined;
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
delete container[key];
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
function markFieldsDirty(data, fields = {}, fieldRefs) {
|
|
759
1266
|
for (const key in data) {
|
|
760
1267
|
const value = data[key];
|
|
761
|
-
|
|
1268
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
1269
|
+
if (isTraversable(value) &&
|
|
1270
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
762
1271
|
fields[key] = Array.isArray(value) ? [] : {};
|
|
763
|
-
markFieldsDirty(value, fields[key]);
|
|
1272
|
+
markFieldsDirty(value, fields[key], fieldRef);
|
|
1273
|
+
if (isEmptyDirtyContainer(fields[key])) {
|
|
1274
|
+
clearDirtyField(fields, key);
|
|
1275
|
+
}
|
|
764
1276
|
}
|
|
765
1277
|
else if (!isUndefined(value)) {
|
|
766
1278
|
fields[key] = true;
|
|
@@ -768,51 +1280,45 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
768
1280
|
}
|
|
769
1281
|
return fields;
|
|
770
1282
|
}
|
|
771
|
-
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
1283
|
+
function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
|
|
772
1284
|
if (!dirtyFieldsFromValues) {
|
|
773
|
-
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
1285
|
+
dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
|
|
774
1286
|
}
|
|
775
1287
|
for (const key in data) {
|
|
776
1288
|
const value = data[key];
|
|
777
|
-
|
|
1289
|
+
const fieldRef = fieldRefs && fieldRefs[key];
|
|
1290
|
+
if (isTraversable(value) &&
|
|
1291
|
+
(!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
|
|
778
1292
|
if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
|
|
779
|
-
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
|
|
1293
|
+
dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
|
|
780
1294
|
}
|
|
781
1295
|
else {
|
|
782
|
-
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
|
|
1296
|
+
getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
|
|
783
1297
|
}
|
|
1298
|
+
if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
|
|
1299
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
else if (deepEqual(value, formValues[key])) {
|
|
1303
|
+
clearDirtyField(dirtyFieldsFromValues, key);
|
|
784
1304
|
}
|
|
785
1305
|
else {
|
|
786
|
-
|
|
787
|
-
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
1306
|
+
dirtyFieldsFromValues[key] = true;
|
|
788
1307
|
}
|
|
789
1308
|
}
|
|
790
1309
|
return dirtyFieldsFromValues;
|
|
791
1310
|
}
|
|
792
1311
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
.map((option) => option.value);
|
|
804
|
-
return { value: values, isValid: !!values.length };
|
|
805
|
-
}
|
|
806
|
-
return options[0].checked && !options[0].disabled
|
|
807
|
-
? // @ts-expect-error expected to work in the browser
|
|
808
|
-
options[0].attributes && !isUndefined(options[0].attributes.value)
|
|
809
|
-
? isUndefined(options[0].value) || options[0].value === ''
|
|
810
|
-
? validResult
|
|
811
|
-
: { value: options[0].value, isValid: true }
|
|
812
|
-
: validResult
|
|
813
|
-
: defaultResult;
|
|
814
|
-
}
|
|
815
|
-
return defaultResult;
|
|
1312
|
+
var getFieldArrayItemNames = (names, name) => {
|
|
1313
|
+
const segments = name.split('.');
|
|
1314
|
+
const matches = [];
|
|
1315
|
+
let prefix = segments[0];
|
|
1316
|
+
for (let i = 1; i < segments.length; prefix += '.' + segments[i++]) {
|
|
1317
|
+
if (!isNaN(+segments[i]) && names.has(prefix)) {
|
|
1318
|
+
matches.push(`${prefix}.${segments[i]}`);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
return matches;
|
|
816
1322
|
};
|
|
817
1323
|
|
|
818
1324
|
var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
|
|
@@ -829,19 +1335,6 @@ var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isU
|
|
|
829
1335
|
? setValueAs(value)
|
|
830
1336
|
: value;
|
|
831
1337
|
|
|
832
|
-
const defaultReturn = {
|
|
833
|
-
isValid: false,
|
|
834
|
-
value: null,
|
|
835
|
-
};
|
|
836
|
-
var getRadioValue = (options) => Array.isArray(options)
|
|
837
|
-
? options.reduce((previous, option) => option && option.checked && !option.disabled
|
|
838
|
-
? {
|
|
839
|
-
isValid: true,
|
|
840
|
-
value: option.value,
|
|
841
|
-
}
|
|
842
|
-
: previous, defaultReturn)
|
|
843
|
-
: defaultReturn;
|
|
844
|
-
|
|
845
1338
|
function getFieldValue(_f) {
|
|
846
1339
|
const ref = _f.ref;
|
|
847
1340
|
if (isFileInput(ref)) {
|
|
@@ -856,7 +1349,7 @@ function getFieldValue(_f) {
|
|
|
856
1349
|
if (isCheckBoxInput(ref)) {
|
|
857
1350
|
return getCheckboxValue(_f.refs).value;
|
|
858
1351
|
}
|
|
859
|
-
return getFieldValueAs(
|
|
1352
|
+
return getFieldValueAs(ref.value, _f);
|
|
860
1353
|
}
|
|
861
1354
|
|
|
862
1355
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
@@ -873,8 +1366,6 @@ var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeVal
|
|
|
873
1366
|
};
|
|
874
1367
|
};
|
|
875
1368
|
|
|
876
|
-
var isRegex = (value) => value instanceof RegExp;
|
|
877
|
-
|
|
878
1369
|
var getRuleValue = (rule) => isUndefined(rule)
|
|
879
1370
|
? rule
|
|
880
1371
|
: isRegex(rule)
|
|
@@ -885,65 +1376,34 @@ var getRuleValue = (rule) => isUndefined(rule)
|
|
|
885
1376
|
: rule.value
|
|
886
1377
|
: rule;
|
|
887
1378
|
|
|
888
|
-
var getValidationModes = (mode) => ({
|
|
889
|
-
isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
|
|
890
|
-
isOnBlur: mode === VALIDATION_MODE.onBlur,
|
|
891
|
-
isOnChange: mode === VALIDATION_MODE.onChange,
|
|
892
|
-
isOnAll: mode === VALIDATION_MODE.all,
|
|
893
|
-
isOnTouch: mode === VALIDATION_MODE.onTouched,
|
|
894
|
-
});
|
|
895
|
-
|
|
896
1379
|
const ASYNC_FUNCTION = 'AsyncFunction';
|
|
897
|
-
var hasPromiseValidation = (fieldReference) =>
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1380
|
+
var hasPromiseValidation = (fieldReference) => {
|
|
1381
|
+
if (!fieldReference || !fieldReference.validate)
|
|
1382
|
+
return false;
|
|
1383
|
+
if (isFunction(fieldReference.validate)) {
|
|
1384
|
+
return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
|
|
1385
|
+
}
|
|
1386
|
+
if (isObject(fieldReference.validate)) {
|
|
1387
|
+
for (const key in fieldReference.validate) {
|
|
1388
|
+
if (fieldReference.validate[key].constructor
|
|
1389
|
+
.name === ASYNC_FUNCTION) {
|
|
1390
|
+
return true;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
return false;
|
|
1395
|
+
};
|
|
903
1396
|
|
|
904
1397
|
var hasValidation = (options) => options.mount &&
|
|
905
1398
|
(options.required ||
|
|
906
|
-
options.
|
|
907
|
-
options.
|
|
908
|
-
options.
|
|
909
|
-
options.
|
|
1399
|
+
(!isUndefined(options.required) && options.required !== false) ||
|
|
1400
|
+
!isUndefined(options.min) ||
|
|
1401
|
+
!isUndefined(options.max) ||
|
|
1402
|
+
!isUndefined(options.maxLength) ||
|
|
1403
|
+
!isUndefined(options.minLength) ||
|
|
910
1404
|
options.pattern ||
|
|
911
1405
|
options.validate);
|
|
912
1406
|
|
|
913
|
-
var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
|
|
914
|
-
(_names.watchAll ||
|
|
915
|
-
_names.watch.has(name) ||
|
|
916
|
-
[..._names.watch].some((watchName) => name.startsWith(watchName) &&
|
|
917
|
-
/^\.\w+/.test(name.slice(watchName.length))));
|
|
918
|
-
|
|
919
|
-
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
920
|
-
for (const key of fieldsNames || Object.keys(fields)) {
|
|
921
|
-
const field = get(fields, key);
|
|
922
|
-
if (field) {
|
|
923
|
-
const { _f, ...currentField } = field;
|
|
924
|
-
if (_f) {
|
|
925
|
-
if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
|
|
926
|
-
return true;
|
|
927
|
-
}
|
|
928
|
-
else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
|
|
929
|
-
return true;
|
|
930
|
-
}
|
|
931
|
-
else {
|
|
932
|
-
if (iterateFieldsByAction(currentField, action)) {
|
|
933
|
-
break;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
else if (isObject(currentField)) {
|
|
938
|
-
if (iterateFieldsByAction(currentField, action)) {
|
|
939
|
-
break;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
return;
|
|
945
|
-
};
|
|
946
|
-
|
|
947
1407
|
function schemaErrorLookup(errors, _fields, name) {
|
|
948
1408
|
const error = get(errors, name);
|
|
949
1409
|
if (error || isKey(name)) {
|
|
@@ -958,266 +1418,66 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
958
1418
|
const field = get(_fields, fieldName);
|
|
959
1419
|
const foundError = get(errors, fieldName);
|
|
960
1420
|
if (field && !Array.isArray(field) && name !== fieldName) {
|
|
961
|
-
return { name };
|
|
962
|
-
}
|
|
963
|
-
if (foundError && foundError.type) {
|
|
964
|
-
return {
|
|
965
|
-
name: fieldName,
|
|
966
|
-
error: foundError,
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
if (foundError && foundError.root && foundError.root.type) {
|
|
970
|
-
return {
|
|
971
|
-
name: `${fieldName}.root`,
|
|
972
|
-
error: foundError.root,
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
|
-
names.pop();
|
|
976
|
-
}
|
|
977
|
-
return {
|
|
978
|
-
name,
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
983
|
-
updateFormState(formStateData);
|
|
984
|
-
const { name, ...formState } = formStateData;
|
|
985
|
-
return (isEmptyObject(formState) ||
|
|
986
|
-
Object.keys(formState).length >= Object.keys(_proxyFormState).length ||
|
|
987
|
-
Object.keys(formState).find((key) => _proxyFormState[key] ===
|
|
988
|
-
(!isRoot || VALIDATION_MODE.all)));
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
var shouldSubscribeByName = (name, signalName, exact) => !name ||
|
|
992
|
-
!signalName ||
|
|
993
|
-
name === signalName ||
|
|
994
|
-
convertToArrayPayload(name).some((currentName) => currentName &&
|
|
995
|
-
(exact
|
|
996
|
-
? currentName === signalName
|
|
997
|
-
: currentName.startsWith(signalName) ||
|
|
998
|
-
signalName.startsWith(currentName)));
|
|
999
|
-
|
|
1000
|
-
var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
|
|
1001
|
-
if (mode.isOnAll) {
|
|
1002
|
-
return false;
|
|
1003
|
-
}
|
|
1004
|
-
else if (!isSubmitted && mode.isOnTouch) {
|
|
1005
|
-
return !(isTouched || isBlurEvent);
|
|
1006
|
-
}
|
|
1007
|
-
else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
|
|
1008
|
-
return !isBlurEvent;
|
|
1009
|
-
}
|
|
1010
|
-
else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
|
|
1011
|
-
return isBlurEvent;
|
|
1012
|
-
}
|
|
1013
|
-
return true;
|
|
1014
|
-
};
|
|
1015
|
-
|
|
1016
|
-
var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
|
|
1017
|
-
|
|
1018
|
-
var updateFieldArrayRootError = (errors, error, name) => {
|
|
1019
|
-
const fieldArrayErrors = convertToArrayPayload(get(errors, name));
|
|
1020
|
-
set(fieldArrayErrors, 'root', error[name]);
|
|
1021
|
-
set(errors, name, fieldArrayErrors);
|
|
1022
|
-
return errors;
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
function getValidateError(result, ref, type = 'validate') {
|
|
1026
|
-
if (isString(result) ||
|
|
1027
|
-
(Array.isArray(result) && result.every(isString)) ||
|
|
1028
|
-
(isBoolean(result) && !result)) {
|
|
1029
|
-
return {
|
|
1030
|
-
type,
|
|
1031
|
-
message: isString(result) ? result : '',
|
|
1032
|
-
ref,
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
var getValueAndMessage = (validationData) => isObject(validationData) && !isRegex(validationData)
|
|
1038
|
-
? validationData
|
|
1039
|
-
: {
|
|
1040
|
-
value: validationData,
|
|
1041
|
-
message: '',
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
|
|
1045
|
-
const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f;
|
|
1046
|
-
const inputValue = get(formValues, name);
|
|
1047
|
-
if (!mount || disabledFieldNames.has(name)) {
|
|
1048
|
-
return {};
|
|
1049
|
-
}
|
|
1050
|
-
const inputRef = refs ? refs[0] : ref;
|
|
1051
|
-
const setCustomValidity = (message) => {
|
|
1052
|
-
if (shouldUseNativeValidation && inputRef.reportValidity) {
|
|
1053
|
-
inputRef.setCustomValidity(isBoolean(message) ? '' : message || '');
|
|
1054
|
-
inputRef.reportValidity();
|
|
1055
|
-
}
|
|
1056
|
-
};
|
|
1057
|
-
const error = {};
|
|
1058
|
-
const isRadio = isRadioInput(ref);
|
|
1059
|
-
const isCheckBox = isCheckBoxInput(ref);
|
|
1060
|
-
const isRadioOrCheckbox = isRadio || isCheckBox;
|
|
1061
|
-
const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
|
|
1062
|
-
isUndefined(ref.value) &&
|
|
1063
|
-
isUndefined(inputValue)) ||
|
|
1064
|
-
(isHTMLElement(ref) && ref.value === '') ||
|
|
1065
|
-
inputValue === '' ||
|
|
1066
|
-
(Array.isArray(inputValue) && !inputValue.length);
|
|
1067
|
-
const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
|
|
1068
|
-
const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
|
|
1069
|
-
const message = exceedMax ? maxLengthMessage : minLengthMessage;
|
|
1070
|
-
error[name] = {
|
|
1071
|
-
type: exceedMax ? maxType : minType,
|
|
1072
|
-
message,
|
|
1073
|
-
ref,
|
|
1074
|
-
...appendErrorsCurry(exceedMax ? maxType : minType, message),
|
|
1075
|
-
};
|
|
1076
|
-
};
|
|
1077
|
-
if (isFieldArray
|
|
1078
|
-
? !Array.isArray(inputValue) || !inputValue.length
|
|
1079
|
-
: required &&
|
|
1080
|
-
((!isRadioOrCheckbox && (isEmpty || isNullOrUndefined(inputValue))) ||
|
|
1081
|
-
(isBoolean(inputValue) && !inputValue) ||
|
|
1082
|
-
(isCheckBox && !getCheckboxValue(refs).isValid) ||
|
|
1083
|
-
(isRadio && !getRadioValue(refs).isValid))) {
|
|
1084
|
-
const { value, message } = isString(required)
|
|
1085
|
-
? { value: !!required, message: required }
|
|
1086
|
-
: getValueAndMessage(required);
|
|
1087
|
-
if (value) {
|
|
1088
|
-
error[name] = {
|
|
1089
|
-
type: INPUT_VALIDATION_RULES.required,
|
|
1090
|
-
message,
|
|
1091
|
-
ref: inputRef,
|
|
1092
|
-
...appendErrorsCurry(INPUT_VALIDATION_RULES.required, message),
|
|
1093
|
-
};
|
|
1094
|
-
if (!validateAllFieldCriteria) {
|
|
1095
|
-
setCustomValidity(message);
|
|
1096
|
-
return error;
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
if (!isEmpty && (!isNullOrUndefined(min) || !isNullOrUndefined(max))) {
|
|
1101
|
-
let exceedMax;
|
|
1102
|
-
let exceedMin;
|
|
1103
|
-
const maxOutput = getValueAndMessage(max);
|
|
1104
|
-
const minOutput = getValueAndMessage(min);
|
|
1105
|
-
if (!isNullOrUndefined(inputValue) && !isNaN(inputValue)) {
|
|
1106
|
-
const valueNumber = ref.valueAsNumber ||
|
|
1107
|
-
(inputValue ? +inputValue : inputValue);
|
|
1108
|
-
if (!isNullOrUndefined(maxOutput.value)) {
|
|
1109
|
-
exceedMax = valueNumber > maxOutput.value;
|
|
1110
|
-
}
|
|
1111
|
-
if (!isNullOrUndefined(minOutput.value)) {
|
|
1112
|
-
exceedMin = valueNumber < minOutput.value;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
else {
|
|
1116
|
-
const valueDate = ref.valueAsDate || new Date(inputValue);
|
|
1117
|
-
const convertTimeToDate = (time) => new Date(new Date().toDateString() + ' ' + time);
|
|
1118
|
-
const isTime = ref.type == 'time';
|
|
1119
|
-
const isWeek = ref.type == 'week';
|
|
1120
|
-
if (isString(maxOutput.value) && inputValue) {
|
|
1121
|
-
exceedMax = isTime
|
|
1122
|
-
? convertTimeToDate(inputValue) > convertTimeToDate(maxOutput.value)
|
|
1123
|
-
: isWeek
|
|
1124
|
-
? inputValue > maxOutput.value
|
|
1125
|
-
: valueDate > new Date(maxOutput.value);
|
|
1126
|
-
}
|
|
1127
|
-
if (isString(minOutput.value) && inputValue) {
|
|
1128
|
-
exceedMin = isTime
|
|
1129
|
-
? convertTimeToDate(inputValue) < convertTimeToDate(minOutput.value)
|
|
1130
|
-
: isWeek
|
|
1131
|
-
? inputValue < minOutput.value
|
|
1132
|
-
: valueDate < new Date(minOutput.value);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
if (exceedMax || exceedMin) {
|
|
1136
|
-
getMinMaxMessage(!!exceedMax, maxOutput.message, minOutput.message, INPUT_VALIDATION_RULES.max, INPUT_VALIDATION_RULES.min);
|
|
1137
|
-
if (!validateAllFieldCriteria) {
|
|
1138
|
-
setCustomValidity(error[name].message);
|
|
1139
|
-
return error;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
if ((maxLength || minLength) &&
|
|
1144
|
-
!isEmpty &&
|
|
1145
|
-
(isString(inputValue) || (isFieldArray && Array.isArray(inputValue)))) {
|
|
1146
|
-
const maxLengthOutput = getValueAndMessage(maxLength);
|
|
1147
|
-
const minLengthOutput = getValueAndMessage(minLength);
|
|
1148
|
-
const exceedMax = !isNullOrUndefined(maxLengthOutput.value) &&
|
|
1149
|
-
inputValue.length > +maxLengthOutput.value;
|
|
1150
|
-
const exceedMin = !isNullOrUndefined(minLengthOutput.value) &&
|
|
1151
|
-
inputValue.length < +minLengthOutput.value;
|
|
1152
|
-
if (exceedMax || exceedMin) {
|
|
1153
|
-
getMinMaxMessage(exceedMax, maxLengthOutput.message, minLengthOutput.message);
|
|
1154
|
-
if (!validateAllFieldCriteria) {
|
|
1155
|
-
setCustomValidity(error[name].message);
|
|
1156
|
-
return error;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
if (pattern && !isEmpty && isString(inputValue)) {
|
|
1161
|
-
const { value: patternValue, message } = getValueAndMessage(pattern);
|
|
1162
|
-
if (isRegex(patternValue) && !inputValue.match(patternValue)) {
|
|
1163
|
-
error[name] = {
|
|
1164
|
-
type: INPUT_VALIDATION_RULES.pattern,
|
|
1165
|
-
message,
|
|
1166
|
-
ref,
|
|
1167
|
-
...appendErrorsCurry(INPUT_VALIDATION_RULES.pattern, message),
|
|
1168
|
-
};
|
|
1169
|
-
if (!validateAllFieldCriteria) {
|
|
1170
|
-
setCustomValidity(message);
|
|
1171
|
-
return error;
|
|
1172
|
-
}
|
|
1421
|
+
return { name };
|
|
1173
1422
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (validateError) {
|
|
1180
|
-
error[name] = {
|
|
1181
|
-
...validateError,
|
|
1182
|
-
...appendErrorsCurry(INPUT_VALIDATION_RULES.validate, validateError.message),
|
|
1183
|
-
};
|
|
1184
|
-
if (!validateAllFieldCriteria) {
|
|
1185
|
-
setCustomValidity(validateError.message);
|
|
1186
|
-
return error;
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1423
|
+
if (foundError && foundError.type) {
|
|
1424
|
+
return {
|
|
1425
|
+
name: fieldName,
|
|
1426
|
+
error: foundError,
|
|
1427
|
+
};
|
|
1189
1428
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1196
|
-
const validateError = getValidateError(await validate[key](inputValue, formValues), inputRef, key);
|
|
1197
|
-
if (validateError) {
|
|
1198
|
-
validationResult = {
|
|
1199
|
-
...validateError,
|
|
1200
|
-
...appendErrorsCurry(key, validateError.message),
|
|
1201
|
-
};
|
|
1202
|
-
setCustomValidity(validateError.message);
|
|
1203
|
-
if (validateAllFieldCriteria) {
|
|
1204
|
-
error[name] = validationResult;
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
if (!isEmptyObject(validationResult)) {
|
|
1209
|
-
error[name] = {
|
|
1210
|
-
ref: inputRef,
|
|
1211
|
-
...validationResult,
|
|
1212
|
-
};
|
|
1213
|
-
if (!validateAllFieldCriteria) {
|
|
1214
|
-
return error;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1429
|
+
if (foundError && foundError.root && foundError.root.type) {
|
|
1430
|
+
return {
|
|
1431
|
+
name: `${fieldName}.root`,
|
|
1432
|
+
error: foundError.root,
|
|
1433
|
+
};
|
|
1217
1434
|
}
|
|
1435
|
+
names.pop();
|
|
1218
1436
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1437
|
+
return {
|
|
1438
|
+
name,
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
1443
|
+
updateFormState(formStateData);
|
|
1444
|
+
const keys = Object.keys(formStateData).filter((key) => key !== 'name');
|
|
1445
|
+
return (!keys.length ||
|
|
1446
|
+
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
1447
|
+
keys.find((key) => _proxyFormState[key] ===
|
|
1448
|
+
(!isRoot || VALIDATION_MODE.all)));
|
|
1449
|
+
};
|
|
1450
|
+
|
|
1451
|
+
var shouldSubscribeByName = (name, signalName, exact) => !name ||
|
|
1452
|
+
!signalName ||
|
|
1453
|
+
name === signalName ||
|
|
1454
|
+
convertToArrayPayload(name).some((currentName) => currentName &&
|
|
1455
|
+
(exact
|
|
1456
|
+
? currentName === signalName || currentName.startsWith(signalName + '.')
|
|
1457
|
+
: currentName.startsWith(signalName) ||
|
|
1458
|
+
signalName.startsWith(currentName)));
|
|
1459
|
+
|
|
1460
|
+
var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
|
|
1461
|
+
if (mode.isOnAll) {
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
else if (!isSubmitted && mode.isOnTouch) {
|
|
1465
|
+
return !(isTouched || isBlurEvent);
|
|
1466
|
+
}
|
|
1467
|
+
else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
|
|
1468
|
+
return !isBlurEvent;
|
|
1469
|
+
}
|
|
1470
|
+
else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
|
|
1471
|
+
return isBlurEvent;
|
|
1472
|
+
}
|
|
1473
|
+
return true;
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
var unsetEmptyArray = (ref, name) => {
|
|
1477
|
+
const array = get(ref, name);
|
|
1478
|
+
!compact(array).length &&
|
|
1479
|
+
!(array === null || array === void 0 ? void 0 : array.root) &&
|
|
1480
|
+
unset(ref, name);
|
|
1221
1481
|
};
|
|
1222
1482
|
|
|
1223
1483
|
const defaultOptions = {
|
|
@@ -1225,24 +1485,36 @@ const defaultOptions = {
|
|
|
1225
1485
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
1226
1486
|
shouldFocusError: true,
|
|
1227
1487
|
};
|
|
1488
|
+
const FORM_ERROR_TYPE = 'form';
|
|
1489
|
+
const updateDirtyFields = (dirtyFields, nextDirtyFields) => {
|
|
1490
|
+
for (const key in dirtyFields) {
|
|
1491
|
+
if (!(key in nextDirtyFields)) {
|
|
1492
|
+
delete dirtyFields[key];
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
Object.assign(dirtyFields, nextDirtyFields);
|
|
1496
|
+
};
|
|
1497
|
+
const DEFAULT_FORM_STATE = {
|
|
1498
|
+
submitCount: 0,
|
|
1499
|
+
isDirty: false,
|
|
1500
|
+
isReady: false,
|
|
1501
|
+
isValidating: false,
|
|
1502
|
+
isSubmitted: false,
|
|
1503
|
+
isSubmitting: false,
|
|
1504
|
+
isSubmitSuccessful: false,
|
|
1505
|
+
isValid: false,
|
|
1506
|
+
touchedFields: {},
|
|
1507
|
+
dirtyFields: {},
|
|
1508
|
+
validatingFields: {},
|
|
1509
|
+
};
|
|
1228
1510
|
function createFormControl(props = {}) {
|
|
1229
1511
|
let _options = {
|
|
1230
1512
|
...defaultOptions,
|
|
1231
1513
|
...props,
|
|
1232
1514
|
};
|
|
1233
1515
|
let _formState = {
|
|
1234
|
-
|
|
1235
|
-
isDirty: false,
|
|
1236
|
-
isReady: false,
|
|
1516
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
1237
1517
|
isLoading: isFunction(_options.defaultValues),
|
|
1238
|
-
isValidating: false,
|
|
1239
|
-
isSubmitted: false,
|
|
1240
|
-
isSubmitting: false,
|
|
1241
|
-
isSubmitSuccessful: false,
|
|
1242
|
-
isValid: false,
|
|
1243
|
-
touchedFields: {},
|
|
1244
|
-
dirtyFields: {},
|
|
1245
|
-
validatingFields: {},
|
|
1246
1518
|
errors: _options.errors || {},
|
|
1247
1519
|
disabled: _options.disabled || false,
|
|
1248
1520
|
};
|
|
@@ -1255,6 +1527,7 @@ function createFormControl(props = {}) {
|
|
|
1255
1527
|
: cloneObject(_defaultValues);
|
|
1256
1528
|
let _state = {
|
|
1257
1529
|
action: false,
|
|
1530
|
+
actionArrayLengths: new Map(),
|
|
1258
1531
|
mount: false,
|
|
1259
1532
|
watch: false,
|
|
1260
1533
|
keepIsValid: false,
|
|
@@ -1265,9 +1538,13 @@ function createFormControl(props = {}) {
|
|
|
1265
1538
|
unMount: new Set(),
|
|
1266
1539
|
array: new Set(),
|
|
1267
1540
|
watch: new Set(),
|
|
1541
|
+
registerName: new Set(),
|
|
1268
1542
|
};
|
|
1269
|
-
|
|
1270
|
-
|
|
1543
|
+
const delayErrorCallbacks = {};
|
|
1544
|
+
const timers = {};
|
|
1545
|
+
let _valuesSubscriberCount = 0;
|
|
1546
|
+
let _validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1547
|
+
let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1271
1548
|
const defaultProxyFormState = {
|
|
1272
1549
|
isDirty: false,
|
|
1273
1550
|
dirtyFields: false,
|
|
@@ -1287,10 +1564,11 @@ function createFormControl(props = {}) {
|
|
|
1287
1564
|
array: createSubject(),
|
|
1288
1565
|
state: createSubject(),
|
|
1289
1566
|
};
|
|
1567
|
+
let _setValidCallId = 0;
|
|
1290
1568
|
const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
|
|
1291
|
-
const debounce = (callback) => (wait) => {
|
|
1292
|
-
clearTimeout(
|
|
1293
|
-
|
|
1569
|
+
const debounce = (name, callback) => (wait) => {
|
|
1570
|
+
clearTimeout(timers[name]);
|
|
1571
|
+
timers[name] = setTimeout(callback, wait);
|
|
1294
1572
|
};
|
|
1295
1573
|
const _setValid = async (shouldUpdateValid) => {
|
|
1296
1574
|
if (_state.keepIsValid) {
|
|
@@ -1300,15 +1578,20 @@ function createFormControl(props = {}) {
|
|
|
1300
1578
|
(_proxyFormState.isValid ||
|
|
1301
1579
|
_proxySubscribeFormState.isValid ||
|
|
1302
1580
|
shouldUpdateValid)) {
|
|
1581
|
+
const callId = ++_setValidCallId;
|
|
1303
1582
|
let isValid;
|
|
1304
1583
|
if (_options.resolver) {
|
|
1305
1584
|
isValid = isEmptyObject((await _runSchema()).errors);
|
|
1306
|
-
_updateIsValidating();
|
|
1585
|
+
callId === _setValidCallId && _updateIsValidating();
|
|
1307
1586
|
}
|
|
1308
1587
|
else {
|
|
1309
|
-
isValid = await executeBuiltInValidation(
|
|
1588
|
+
isValid = await executeBuiltInValidation({
|
|
1589
|
+
fields: _fields,
|
|
1590
|
+
onlyCheckValid: true,
|
|
1591
|
+
eventType: EVENTS.VALID,
|
|
1592
|
+
});
|
|
1310
1593
|
}
|
|
1311
|
-
if (isValid !== _formState.isValid) {
|
|
1594
|
+
if (callId === _setValidCallId && isValid !== _formState.isValid) {
|
|
1312
1595
|
_subjects.state.next({
|
|
1313
1596
|
isValid,
|
|
1314
1597
|
});
|
|
@@ -1321,7 +1604,7 @@ function createFormControl(props = {}) {
|
|
|
1321
1604
|
_proxyFormState.validatingFields ||
|
|
1322
1605
|
_proxySubscribeFormState.isValidating ||
|
|
1323
1606
|
_proxySubscribeFormState.validatingFields)) {
|
|
1324
|
-
(names ||
|
|
1607
|
+
(names || _names.mount).forEach((name) => {
|
|
1325
1608
|
if (name) {
|
|
1326
1609
|
isValidating
|
|
1327
1610
|
? set(_formState.validatingFields, name, isValidating)
|
|
@@ -1334,28 +1617,40 @@ function createFormControl(props = {}) {
|
|
|
1334
1617
|
});
|
|
1335
1618
|
}
|
|
1336
1619
|
};
|
|
1620
|
+
const _updateDirtyFields = () => {
|
|
1621
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
1622
|
+
};
|
|
1337
1623
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1338
1624
|
if (args && method && !_options.disabled) {
|
|
1339
1625
|
_state.action = true;
|
|
1340
|
-
|
|
1341
|
-
|
|
1626
|
+
const fields = get(_fields, name);
|
|
1627
|
+
if (!_state.actionArrayLengths.has(name)) {
|
|
1628
|
+
_state.actionArrayLengths.set(name, Array.isArray(fields) ? fields.length : 0);
|
|
1629
|
+
}
|
|
1630
|
+
if (shouldUpdateFieldsAndState && Array.isArray(fields)) {
|
|
1631
|
+
const fieldValues = method(fields, args.argA, args.argB);
|
|
1342
1632
|
shouldSetValues && set(_fields, name, fieldValues);
|
|
1343
1633
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
const
|
|
1634
|
+
const fieldArrayErrors = get(_formState.errors, name);
|
|
1635
|
+
if (shouldUpdateFieldsAndState && Array.isArray(fieldArrayErrors)) {
|
|
1636
|
+
const rootError = fieldArrayErrors.root;
|
|
1637
|
+
const errors = method(fieldArrayErrors, args.argA, args.argB) || fieldArrayErrors;
|
|
1638
|
+
if (rootError) {
|
|
1639
|
+
errors.root = rootError;
|
|
1640
|
+
}
|
|
1347
1641
|
shouldSetValues && set(_formState.errors, name, errors);
|
|
1348
1642
|
unsetEmptyArray(_formState.errors, name);
|
|
1349
1643
|
}
|
|
1644
|
+
const touchedFieldsArray = get(_formState.touchedFields, name);
|
|
1350
1645
|
if ((_proxyFormState.touchedFields ||
|
|
1351
1646
|
_proxySubscribeFormState.touchedFields) &&
|
|
1352
1647
|
shouldUpdateFieldsAndState &&
|
|
1353
|
-
Array.isArray(
|
|
1354
|
-
const touchedFields = method(
|
|
1648
|
+
Array.isArray(touchedFieldsArray)) {
|
|
1649
|
+
const touchedFields = method(touchedFieldsArray, args.argA, args.argB);
|
|
1355
1650
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1356
1651
|
}
|
|
1357
1652
|
if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
|
|
1358
|
-
|
|
1653
|
+
_updateDirtyFields();
|
|
1359
1654
|
}
|
|
1360
1655
|
_subjects.state.next({
|
|
1361
1656
|
name,
|
|
@@ -1371,6 +1666,7 @@ function createFormControl(props = {}) {
|
|
|
1371
1666
|
};
|
|
1372
1667
|
const updateErrors = (name, error) => {
|
|
1373
1668
|
set(_formState.errors, name, error);
|
|
1669
|
+
_formState.errors = { ..._formState.errors };
|
|
1374
1670
|
_subjects.state.next({
|
|
1375
1671
|
errors: _formState.errors,
|
|
1376
1672
|
});
|
|
@@ -1382,16 +1678,83 @@ function createFormControl(props = {}) {
|
|
|
1382
1678
|
isValid: false,
|
|
1383
1679
|
});
|
|
1384
1680
|
};
|
|
1681
|
+
const hasExplicitNullIntermediate = (name) => {
|
|
1682
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
1683
|
+
let formValues = _formValues;
|
|
1684
|
+
let defaultValues = _defaultValues;
|
|
1685
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1686
|
+
const key = segments[i];
|
|
1687
|
+
formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
|
|
1688
|
+
defaultValues = isNullOrUndefined(defaultValues)
|
|
1689
|
+
? defaultValues
|
|
1690
|
+
: defaultValues[key];
|
|
1691
|
+
if (formValues === null && defaultValues !== null) {
|
|
1692
|
+
return true;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return false;
|
|
1696
|
+
};
|
|
1697
|
+
const isStaleArrayIndex = (name) => {
|
|
1698
|
+
if (!_state.actionArrayLengths.size) {
|
|
1699
|
+
return false;
|
|
1700
|
+
}
|
|
1701
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
1702
|
+
let node = _formValues;
|
|
1703
|
+
let path = '';
|
|
1704
|
+
let ownerDepth = -1;
|
|
1705
|
+
let ownerPreActionLength = 0;
|
|
1706
|
+
for (let i = 0; i < segments.length; i++) {
|
|
1707
|
+
if (isNullOrUndefined(node)) {
|
|
1708
|
+
return false;
|
|
1709
|
+
}
|
|
1710
|
+
const key = segments[i];
|
|
1711
|
+
path = path ? `${path}.${key}` : key;
|
|
1712
|
+
if (Array.isArray(node) && +key >= node.length) {
|
|
1713
|
+
return ownerDepth === -1
|
|
1714
|
+
? false
|
|
1715
|
+
: i === ownerDepth
|
|
1716
|
+
? +key < ownerPreActionLength
|
|
1717
|
+
: true;
|
|
1718
|
+
}
|
|
1719
|
+
if (_state.actionArrayLengths.has(path)) {
|
|
1720
|
+
ownerDepth = i + 1;
|
|
1721
|
+
ownerPreActionLength = _state.actionArrayLengths.get(path);
|
|
1722
|
+
}
|
|
1723
|
+
node = node[key];
|
|
1724
|
+
}
|
|
1725
|
+
return false;
|
|
1726
|
+
};
|
|
1385
1727
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1386
1728
|
const field = get(_fields, name);
|
|
1387
1729
|
if (field) {
|
|
1730
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayIndex(name)) {
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
1388
1734
|
const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
|
|
1389
1735
|
isUndefined(defaultValue) ||
|
|
1390
1736
|
(ref && ref.defaultChecked) ||
|
|
1391
1737
|
shouldSkipSetValueAs
|
|
1392
1738
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1393
1739
|
: setFieldValue(name, defaultValue);
|
|
1394
|
-
_state.mount && !_state.action
|
|
1740
|
+
if (_state.mount && !_state.action) {
|
|
1741
|
+
_setValid();
|
|
1742
|
+
if (wasUnsetInFormValues &&
|
|
1743
|
+
_formState.isDirty &&
|
|
1744
|
+
(_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
|
|
1745
|
+
const isDirty = _getDirty();
|
|
1746
|
+
if (!isDirty) {
|
|
1747
|
+
_formState.isDirty = false;
|
|
1748
|
+
_subjects.state.next({ ..._formState });
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
if (props.shouldUnregister &&
|
|
1752
|
+
wasUnsetInFormValues &&
|
|
1753
|
+
!isUndefined(get(_formValues, name)) &&
|
|
1754
|
+
isWatched(name, _names)) {
|
|
1755
|
+
_state.watch = true;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1395
1758
|
}
|
|
1396
1759
|
};
|
|
1397
1760
|
const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
|
|
@@ -1400,18 +1763,26 @@ function createFormControl(props = {}) {
|
|
|
1400
1763
|
const output = {
|
|
1401
1764
|
name,
|
|
1402
1765
|
};
|
|
1403
|
-
|
|
1766
|
+
// an explicit programmatic update (e.g. setValue with shouldDirty: true)
|
|
1767
|
+
// opts into dirty tracking even when the form is disabled
|
|
1768
|
+
if (!_options.disabled || shouldDirty === true) {
|
|
1404
1769
|
if (!isBlurEvent || shouldDirty) {
|
|
1770
|
+
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1405
1771
|
if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
|
|
1406
1772
|
isPreviousDirty = _formState.isDirty;
|
|
1407
|
-
_formState.isDirty = output.isDirty =
|
|
1773
|
+
_formState.isDirty = output.isDirty =
|
|
1774
|
+
!isCurrentFieldPristine || _getDirty();
|
|
1408
1775
|
shouldUpdateField = isPreviousDirty !== output.isDirty;
|
|
1409
1776
|
}
|
|
1410
|
-
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1411
1777
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1412
|
-
isCurrentFieldPristine
|
|
1413
|
-
|
|
1414
|
-
|
|
1778
|
+
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1779
|
+
updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
|
|
1780
|
+
}
|
|
1781
|
+
else {
|
|
1782
|
+
isCurrentFieldPristine
|
|
1783
|
+
? unset(_formState.dirtyFields, name)
|
|
1784
|
+
: set(_formState.dirtyFields, name, true);
|
|
1785
|
+
}
|
|
1415
1786
|
output.dirtyFields = _formState.dirtyFields;
|
|
1416
1787
|
shouldUpdateField =
|
|
1417
1788
|
shouldUpdateField ||
|
|
@@ -1441,15 +1812,16 @@ function createFormControl(props = {}) {
|
|
|
1441
1812
|
isBoolean(isValid) &&
|
|
1442
1813
|
_formState.isValid !== isValid;
|
|
1443
1814
|
if (_options.delayError && error) {
|
|
1444
|
-
|
|
1445
|
-
|
|
1815
|
+
delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
|
|
1816
|
+
delayErrorCallbacks[name](_options.delayError);
|
|
1446
1817
|
}
|
|
1447
1818
|
else {
|
|
1448
|
-
clearTimeout(
|
|
1449
|
-
|
|
1819
|
+
clearTimeout(timers[name]);
|
|
1820
|
+
delete delayErrorCallbacks[name];
|
|
1450
1821
|
error
|
|
1451
1822
|
? set(_formState.errors, name, error)
|
|
1452
1823
|
: unset(_formState.errors, name);
|
|
1824
|
+
_formState.errors = { ..._formState.errors };
|
|
1453
1825
|
}
|
|
1454
1826
|
if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
|
|
1455
1827
|
!isEmptyObject(fieldState) ||
|
|
@@ -1460,17 +1832,12 @@ function createFormControl(props = {}) {
|
|
|
1460
1832
|
errors: _formState.errors,
|
|
1461
1833
|
name,
|
|
1462
1834
|
};
|
|
1463
|
-
_formState = {
|
|
1464
|
-
..._formState,
|
|
1465
|
-
...updatedFormState,
|
|
1466
|
-
};
|
|
1467
1835
|
_subjects.state.next(updatedFormState);
|
|
1468
1836
|
}
|
|
1469
1837
|
};
|
|
1470
1838
|
const _runSchema = async (name) => {
|
|
1471
1839
|
_updateIsValidating(name, true);
|
|
1472
|
-
|
|
1473
|
-
return result;
|
|
1840
|
+
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1474
1841
|
};
|
|
1475
1842
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1476
1843
|
const { errors } = await _runSchema(names);
|
|
@@ -1479,18 +1846,69 @@ function createFormControl(props = {}) {
|
|
|
1479
1846
|
for (const name of names) {
|
|
1480
1847
|
const error = get(errors, name);
|
|
1481
1848
|
error
|
|
1482
|
-
?
|
|
1849
|
+
? _names.array.has(name) &&
|
|
1850
|
+
isObject(error) &&
|
|
1851
|
+
!Object.keys(error).some((key) => !Number.isNaN(Number(key)))
|
|
1852
|
+
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
1853
|
+
: set(_formState.errors, name, error)
|
|
1483
1854
|
: unset(_formState.errors, name);
|
|
1484
1855
|
}
|
|
1856
|
+
_formState.errors = { ..._formState.errors };
|
|
1485
1857
|
}
|
|
1486
1858
|
else {
|
|
1487
1859
|
_formState.errors = errors;
|
|
1488
1860
|
}
|
|
1489
1861
|
return errors;
|
|
1490
1862
|
};
|
|
1491
|
-
const
|
|
1863
|
+
const validateForm = async ({ name, eventType, }) => {
|
|
1864
|
+
if (props.validate) {
|
|
1865
|
+
const result = await props.validate({
|
|
1866
|
+
formValues: _formValues,
|
|
1867
|
+
formState: _formState,
|
|
1868
|
+
name,
|
|
1869
|
+
eventType,
|
|
1870
|
+
});
|
|
1871
|
+
if (isObject(result)) {
|
|
1872
|
+
for (const key in result) {
|
|
1873
|
+
const error = result[key];
|
|
1874
|
+
if (error) {
|
|
1875
|
+
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1876
|
+
message: isString(error.message) ? error.message : '',
|
|
1877
|
+
type: error.type || INPUT_VALIDATION_RULES.validate,
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
else if (isString(result) || !result) {
|
|
1883
|
+
setError(FORM_ERROR_TYPE, {
|
|
1884
|
+
message: result || '',
|
|
1885
|
+
type: INPUT_VALIDATION_RULES.validate,
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
else {
|
|
1889
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1890
|
+
}
|
|
1891
|
+
return result;
|
|
1892
|
+
}
|
|
1893
|
+
return true;
|
|
1894
|
+
};
|
|
1895
|
+
const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
|
|
1492
1896
|
valid: true,
|
|
1493
|
-
|
|
1897
|
+
runRootValidation: false,
|
|
1898
|
+
}, }) => {
|
|
1899
|
+
if (props.validate) {
|
|
1900
|
+
context.runRootValidation = true;
|
|
1901
|
+
const result = await validateForm({
|
|
1902
|
+
name,
|
|
1903
|
+
eventType,
|
|
1904
|
+
});
|
|
1905
|
+
if (!result) {
|
|
1906
|
+
context.valid = false;
|
|
1907
|
+
if (onlyCheckValid) {
|
|
1908
|
+
return context.valid;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1494
1912
|
for (const name in fields) {
|
|
1495
1913
|
const field = fields[name];
|
|
1496
1914
|
if (field) {
|
|
@@ -1498,28 +1916,41 @@ function createFormControl(props = {}) {
|
|
|
1498
1916
|
if (_f) {
|
|
1499
1917
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
1500
1918
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
1501
|
-
|
|
1919
|
+
const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
|
|
1920
|
+
_proxyFormState.isValidating ||
|
|
1921
|
+
_proxySubscribeFormState.validatingFields ||
|
|
1922
|
+
_proxySubscribeFormState.isValidating;
|
|
1923
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1502
1924
|
_updateIsValidating([_f.name], true);
|
|
1503
1925
|
}
|
|
1504
|
-
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !
|
|
1505
|
-
if (isPromiseFunction &&
|
|
1926
|
+
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1927
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1506
1928
|
_updateIsValidating([_f.name]);
|
|
1507
1929
|
}
|
|
1508
1930
|
if (fieldError[_f.name]) {
|
|
1509
1931
|
context.valid = false;
|
|
1510
|
-
if (
|
|
1932
|
+
if (onlyCheckValid) {
|
|
1511
1933
|
break;
|
|
1512
1934
|
}
|
|
1513
1935
|
}
|
|
1514
|
-
!
|
|
1936
|
+
!onlyCheckValid &&
|
|
1515
1937
|
(get(fieldError, _f.name)
|
|
1516
1938
|
? isFieldArrayRoot
|
|
1517
1939
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1518
1940
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1519
1941
|
: unset(_formState.errors, _f.name));
|
|
1942
|
+
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1943
|
+
break;
|
|
1944
|
+
}
|
|
1520
1945
|
}
|
|
1521
1946
|
!isEmptyObject(fieldValue) &&
|
|
1522
|
-
(await executeBuiltInValidation(
|
|
1947
|
+
(await executeBuiltInValidation({
|
|
1948
|
+
context,
|
|
1949
|
+
onlyCheckValid,
|
|
1950
|
+
fields: fieldValue,
|
|
1951
|
+
name: name,
|
|
1952
|
+
eventType,
|
|
1953
|
+
}));
|
|
1523
1954
|
}
|
|
1524
1955
|
}
|
|
1525
1956
|
return context.valid;
|
|
@@ -1535,20 +1966,17 @@ function createFormControl(props = {}) {
|
|
|
1535
1966
|
}
|
|
1536
1967
|
_names.unMount = new Set();
|
|
1537
1968
|
};
|
|
1538
|
-
const _getDirty = (name, data) =>
|
|
1539
|
-
(
|
|
1540
|
-
!deepEqual(getValues(), _defaultValues));
|
|
1969
|
+
const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
|
|
1970
|
+
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1541
1971
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
1542
1972
|
...(_state.mount
|
|
1543
1973
|
? _formValues
|
|
1544
|
-
: isUndefined(defaultValue)
|
|
1974
|
+
: isUndefined(defaultValue) || isString(names)
|
|
1545
1975
|
? _defaultValues
|
|
1546
|
-
:
|
|
1547
|
-
? { [names]: defaultValue }
|
|
1548
|
-
: defaultValue),
|
|
1976
|
+
: defaultValue),
|
|
1549
1977
|
}, isGlobal, defaultValue);
|
|
1550
1978
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
1551
|
-
const setFieldValue = (name, value, options = {}) => {
|
|
1979
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
1552
1980
|
const field = get(_fields, name);
|
|
1553
1981
|
let fieldValue = value;
|
|
1554
1982
|
if (field) {
|
|
@@ -1586,23 +2014,32 @@ function createFormControl(props = {}) {
|
|
|
1586
2014
|
}
|
|
1587
2015
|
else {
|
|
1588
2016
|
fieldReference.ref.value = fieldValue;
|
|
1589
|
-
if (!fieldReference.ref.type) {
|
|
2017
|
+
if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
|
|
1590
2018
|
_subjects.state.next({
|
|
1591
2019
|
name,
|
|
1592
|
-
values: cloneObject(_formValues),
|
|
2020
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1593
2021
|
});
|
|
1594
2022
|
}
|
|
1595
2023
|
}
|
|
1596
2024
|
}
|
|
1597
2025
|
}
|
|
1598
2026
|
(options.shouldDirty || options.shouldTouch) &&
|
|
1599
|
-
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty,
|
|
1600
|
-
options.shouldValidate &&
|
|
2027
|
+
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
|
|
2028
|
+
options.shouldValidate &&
|
|
2029
|
+
trigger(name, {
|
|
2030
|
+
delayError: options.delayError,
|
|
2031
|
+
});
|
|
1601
2032
|
};
|
|
1602
|
-
const
|
|
2033
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
2034
|
+
if (_names.array.has(name)) {
|
|
2035
|
+
_subjects.array.next({
|
|
2036
|
+
name,
|
|
2037
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
1603
2040
|
for (const fieldKey in value) {
|
|
1604
2041
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1605
|
-
|
|
2042
|
+
continue;
|
|
1606
2043
|
}
|
|
1607
2044
|
const fieldValue = value[fieldKey];
|
|
1608
2045
|
const fieldName = name + '.' + fieldKey;
|
|
@@ -1611,49 +2048,89 @@ function createFormControl(props = {}) {
|
|
|
1611
2048
|
isObject(fieldValue) ||
|
|
1612
2049
|
(field && !field._f)) &&
|
|
1613
2050
|
!isDateObject(fieldValue)
|
|
1614
|
-
?
|
|
1615
|
-
: setFieldValue(fieldName, fieldValue, options);
|
|
2051
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
|
|
2052
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
|
|
1616
2053
|
}
|
|
1617
2054
|
};
|
|
1618
|
-
const
|
|
2055
|
+
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
1619
2056
|
const field = get(_fields, name);
|
|
1620
2057
|
const isFieldArray = _names.array.has(name);
|
|
1621
|
-
const cloneValue = cloneObject(value);
|
|
1622
|
-
|
|
2058
|
+
const cloneValue = skipClone ? value : cloneObject(value);
|
|
2059
|
+
const previousValue = get(_formValues, name);
|
|
2060
|
+
const isValueUnchanged = deepEqual(previousValue, cloneValue);
|
|
2061
|
+
if (!isValueUnchanged) {
|
|
2062
|
+
set(_formValues, name, cloneValue);
|
|
2063
|
+
}
|
|
1623
2064
|
if (isFieldArray) {
|
|
1624
2065
|
_subjects.array.next({
|
|
1625
2066
|
name,
|
|
1626
|
-
values: cloneObject(_formValues),
|
|
2067
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1627
2068
|
});
|
|
1628
2069
|
if ((_proxyFormState.isDirty ||
|
|
1629
2070
|
_proxyFormState.dirtyFields ||
|
|
1630
2071
|
_proxySubscribeFormState.isDirty ||
|
|
1631
2072
|
_proxySubscribeFormState.dirtyFields) &&
|
|
1632
2073
|
options.shouldDirty) {
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
2074
|
+
_updateDirtyFields();
|
|
2075
|
+
if (!skipStateEmit) {
|
|
2076
|
+
_subjects.state.next({
|
|
2077
|
+
name,
|
|
2078
|
+
dirtyFields: _formState.dirtyFields,
|
|
2079
|
+
isDirty: _getDirty(name, cloneValue),
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
1638
2082
|
}
|
|
1639
2083
|
}
|
|
1640
2084
|
else {
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
2085
|
+
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
2086
|
+
isEmptyObject(cloneValue);
|
|
2087
|
+
const skipValueRender = !isValueUnchanged && !skipStateEmit;
|
|
2088
|
+
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
2089
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2090
|
+
}
|
|
2091
|
+
else {
|
|
2092
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2093
|
+
}
|
|
1644
2094
|
}
|
|
1645
|
-
if (
|
|
2095
|
+
if (!isValueUnchanged && !skipStateEmit) {
|
|
2096
|
+
const watched = isWatched(name, _names);
|
|
2097
|
+
const values = skipClone ? _formValues : cloneObject(_formValues);
|
|
1646
2098
|
_subjects.state.next({
|
|
1647
|
-
..._formState,
|
|
1648
|
-
name,
|
|
1649
|
-
values
|
|
2099
|
+
...(watched && _formState),
|
|
2100
|
+
name: _state.mount || watched ? name : undefined,
|
|
2101
|
+
values,
|
|
1650
2102
|
});
|
|
2103
|
+
if (!isFieldArray) {
|
|
2104
|
+
for (const itemName of getFieldArrayItemNames(_names.array, name)) {
|
|
2105
|
+
_subjects.state.next({ name: itemName, values });
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
1651
2108
|
}
|
|
1652
|
-
|
|
2109
|
+
};
|
|
2110
|
+
const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
|
|
2111
|
+
const setValues = (formValues, options = {}) => {
|
|
2112
|
+
const updatedFormValues = isFunction(formValues)
|
|
2113
|
+
? formValues(_formValues)
|
|
2114
|
+
: formValues;
|
|
2115
|
+
if (!deepEqual(_formValues, updatedFormValues)) {
|
|
2116
|
+
_formValues = {
|
|
2117
|
+
..._formValues,
|
|
2118
|
+
...updatedFormValues,
|
|
2119
|
+
};
|
|
2120
|
+
for (const fieldName of _names.mount) {
|
|
2121
|
+
if (has(updatedFormValues, fieldName)) {
|
|
2122
|
+
_setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
1653
2125
|
_subjects.state.next({
|
|
1654
|
-
|
|
1655
|
-
|
|
2126
|
+
..._formState,
|
|
2127
|
+
name: undefined,
|
|
2128
|
+
type: undefined,
|
|
2129
|
+
...(_valuesSubscriberCount ? { values: _formValues } : {}),
|
|
1656
2130
|
});
|
|
2131
|
+
if (options.shouldValidate) {
|
|
2132
|
+
_setValid();
|
|
2133
|
+
}
|
|
1657
2134
|
}
|
|
1658
2135
|
};
|
|
1659
2136
|
const onChange = async (event) => {
|
|
@@ -1668,8 +2145,6 @@ function createFormControl(props = {}) {
|
|
|
1668
2145
|
(isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
|
|
1669
2146
|
deepEqual(fieldValue, get(_formValues, name, fieldValue));
|
|
1670
2147
|
};
|
|
1671
|
-
const validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1672
|
-
const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1673
2148
|
if (field) {
|
|
1674
2149
|
let error;
|
|
1675
2150
|
let isValid;
|
|
@@ -1677,17 +2152,20 @@ function createFormControl(props = {}) {
|
|
|
1677
2152
|
? getFieldValue(field._f)
|
|
1678
2153
|
: getEventValue(event);
|
|
1679
2154
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1680
|
-
const
|
|
2155
|
+
const hasNoValidationEffect = !hasValidation(field._f) &&
|
|
2156
|
+
!props.validate &&
|
|
1681
2157
|
!_options.resolver &&
|
|
1682
2158
|
!get(_formState.errors, name) &&
|
|
1683
|
-
!field._f.deps
|
|
1684
|
-
|
|
2159
|
+
!field._f.deps;
|
|
2160
|
+
const shouldSkipValidation = hasNoValidationEffect ||
|
|
2161
|
+
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
1685
2162
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
1686
|
-
set(_formValues, name, fieldValue);
|
|
2163
|
+
set(_formValues, name, cloneObject(fieldValue));
|
|
1687
2164
|
if (isBlurEvent) {
|
|
1688
2165
|
if (!target || !target.readOnly) {
|
|
1689
2166
|
field._f.onBlur && field._f.onBlur(event);
|
|
1690
|
-
|
|
2167
|
+
const pendingDelayError = delayErrorCallbacks[name];
|
|
2168
|
+
pendingDelayError && pendingDelayError(0);
|
|
1691
2169
|
}
|
|
1692
2170
|
}
|
|
1693
2171
|
else if (field._f.onChange) {
|
|
@@ -1699,10 +2177,13 @@ function createFormControl(props = {}) {
|
|
|
1699
2177
|
_subjects.state.next({
|
|
1700
2178
|
name,
|
|
1701
2179
|
type: event.type,
|
|
1702
|
-
|
|
2180
|
+
...(_valuesSubscriberCount
|
|
2181
|
+
? { values: cloneObject(_formValues) }
|
|
2182
|
+
: {}),
|
|
1703
2183
|
});
|
|
1704
2184
|
if (shouldSkipValidation) {
|
|
1705
|
-
if (
|
|
2185
|
+
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
2186
|
+
(_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
|
|
1706
2187
|
if (_options.mode === 'onBlur') {
|
|
1707
2188
|
if (isBlurEvent) {
|
|
1708
2189
|
_setValid();
|
|
@@ -1715,18 +2196,26 @@ function createFormControl(props = {}) {
|
|
|
1715
2196
|
return (shouldRender &&
|
|
1716
2197
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1717
2198
|
}
|
|
2199
|
+
if (!_options.resolver && props.validate) {
|
|
2200
|
+
await validateForm({
|
|
2201
|
+
name: name,
|
|
2202
|
+
eventType: event.type,
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
1718
2205
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1719
2206
|
if (_options.resolver) {
|
|
1720
2207
|
const { errors } = await _runSchema([name]);
|
|
1721
2208
|
_updateIsValidating([name]);
|
|
1722
2209
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1723
|
-
if (isFieldValueUpdated) {
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
error = errorLookupResult.error;
|
|
1727
|
-
name = errorLookupResult.name;
|
|
1728
|
-
isValid = isEmptyObject(errors);
|
|
2210
|
+
if (!isFieldValueUpdated) {
|
|
2211
|
+
!isEmptyObject(fieldState) && _subjects.state.next(fieldState);
|
|
2212
|
+
return;
|
|
1729
2213
|
}
|
|
2214
|
+
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
|
2215
|
+
const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
|
|
2216
|
+
error = errorLookupResult.error;
|
|
2217
|
+
name = errorLookupResult.name;
|
|
2218
|
+
isValid = isEmptyObject(errors);
|
|
1730
2219
|
}
|
|
1731
2220
|
else {
|
|
1732
2221
|
_updateIsValidating([name], true);
|
|
@@ -1739,7 +2228,12 @@ function createFormControl(props = {}) {
|
|
|
1739
2228
|
}
|
|
1740
2229
|
else if (_proxyFormState.isValid ||
|
|
1741
2230
|
_proxySubscribeFormState.isValid) {
|
|
1742
|
-
isValid = await executeBuiltInValidation(
|
|
2231
|
+
isValid = await executeBuiltInValidation({
|
|
2232
|
+
fields: _fields,
|
|
2233
|
+
onlyCheckValid: true,
|
|
2234
|
+
name: name,
|
|
2235
|
+
eventType: event.type,
|
|
2236
|
+
});
|
|
1743
2237
|
}
|
|
1744
2238
|
}
|
|
1745
2239
|
}
|
|
@@ -1772,12 +2266,37 @@ function createFormControl(props = {}) {
|
|
|
1772
2266
|
else if (name) {
|
|
1773
2267
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
1774
2268
|
const field = get(_fields, fieldName);
|
|
1775
|
-
return await executeBuiltInValidation(
|
|
2269
|
+
return await executeBuiltInValidation({
|
|
2270
|
+
fields: field && field._f ? { [fieldName]: field } : field,
|
|
2271
|
+
eventType: EVENTS.TRIGGER,
|
|
2272
|
+
});
|
|
1776
2273
|
}))).every(Boolean);
|
|
1777
2274
|
!(!validationResult && !_formState.isValid) && _setValid();
|
|
1778
2275
|
}
|
|
1779
2276
|
else {
|
|
1780
|
-
validationResult = isValid = await executeBuiltInValidation(
|
|
2277
|
+
validationResult = isValid = await executeBuiltInValidation({
|
|
2278
|
+
fields: _fields,
|
|
2279
|
+
name,
|
|
2280
|
+
eventType: EVENTS.TRIGGER,
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
if (options.delayError && _options.delayError && isString(name)) {
|
|
2284
|
+
const error = get(_formState.errors, name);
|
|
2285
|
+
if (error) {
|
|
2286
|
+
unset(_formState.errors, name);
|
|
2287
|
+
delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
|
|
2288
|
+
delayErrorCallbacks[name](_options.delayError);
|
|
2289
|
+
}
|
|
2290
|
+
else {
|
|
2291
|
+
clearTimeout(timers[name]);
|
|
2292
|
+
delete delayErrorCallbacks[name];
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
if (options.shouldTouch) {
|
|
2296
|
+
for (const fieldName of name ? fieldNames : _names.mount) {
|
|
2297
|
+
!_names.array.has(fieldName) &&
|
|
2298
|
+
set(_formState.touchedFields, fieldName, true);
|
|
2299
|
+
}
|
|
1781
2300
|
}
|
|
1782
2301
|
_subjects.state.next({
|
|
1783
2302
|
...(!isString(name) ||
|
|
@@ -1786,6 +2305,10 @@ function createFormControl(props = {}) {
|
|
|
1786
2305
|
? {}
|
|
1787
2306
|
: { name }),
|
|
1788
2307
|
...(_options.resolver || !name ? { isValid } : {}),
|
|
2308
|
+
...(options.shouldTouch &&
|
|
2309
|
+
(_proxyFormState.touchedFields || _proxySubscribeFormState.touchedFields)
|
|
2310
|
+
? { touchedFields: _formState.touchedFields }
|
|
2311
|
+
: {}),
|
|
1789
2312
|
errors: _formState.errors,
|
|
1790
2313
|
});
|
|
1791
2314
|
options.shouldFocus &&
|
|
@@ -1806,19 +2329,26 @@ function createFormControl(props = {}) {
|
|
|
1806
2329
|
? get(values, fieldNames)
|
|
1807
2330
|
: fieldNames.map((name) => get(values, name));
|
|
1808
2331
|
};
|
|
1809
|
-
const
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2332
|
+
const getErrors = (fieldNames) => isUndefined(fieldNames)
|
|
2333
|
+
? { ..._formState.errors }
|
|
2334
|
+
: isString(fieldNames)
|
|
2335
|
+
? get(_formState.errors, fieldNames)
|
|
2336
|
+
: fieldNames.map((name) => get(_formState.errors, name));
|
|
2337
|
+
const getFieldState = (name, formState) => {
|
|
2338
|
+
const targetFormState = formState || _formState;
|
|
2339
|
+
const error = get(targetFormState.errors, name);
|
|
2340
|
+
return {
|
|
2341
|
+
invalid: !!error,
|
|
2342
|
+
isDirty: !!get(targetFormState.dirtyFields, name),
|
|
2343
|
+
error,
|
|
2344
|
+
isValidating: !!get(_formState.validatingFields, name),
|
|
2345
|
+
isTouched: !!get(targetFormState.touchedFields, name),
|
|
2346
|
+
};
|
|
2347
|
+
};
|
|
1816
2348
|
const clearErrors = (name) => {
|
|
1817
2349
|
const names = name ? convertToArrayPayload(name) : undefined;
|
|
1818
2350
|
names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
|
|
1819
2351
|
if (names) {
|
|
1820
|
-
// Emit for each cleared field with the field name so that
|
|
1821
|
-
// shouldSubscribeByName can filter and avoid broad re-renders
|
|
1822
2352
|
names.forEach((inputName) => {
|
|
1823
2353
|
_subjects.state.next({
|
|
1824
2354
|
name: inputName,
|
|
@@ -1827,16 +2357,15 @@ function createFormControl(props = {}) {
|
|
|
1827
2357
|
});
|
|
1828
2358
|
}
|
|
1829
2359
|
else {
|
|
1830
|
-
|
|
2360
|
+
_formState.errors = {};
|
|
1831
2361
|
_subjects.state.next({
|
|
1832
|
-
errors:
|
|
2362
|
+
errors: _formState.errors,
|
|
1833
2363
|
});
|
|
1834
2364
|
}
|
|
1835
2365
|
};
|
|
1836
2366
|
const setError = (name, error, options) => {
|
|
1837
2367
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
1838
2368
|
const currentError = get(_formState.errors, name) || {};
|
|
1839
|
-
// Don't override existing error messages elsewhere in the object tree.
|
|
1840
2369
|
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
1841
2370
|
set(_formState.errors, name, {
|
|
1842
2371
|
...restOfErrorTree,
|
|
@@ -1850,25 +2379,60 @@ function createFormControl(props = {}) {
|
|
|
1850
2379
|
});
|
|
1851
2380
|
options && options.shouldFocus && ref && ref.focus && ref.focus();
|
|
1852
2381
|
};
|
|
1853
|
-
const watch = (name, defaultValue) =>
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
2382
|
+
const watch = (name, defaultValue) => {
|
|
2383
|
+
if (isFunction(name)) {
|
|
2384
|
+
_valuesSubscriberCount++;
|
|
2385
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2386
|
+
next: (payload) => 'values' in payload &&
|
|
2387
|
+
name(payload.values || _getWatch(undefined, defaultValue), payload),
|
|
2388
|
+
});
|
|
2389
|
+
let called = false;
|
|
2390
|
+
return {
|
|
2391
|
+
unsubscribe: () => {
|
|
2392
|
+
if (called) {
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
called = true;
|
|
2396
|
+
_valuesSubscriberCount--;
|
|
2397
|
+
unsubscribe();
|
|
2398
|
+
},
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
return _getWatch(name, defaultValue, true);
|
|
2402
|
+
};
|
|
2403
|
+
const _subscribe = (props) => {
|
|
2404
|
+
var _a;
|
|
2405
|
+
const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
|
|
2406
|
+
if (needsValues) {
|
|
2407
|
+
_valuesSubscriberCount++;
|
|
2408
|
+
}
|
|
2409
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2410
|
+
next: (formState) => {
|
|
2411
|
+
if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
|
|
2412
|
+
shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
|
|
2413
|
+
const snapshot = { ..._formValues };
|
|
2414
|
+
props.callback({
|
|
2415
|
+
values: snapshot,
|
|
2416
|
+
..._formState,
|
|
2417
|
+
...formState,
|
|
2418
|
+
defaultValues: _defaultValues,
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
},
|
|
2422
|
+
});
|
|
2423
|
+
if (!needsValues) {
|
|
2424
|
+
return unsubscribe;
|
|
2425
|
+
}
|
|
2426
|
+
let called = false;
|
|
2427
|
+
return () => {
|
|
2428
|
+
if (called) {
|
|
2429
|
+
return;
|
|
1869
2430
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
2431
|
+
called = true;
|
|
2432
|
+
_valuesSubscriberCount--;
|
|
2433
|
+
unsubscribe();
|
|
2434
|
+
};
|
|
2435
|
+
};
|
|
1872
2436
|
const subscribe = (props) => {
|
|
1873
2437
|
_state.mount = true;
|
|
1874
2438
|
_proxySubscribeFormState = {
|
|
@@ -1900,12 +2464,13 @@ function createFormControl(props = {}) {
|
|
|
1900
2464
|
!options.keepDefaultValue &&
|
|
1901
2465
|
unset(_defaultValues, fieldName);
|
|
1902
2466
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2467
|
+
_valuesSubscriberCount &&
|
|
2468
|
+
_subjects.state.next({
|
|
2469
|
+
values: cloneObject(_formValues),
|
|
2470
|
+
});
|
|
1906
2471
|
_subjects.state.next({
|
|
1907
2472
|
..._formState,
|
|
1908
|
-
...(
|
|
2473
|
+
...(options.keepDirty ? {} : { isDirty: _getDirty() }),
|
|
1909
2474
|
});
|
|
1910
2475
|
!options.keepIsValid && _setValid();
|
|
1911
2476
|
};
|
|
@@ -1923,6 +2488,7 @@ function createFormControl(props = {}) {
|
|
|
1923
2488
|
const register = (name, options = {}) => {
|
|
1924
2489
|
let field = get(_fields, name);
|
|
1925
2490
|
const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
|
|
2491
|
+
const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
|
|
1926
2492
|
set(_fields, name, {
|
|
1927
2493
|
...(field || {}),
|
|
1928
2494
|
_f: {
|
|
@@ -1933,7 +2499,7 @@ function createFormControl(props = {}) {
|
|
|
1933
2499
|
},
|
|
1934
2500
|
});
|
|
1935
2501
|
_names.mount.add(name);
|
|
1936
|
-
if (field) {
|
|
2502
|
+
if (field && !shouldRevalidateRemount) {
|
|
1937
2503
|
_setDisabledField({
|
|
1938
2504
|
disabled: isBoolean(options.disabled)
|
|
1939
2505
|
? options.disabled
|
|
@@ -1963,7 +2529,9 @@ function createFormControl(props = {}) {
|
|
|
1963
2529
|
onBlur: onChange,
|
|
1964
2530
|
ref: (ref) => {
|
|
1965
2531
|
if (ref) {
|
|
2532
|
+
_names.registerName.add(name);
|
|
1966
2533
|
register(name, options);
|
|
2534
|
+
_names.registerName.delete(name);
|
|
1967
2535
|
field = get(_fields, name);
|
|
1968
2536
|
const fieldRef = isUndefined(ref.value)
|
|
1969
2537
|
? ref.querySelectorAll
|
|
@@ -1977,20 +2545,23 @@ function createFormControl(props = {}) {
|
|
|
1977
2545
|
: fieldRef === field._f.ref) {
|
|
1978
2546
|
return;
|
|
1979
2547
|
}
|
|
2548
|
+
const newField = {
|
|
2549
|
+
...field._f,
|
|
2550
|
+
};
|
|
2551
|
+
if (radioOrCheckbox) {
|
|
2552
|
+
newField.refs = [
|
|
2553
|
+
...refs.filter(live),
|
|
2554
|
+
fieldRef,
|
|
2555
|
+
...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
|
|
2556
|
+
];
|
|
2557
|
+
newField.ref = { type: fieldRef.type, name };
|
|
2558
|
+
}
|
|
2559
|
+
else {
|
|
2560
|
+
newField.ref = fieldRef;
|
|
2561
|
+
delete newField.refs;
|
|
2562
|
+
}
|
|
1980
2563
|
set(_fields, name, {
|
|
1981
|
-
_f:
|
|
1982
|
-
...field._f,
|
|
1983
|
-
...(radioOrCheckbox
|
|
1984
|
-
? {
|
|
1985
|
-
refs: [
|
|
1986
|
-
...refs.filter(live),
|
|
1987
|
-
fieldRef,
|
|
1988
|
-
...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
|
|
1989
|
-
],
|
|
1990
|
-
ref: { type: fieldRef.type, name },
|
|
1991
|
-
}
|
|
1992
|
-
: { ref: fieldRef }),
|
|
1993
|
-
},
|
|
2564
|
+
_f: newField,
|
|
1994
2565
|
});
|
|
1995
2566
|
updateValidAndValue(name, false, undefined, fieldRef);
|
|
1996
2567
|
}
|
|
@@ -2007,6 +2578,7 @@ function createFormControl(props = {}) {
|
|
|
2007
2578
|
};
|
|
2008
2579
|
};
|
|
2009
2580
|
const _focusError = () => _options.shouldFocusError &&
|
|
2581
|
+
!_options.shouldUseNativeValidation &&
|
|
2010
2582
|
iterateFieldsByAction(_fields, _focusInput, _names.mount);
|
|
2011
2583
|
const _disableForm = (disabled) => {
|
|
2012
2584
|
if (isBoolean(disabled)) {
|
|
@@ -2025,6 +2597,7 @@ function createFormControl(props = {}) {
|
|
|
2025
2597
|
}
|
|
2026
2598
|
};
|
|
2027
2599
|
const handleSubmit = (onValid, onInvalid) => async (e) => {
|
|
2600
|
+
let result = undefined;
|
|
2028
2601
|
let onValidError = undefined;
|
|
2029
2602
|
if (e) {
|
|
2030
2603
|
e.preventDefault && e.preventDefault();
|
|
@@ -2042,20 +2615,23 @@ function createFormControl(props = {}) {
|
|
|
2042
2615
|
fieldValues = cloneObject(values);
|
|
2043
2616
|
}
|
|
2044
2617
|
else {
|
|
2045
|
-
await executeBuiltInValidation(
|
|
2618
|
+
await executeBuiltInValidation({
|
|
2619
|
+
fields: _fields,
|
|
2620
|
+
eventType: EVENTS.SUBMIT,
|
|
2621
|
+
});
|
|
2046
2622
|
}
|
|
2047
2623
|
if (_names.disabled.size) {
|
|
2048
2624
|
for (const name of _names.disabled) {
|
|
2049
2625
|
unset(fieldValues, name);
|
|
2050
2626
|
}
|
|
2051
2627
|
}
|
|
2052
|
-
unset(_formState.errors,
|
|
2628
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
2053
2629
|
if (isEmptyObject(_formState.errors)) {
|
|
2054
2630
|
_subjects.state.next({
|
|
2055
2631
|
errors: {},
|
|
2056
2632
|
});
|
|
2057
2633
|
try {
|
|
2058
|
-
await onValid(fieldValues, e);
|
|
2634
|
+
result = await onValid(fieldValues, e);
|
|
2059
2635
|
}
|
|
2060
2636
|
catch (error) {
|
|
2061
2637
|
onValidError = error;
|
|
@@ -2078,6 +2654,7 @@ function createFormControl(props = {}) {
|
|
|
2078
2654
|
if (onValidError) {
|
|
2079
2655
|
throw onValidError;
|
|
2080
2656
|
}
|
|
2657
|
+
return result;
|
|
2081
2658
|
};
|
|
2082
2659
|
const resetField = (name, options = {}) => {
|
|
2083
2660
|
if (get(_fields, name)) {
|
|
@@ -2099,7 +2676,7 @@ function createFormControl(props = {}) {
|
|
|
2099
2676
|
}
|
|
2100
2677
|
if (!options.keepError) {
|
|
2101
2678
|
unset(_formState.errors, name);
|
|
2102
|
-
|
|
2679
|
+
_setValid();
|
|
2103
2680
|
}
|
|
2104
2681
|
_subjects.state.next({ ..._formState });
|
|
2105
2682
|
}
|
|
@@ -2108,7 +2685,8 @@ function createFormControl(props = {}) {
|
|
|
2108
2685
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
2109
2686
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
2110
2687
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
2111
|
-
const values =
|
|
2688
|
+
const values = cloneUpdatedValues;
|
|
2689
|
+
const fieldRefs = _fields;
|
|
2112
2690
|
if (!keepStateOptions.keepDefaultValues) {
|
|
2113
2691
|
_defaultValues = updatedValues;
|
|
2114
2692
|
}
|
|
@@ -2116,9 +2694,9 @@ function createFormControl(props = {}) {
|
|
|
2116
2694
|
if (keepStateOptions.keepDirtyValues) {
|
|
2117
2695
|
const fieldsToCheck = new Set([
|
|
2118
2696
|
..._names.mount,
|
|
2119
|
-
...
|
|
2697
|
+
...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
|
|
2120
2698
|
]);
|
|
2121
|
-
for (const fieldName of
|
|
2699
|
+
for (const fieldName of fieldsToCheck) {
|
|
2122
2700
|
const isDirty = get(_formState.dirtyFields, fieldName);
|
|
2123
2701
|
const existingValue = get(_formValues, fieldName);
|
|
2124
2702
|
const newValue = get(values, fieldName);
|
|
@@ -2157,15 +2735,25 @@ function createFormControl(props = {}) {
|
|
|
2157
2735
|
_fields = {};
|
|
2158
2736
|
}
|
|
2159
2737
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2738
|
+
if (_options.shouldUnregister) {
|
|
2739
|
+
_formValues = keepStateOptions.keepDefaultValues
|
|
2162
2740
|
? cloneObject(_defaultValues)
|
|
2163
|
-
: {}
|
|
2164
|
-
|
|
2741
|
+
: {};
|
|
2742
|
+
if (keepStateOptions.keepFieldsRef) {
|
|
2743
|
+
for (const fieldName of _names.mount) {
|
|
2744
|
+
set(_formValues, fieldName, get(values, fieldName));
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
else {
|
|
2749
|
+
_formValues = cloneObject(values);
|
|
2750
|
+
}
|
|
2165
2751
|
_subjects.array.next({
|
|
2166
2752
|
values: { ...values },
|
|
2167
2753
|
});
|
|
2168
2754
|
_subjects.state.next({
|
|
2755
|
+
name: undefined,
|
|
2756
|
+
type: undefined,
|
|
2169
2757
|
values: { ...values },
|
|
2170
2758
|
});
|
|
2171
2759
|
}
|
|
@@ -2173,6 +2761,7 @@ function createFormControl(props = {}) {
|
|
|
2173
2761
|
mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
|
|
2174
2762
|
unMount: new Set(),
|
|
2175
2763
|
array: new Set(),
|
|
2764
|
+
registerName: new Set(),
|
|
2176
2765
|
disabled: new Set(),
|
|
2177
2766
|
watch: new Set(),
|
|
2178
2767
|
watchAll: false,
|
|
@@ -2186,9 +2775,7 @@ function createFormControl(props = {}) {
|
|
|
2186
2775
|
_state.watch = !!_options.shouldUnregister;
|
|
2187
2776
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
2188
2777
|
_state.action = false;
|
|
2189
|
-
|
|
2190
|
-
// This fixes the issue where form.reset() causes validation errors on subsequent
|
|
2191
|
-
// submissions in Next.js 16 with Server Actions
|
|
2778
|
+
_state.actionArrayLengths.clear();
|
|
2192
2779
|
if (!keepStateOptions.keepErrors) {
|
|
2193
2780
|
_formState.errors = {};
|
|
2194
2781
|
}
|
|
@@ -2200,8 +2787,10 @@ function createFormControl(props = {}) {
|
|
|
2200
2787
|
? false
|
|
2201
2788
|
: keepStateOptions.keepDirty
|
|
2202
2789
|
? _formState.isDirty
|
|
2203
|
-
:
|
|
2204
|
-
|
|
2790
|
+
: keepStateOptions.keepValues
|
|
2791
|
+
? _getDirty()
|
|
2792
|
+
: !!(keepStateOptions.keepDefaultValues &&
|
|
2793
|
+
!deepEqual(formValues, _defaultValues)),
|
|
2205
2794
|
isSubmitted: keepStateOptions.keepIsSubmitted
|
|
2206
2795
|
? _formState.isSubmitted
|
|
2207
2796
|
: false,
|
|
@@ -2209,10 +2798,10 @@ function createFormControl(props = {}) {
|
|
|
2209
2798
|
? {}
|
|
2210
2799
|
: keepStateOptions.keepDirtyValues
|
|
2211
2800
|
? keepStateOptions.keepDefaultValues && _formValues
|
|
2212
|
-
? getDirtyFields(_defaultValues, _formValues)
|
|
2801
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
2213
2802
|
: _formState.dirtyFields
|
|
2214
2803
|
: keepStateOptions.keepDefaultValues && formValues
|
|
2215
|
-
? getDirtyFields(_defaultValues, formValues)
|
|
2804
|
+
? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
|
|
2216
2805
|
: keepStateOptions.keepDirty
|
|
2217
2806
|
? _formState.dirtyFields
|
|
2218
2807
|
: {},
|
|
@@ -2238,8 +2827,6 @@ function createFormControl(props = {}) {
|
|
|
2238
2827
|
? fieldReference.refs[0]
|
|
2239
2828
|
: fieldReference.ref;
|
|
2240
2829
|
if (fieldRef.focus) {
|
|
2241
|
-
// Use setTimeout to ensure focus happens after any pending state updates
|
|
2242
|
-
// This fixes the issue where setFocus doesn't work immediately after setError
|
|
2243
2830
|
setTimeout(() => {
|
|
2244
2831
|
fieldRef.focus();
|
|
2245
2832
|
options.shouldSelect &&
|
|
@@ -2250,11 +2837,18 @@ function createFormControl(props = {}) {
|
|
|
2250
2837
|
}
|
|
2251
2838
|
};
|
|
2252
2839
|
const _setFormState = (updatedFormState) => {
|
|
2840
|
+
// `name`, `type`, and `values` describe the event that produced this
|
|
2841
|
+
// update, not the form's persisted state (they aren't part of
|
|
2842
|
+
// `FormState`). Merging them in would leak a stale `name`/`type` from
|
|
2843
|
+
// one event into a later, unrelated notification that doesn't specify
|
|
2844
|
+
// its own.
|
|
2845
|
+
const { name, type, values, ...formState } = updatedFormState;
|
|
2253
2846
|
_formState = {
|
|
2254
2847
|
..._formState,
|
|
2255
|
-
...
|
|
2848
|
+
...formState,
|
|
2256
2849
|
};
|
|
2257
2850
|
};
|
|
2851
|
+
_subjects.state.subscribe({ next: _setFormState });
|
|
2258
2852
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
2259
2853
|
_options.defaultValues().then((values) => {
|
|
2260
2854
|
reset(values, _options.resetOptions);
|
|
@@ -2262,6 +2856,21 @@ function createFormControl(props = {}) {
|
|
|
2262
2856
|
isLoading: false,
|
|
2263
2857
|
});
|
|
2264
2858
|
});
|
|
2859
|
+
const resetDefaultValues = (values, options = {}) => {
|
|
2860
|
+
_defaultValues = cloneObject(values);
|
|
2861
|
+
if (!options.keepDirty) {
|
|
2862
|
+
const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
|
|
2863
|
+
_formState.dirtyFields = newDirtyFields;
|
|
2864
|
+
_formState.isDirty = !isEmptyObject(newDirtyFields);
|
|
2865
|
+
}
|
|
2866
|
+
if (!options.keepIsValid) {
|
|
2867
|
+
_setValid();
|
|
2868
|
+
}
|
|
2869
|
+
_subjects.state.next({
|
|
2870
|
+
..._formState,
|
|
2871
|
+
defaultValues: _defaultValues,
|
|
2872
|
+
});
|
|
2873
|
+
};
|
|
2265
2874
|
const methods = {
|
|
2266
2875
|
control: {
|
|
2267
2876
|
register,
|
|
@@ -2318,6 +2927,8 @@ function createFormControl(props = {}) {
|
|
|
2318
2927
|
..._options,
|
|
2319
2928
|
...value,
|
|
2320
2929
|
};
|
|
2930
|
+
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2931
|
+
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2321
2932
|
},
|
|
2322
2933
|
},
|
|
2323
2934
|
subscribe,
|
|
@@ -2326,9 +2937,12 @@ function createFormControl(props = {}) {
|
|
|
2326
2937
|
handleSubmit,
|
|
2327
2938
|
watch,
|
|
2328
2939
|
setValue,
|
|
2940
|
+
setValues,
|
|
2329
2941
|
getValues,
|
|
2942
|
+
getErrors,
|
|
2330
2943
|
reset,
|
|
2331
2944
|
resetField,
|
|
2945
|
+
resetDefaultValues,
|
|
2332
2946
|
clearErrors,
|
|
2333
2947
|
unregister,
|
|
2334
2948
|
setError,
|
|
@@ -2373,26 +2987,19 @@ function createFormControl(props = {}) {
|
|
|
2373
2987
|
function useForm(props = {}) {
|
|
2374
2988
|
const _formControl = React__default.useRef(undefined);
|
|
2375
2989
|
const _values = React__default.useRef(undefined);
|
|
2376
|
-
const
|
|
2377
|
-
|
|
2378
|
-
|
|
2990
|
+
const _formControlProp = React__default.useRef(props.formControl);
|
|
2991
|
+
const [formState, updateFormState] = React__default.useState(() => ({
|
|
2992
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
2379
2993
|
isLoading: isFunction(props.defaultValues),
|
|
2380
|
-
isSubmitted: false,
|
|
2381
|
-
isSubmitting: false,
|
|
2382
|
-
isSubmitSuccessful: false,
|
|
2383
|
-
isValid: false,
|
|
2384
|
-
submitCount: 0,
|
|
2385
|
-
dirtyFields: {},
|
|
2386
|
-
touchedFields: {},
|
|
2387
|
-
validatingFields: {},
|
|
2388
2994
|
errors: props.errors || {},
|
|
2389
2995
|
disabled: props.disabled || false,
|
|
2390
|
-
isReady: false,
|
|
2391
2996
|
defaultValues: isFunction(props.defaultValues)
|
|
2392
2997
|
? undefined
|
|
2393
2998
|
: props.defaultValues,
|
|
2394
|
-
});
|
|
2395
|
-
if (!_formControl.current
|
|
2999
|
+
}));
|
|
3000
|
+
if (!_formControl.current ||
|
|
3001
|
+
(props.formControl && _formControlProp.current !== props.formControl)) {
|
|
3002
|
+
_formControlProp.current = props.formControl;
|
|
2396
3003
|
if (props.formControl) {
|
|
2397
3004
|
_formControl.current = {
|
|
2398
3005
|
...props.formControl,
|
|
@@ -2412,10 +3019,19 @@ function useForm(props = {}) {
|
|
|
2412
3019
|
}
|
|
2413
3020
|
const control = _formControl.current.control;
|
|
2414
3021
|
control._options = props;
|
|
3022
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
2415
3023
|
useIsomorphicLayoutEffect(() => {
|
|
2416
|
-
const
|
|
3024
|
+
const getCurrentFormState = () => ({
|
|
3025
|
+
...control._formState,
|
|
3026
|
+
defaultValues: control._defaultValues,
|
|
3027
|
+
});
|
|
3028
|
+
resyncIfNeeded(true, getCurrentFormState, updateFormState);
|
|
3029
|
+
const unsubscribe = control._subscribe({
|
|
2417
3030
|
formState: control._proxyFormState,
|
|
2418
|
-
callback: () => updateFormState({
|
|
3031
|
+
callback: () => updateFormState({
|
|
3032
|
+
...control._formState,
|
|
3033
|
+
defaultValues: control._defaultValues,
|
|
3034
|
+
}),
|
|
2419
3035
|
reRenderRoot: true,
|
|
2420
3036
|
});
|
|
2421
3037
|
updateFormState((data) => ({
|
|
@@ -2423,8 +3039,11 @@ function useForm(props = {}) {
|
|
|
2423
3039
|
isReady: true,
|
|
2424
3040
|
}));
|
|
2425
3041
|
control._formState.isReady = true;
|
|
2426
|
-
return
|
|
2427
|
-
|
|
3042
|
+
return () => {
|
|
3043
|
+
unsubscribe();
|
|
3044
|
+
snapshot(true, getCurrentFormState);
|
|
3045
|
+
};
|
|
3046
|
+
}, [control, resyncIfNeeded, snapshot]);
|
|
2428
3047
|
React__default.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]);
|
|
2429
3048
|
React__default.useEffect(() => {
|
|
2430
3049
|
if (props.mode) {
|