@depup/react-hook-form 7.83.0-depup.0 → 7.85.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/changes.json +1 -1
- package/dist/fieldArray.d.ts +2 -1
- package/dist/fieldArray.d.ts.map +1 -1
- package/dist/form.d.ts +1 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/formStateSubscribe.d.ts +8 -3
- package/dist/formStateSubscribe.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.mjs +311 -150
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/collectDirtyFieldNames.d.ts +3 -0
- package/dist/logic/collectDirtyFieldNames.d.ts.map +1 -0
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/getFieldValue.d.ts.map +1 -1
- package/dist/logic/iterateFieldsByAction.d.ts.map +1 -1
- package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
- package/dist/logic/unsetEmptyArray.d.ts +1 -1
- package/dist/logic/unsetEmptyArray.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +102 -26
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/errors.d.ts +6 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/form.d.ts +8 -6
- package/dist/types/form.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useResyncOnReconnect.d.ts +5 -0
- package/dist/useResyncOnReconnect.d.ts.map +1 -0
- package/dist/useWatch.d.ts.map +1 -1
- package/dist/utils/formData.d.ts +3 -0
- package/dist/utils/formData.d.ts.map +1 -0
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/package.json +4 -10
- package/dist/logic/getNodeParentName.d.ts +0 -3
- package/dist/logic/getNodeParentName.d.ts.map +0 -1
- package/dist/utils/deepMerge.d.ts +0 -2
- package/dist/utils/deepMerge.d.ts.map +0 -1
package/dist/index.esm.mjs
CHANGED
|
@@ -170,6 +170,82 @@ const useIsomorphicLayoutEffect = isWeb
|
|
|
170
170
|
? React.useLayoutEffect
|
|
171
171
|
: React.useEffect;
|
|
172
172
|
|
|
173
|
+
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
174
|
+
|
|
175
|
+
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
176
|
+
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
177
|
+
if (object1 === object2) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
181
|
+
return Object.is(object1, object2);
|
|
182
|
+
}
|
|
183
|
+
if (isDateObject(object1) && isDateObject(object2)) {
|
|
184
|
+
return Object.is(object1.getTime(), object2.getTime());
|
|
185
|
+
}
|
|
186
|
+
const keys1 = Object.keys(object1);
|
|
187
|
+
const keys2 = Object.keys(object2);
|
|
188
|
+
if (keys1.length !== keys2.length) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
192
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
193
|
+
return Object.is(object1, object2);
|
|
194
|
+
}
|
|
195
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const visitedPairs = visited.get(object1);
|
|
199
|
+
if (visitedPairs && visitedPairs.has(object2)) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (visitedPairs) {
|
|
203
|
+
visitedPairs.add(object2);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const ws = new WeakSet();
|
|
207
|
+
ws.add(object2);
|
|
208
|
+
visited.set(object1, ws);
|
|
209
|
+
}
|
|
210
|
+
for (const key of keys1) {
|
|
211
|
+
const val1 = object1[key];
|
|
212
|
+
if (!(key in object2)) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
if (key !== 'ref') {
|
|
216
|
+
const val2 = object2[key];
|
|
217
|
+
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
218
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
219
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
220
|
+
? !deepEqual(val1, val2, visited)
|
|
221
|
+
: !Object.is(val1, val2)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function useResyncOnReconnect() {
|
|
230
|
+
const _connected = React.useRef(false);
|
|
231
|
+
const _prevValue = React.useRef(undefined);
|
|
232
|
+
const resyncIfNeeded = React.useCallback((enabled, getCurrentValue, setValue) => {
|
|
233
|
+
if (enabled && _connected.current) {
|
|
234
|
+
const currentValue = getCurrentValue();
|
|
235
|
+
if (!deepEqual(_prevValue.current, currentValue)) {
|
|
236
|
+
setValue(currentValue);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
_connected.current = true;
|
|
240
|
+
}, []);
|
|
241
|
+
const snapshot = React.useCallback((enabled, getCurrentValue) => {
|
|
242
|
+
if (enabled) {
|
|
243
|
+
_prevValue.current = cloneObject(getCurrentValue());
|
|
244
|
+
}
|
|
245
|
+
}, []);
|
|
246
|
+
return { resyncIfNeeded, snapshot };
|
|
247
|
+
}
|
|
248
|
+
|
|
173
249
|
/**
|
|
174
250
|
* 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.
|
|
175
251
|
*
|
|
@@ -217,19 +293,31 @@ function useFormState(props) {
|
|
|
217
293
|
isValid: false,
|
|
218
294
|
errors: false,
|
|
219
295
|
});
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
296
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
297
|
+
useIsomorphicLayoutEffect(() => {
|
|
298
|
+
const getCurrentFormState = () => ({
|
|
299
|
+
...control._formState,
|
|
300
|
+
defaultValues: control._defaultValues,
|
|
301
|
+
});
|
|
302
|
+
resyncIfNeeded(!disabled, getCurrentFormState, updateFormState);
|
|
303
|
+
const unsubscribe = control._subscribe({
|
|
304
|
+
name,
|
|
305
|
+
formState: _localProxyFormState.current,
|
|
306
|
+
exact,
|
|
307
|
+
callback: (formState) => {
|
|
308
|
+
!disabled &&
|
|
309
|
+
updateFormState({
|
|
310
|
+
...control._formState,
|
|
311
|
+
...formState,
|
|
312
|
+
defaultValues: control._defaultValues,
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
return () => {
|
|
317
|
+
unsubscribe();
|
|
318
|
+
snapshot(!disabled, getCurrentFormState);
|
|
319
|
+
};
|
|
320
|
+
}, [name, disabled, exact, resyncIfNeeded, snapshot]);
|
|
233
321
|
React.useEffect(() => {
|
|
234
322
|
_localProxyFormState.current.isValid && control._setValid(true);
|
|
235
323
|
}, [control]);
|
|
@@ -251,62 +339,6 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
251
339
|
return formValues;
|
|
252
340
|
};
|
|
253
341
|
|
|
254
|
-
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
255
|
-
|
|
256
|
-
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
257
|
-
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
258
|
-
if (object1 === object2) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
262
|
-
return Object.is(object1, object2);
|
|
263
|
-
}
|
|
264
|
-
if (isDateObject(object1) && isDateObject(object2)) {
|
|
265
|
-
return Object.is(object1.getTime(), object2.getTime());
|
|
266
|
-
}
|
|
267
|
-
const keys1 = Object.keys(object1);
|
|
268
|
-
const keys2 = Object.keys(object2);
|
|
269
|
-
if (keys1.length !== keys2.length) {
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
273
|
-
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
274
|
-
return Object.is(object1, object2);
|
|
275
|
-
}
|
|
276
|
-
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
const visitedPairs = visited.get(object1);
|
|
280
|
-
if (visitedPairs && visitedPairs.has(object2)) {
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
if (visitedPairs) {
|
|
284
|
-
visitedPairs.add(object2);
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
const ws = new WeakSet();
|
|
288
|
-
ws.add(object2);
|
|
289
|
-
visited.set(object1, ws);
|
|
290
|
-
}
|
|
291
|
-
for (const key of keys1) {
|
|
292
|
-
const val1 = object1[key];
|
|
293
|
-
if (!(key in object2)) {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
if (key !== 'ref') {
|
|
297
|
-
const val2 = object2[key];
|
|
298
|
-
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
299
|
-
((isObject(val1) || Array.isArray(val1)) &&
|
|
300
|
-
(isObject(val2) || Array.isArray(val2)))
|
|
301
|
-
? !deepEqual(val1, val2, visited)
|
|
302
|
-
: !Object.is(val1, val2)) {
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
342
|
/**
|
|
311
343
|
* Custom hook to subscribe to field changes and isolate re-rendering at the component level.
|
|
312
344
|
*
|
|
@@ -355,24 +387,39 @@ function useWatch(props) {
|
|
|
355
387
|
}
|
|
356
388
|
}
|
|
357
389
|
}, [control._formValues, control._names, disabled, name]);
|
|
390
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
391
|
+
const _refreshValue = React.useRef(refreshValue);
|
|
392
|
+
_refreshValue.current = refreshValue;
|
|
393
|
+
const _getCurrentOutput = React.useRef(getCurrentOutput);
|
|
394
|
+
_getCurrentOutput.current = getCurrentOutput;
|
|
358
395
|
useIsomorphicLayoutEffect(() => {
|
|
359
396
|
if (_prevControl.current !== control ||
|
|
360
397
|
!deepEqual(_prevName.current, name)) {
|
|
361
398
|
_prevControl.current = control;
|
|
362
399
|
_prevName.current = name;
|
|
363
|
-
|
|
400
|
+
_refreshValue.current();
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
resyncIfNeeded(!disabled, () => _getCurrentOutput.current(), (currentValue) => {
|
|
404
|
+
updateValue(currentValue);
|
|
405
|
+
_computeFormValues.current = currentValue;
|
|
406
|
+
});
|
|
364
407
|
}
|
|
365
|
-
|
|
408
|
+
const unsubscribe = control._subscribe({
|
|
366
409
|
name,
|
|
367
410
|
formState: {
|
|
368
411
|
values: true,
|
|
369
412
|
},
|
|
370
413
|
exact,
|
|
371
414
|
callback: (formState) => {
|
|
372
|
-
|
|
415
|
+
_refreshValue.current(formState.values);
|
|
373
416
|
},
|
|
374
417
|
});
|
|
375
|
-
|
|
418
|
+
return () => {
|
|
419
|
+
unsubscribe();
|
|
420
|
+
snapshot(!disabled, () => _getCurrentOutput.current());
|
|
421
|
+
};
|
|
422
|
+
}, [control, exact, name, disabled, resyncIfNeeded, snapshot]);
|
|
376
423
|
React.useEffect(() => control._removeUnmounted());
|
|
377
424
|
// If name or control changed for this render, synchronously reflect the
|
|
378
425
|
// latest value so callers (like useController) see the correct value
|
|
@@ -644,9 +691,12 @@ var isWatched = (name, _names, isBlurEvent) => {
|
|
|
644
691
|
|
|
645
692
|
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
646
693
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
647
|
-
|
|
694
|
+
if (key === '_f') {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
const field = fieldsNames ? get(fields, key) : fields[key];
|
|
648
698
|
if (field) {
|
|
649
|
-
const { _f
|
|
699
|
+
const { _f } = field;
|
|
650
700
|
if (_f) {
|
|
651
701
|
if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
|
|
652
702
|
return true;
|
|
@@ -655,13 +705,13 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
|
655
705
|
return true;
|
|
656
706
|
}
|
|
657
707
|
else {
|
|
658
|
-
if (iterateFieldsByAction(
|
|
708
|
+
if (iterateFieldsByAction(field, action)) {
|
|
659
709
|
break;
|
|
660
710
|
}
|
|
661
711
|
}
|
|
662
712
|
}
|
|
663
|
-
else if (isObject(
|
|
664
|
-
if (iterateFieldsByAction(
|
|
713
|
+
else if (isObject(field) || Array.isArray(field)) {
|
|
714
|
+
if (iterateFieldsByAction(field, action)) {
|
|
665
715
|
break;
|
|
666
716
|
}
|
|
667
717
|
}
|
|
@@ -827,7 +877,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
827
877
|
let exceedMin;
|
|
828
878
|
const maxOutput = getValueAndMessage(max);
|
|
829
879
|
const minOutput = getValueAndMessage(min);
|
|
830
|
-
if (!isNullOrUndefined(inputValue) &&
|
|
880
|
+
if (!isNullOrUndefined(inputValue) &&
|
|
881
|
+
!isDateObject(inputValue) &&
|
|
882
|
+
!isNaN(inputValue)) {
|
|
831
883
|
const valueNumber = ref.valueAsNumber ||
|
|
832
884
|
(inputValue ? +inputValue : inputValue);
|
|
833
885
|
if (!isNullOrUndefined(maxOutput.value)) {
|
|
@@ -998,7 +1050,7 @@ var swapArrayAt = (data, indexA, indexB) => {
|
|
|
998
1050
|
};
|
|
999
1051
|
|
|
1000
1052
|
function baseGet(object, updatePath) {
|
|
1001
|
-
const length = updatePath.
|
|
1053
|
+
const length = updatePath.length - 1;
|
|
1002
1054
|
let index = 0;
|
|
1003
1055
|
while (index < length) {
|
|
1004
1056
|
if (isNullOrUndefined(object)) {
|
|
@@ -1235,9 +1287,11 @@ function useFieldArray(props) {
|
|
|
1235
1287
|
};
|
|
1236
1288
|
React.useEffect(() => {
|
|
1237
1289
|
if (disabled) {
|
|
1290
|
+
control._state.actionArrayLengths.delete(name);
|
|
1238
1291
|
return;
|
|
1239
1292
|
}
|
|
1240
1293
|
control._state.action = false;
|
|
1294
|
+
control._state.actionArrayLengths.delete(name);
|
|
1241
1295
|
isWatched(name, control._names) &&
|
|
1242
1296
|
control._subjects.state.next({
|
|
1243
1297
|
...control._formState,
|
|
@@ -1317,6 +1371,7 @@ function useFieldArray(props) {
|
|
|
1317
1371
|
!get(control._formValues, name) && control._setFieldArray(name);
|
|
1318
1372
|
}
|
|
1319
1373
|
return () => {
|
|
1374
|
+
control._state.actionArrayLengths.delete(name);
|
|
1320
1375
|
if (disabled) {
|
|
1321
1376
|
return;
|
|
1322
1377
|
}
|
|
@@ -1417,6 +1472,26 @@ const flatten = (obj) => {
|
|
|
1417
1472
|
return output;
|
|
1418
1473
|
};
|
|
1419
1474
|
|
|
1475
|
+
function jsonToFormData(json) {
|
|
1476
|
+
const result = new FormData();
|
|
1477
|
+
const flattenFormValues = flatten(json);
|
|
1478
|
+
for (const key in flattenFormValues) {
|
|
1479
|
+
result.append(key, flattenFormValues[key]);
|
|
1480
|
+
}
|
|
1481
|
+
return result;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function safeJSONStringify(value) {
|
|
1485
|
+
try {
|
|
1486
|
+
return JSON.stringify(value);
|
|
1487
|
+
}
|
|
1488
|
+
catch (_a) {
|
|
1489
|
+
return '';
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
function noop() { }
|
|
1494
|
+
|
|
1420
1495
|
const HookFormContext = React.createContext(null);
|
|
1421
1496
|
HookFormContext.displayName = 'HookFormContext';
|
|
1422
1497
|
/**
|
|
@@ -1525,6 +1600,9 @@ const FormProvider = ({ children, watch, getValues, getFieldState, setError, cle
|
|
|
1525
1600
|
};
|
|
1526
1601
|
|
|
1527
1602
|
const POST_REQUEST = 'post';
|
|
1603
|
+
function defaultValidateStatus(status) {
|
|
1604
|
+
return status >= 200 && status < 300;
|
|
1605
|
+
}
|
|
1528
1606
|
/**
|
|
1529
1607
|
* Form component to manage submission.
|
|
1530
1608
|
*
|
|
@@ -1550,21 +1628,11 @@ const POST_REQUEST = 'post';
|
|
|
1550
1628
|
function Form(props) {
|
|
1551
1629
|
const methods = useFormContext();
|
|
1552
1630
|
const [mounted, setMounted] = React.useState(false);
|
|
1553
|
-
const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
const formData = new FormData();
|
|
1559
|
-
let formDataJson = '';
|
|
1560
|
-
try {
|
|
1561
|
-
formDataJson = JSON.stringify(data);
|
|
1562
|
-
}
|
|
1563
|
-
catch (_a) { }
|
|
1564
|
-
const flattenFormValues = flatten(data);
|
|
1565
|
-
for (const key in flattenFormValues) {
|
|
1566
|
-
formData.append(key, flattenFormValues[key]);
|
|
1567
|
-
}
|
|
1631
|
+
const { control = methods.control, onSubmit = noop, children, action, method = POST_REQUEST, headers, encType, onError = noop, render, onSuccess = noop, validateStatus = defaultValidateStatus, ...rest } = props;
|
|
1632
|
+
const handleSubmit = React.useMemo(() => {
|
|
1633
|
+
return control.handleSubmit(async (data, event) => {
|
|
1634
|
+
const formData = jsonToFormData(data);
|
|
1635
|
+
const formDataJson = safeJSONStringify(data);
|
|
1568
1636
|
if (onSubmit) {
|
|
1569
1637
|
await onSubmit({
|
|
1570
1638
|
data,
|
|
@@ -1574,48 +1642,48 @@ function Form(props) {
|
|
|
1574
1642
|
formDataJson,
|
|
1575
1643
|
});
|
|
1576
1644
|
}
|
|
1577
|
-
if (action) {
|
|
1645
|
+
if (isString(action)) {
|
|
1578
1646
|
try {
|
|
1579
|
-
const shouldStringifySubmissionData =
|
|
1580
|
-
headers
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
const response = await fetch(
|
|
1647
|
+
const shouldStringifySubmissionData = (headers &&
|
|
1648
|
+
headers['Content-Type'] &&
|
|
1649
|
+
headers['Content-Type'].includes('json')) ||
|
|
1650
|
+
(encType && encType.includes('json'));
|
|
1651
|
+
const response = await fetch(action, {
|
|
1584
1652
|
method,
|
|
1585
1653
|
headers: {
|
|
1586
1654
|
...headers,
|
|
1587
|
-
...(encType &&
|
|
1588
|
-
|
|
1589
|
-
:
|
|
1655
|
+
...(encType &&
|
|
1656
|
+
encType !== 'multipart/form-data' && {
|
|
1657
|
+
'Content-Type': encType,
|
|
1658
|
+
}),
|
|
1590
1659
|
},
|
|
1591
1660
|
body: shouldStringifySubmissionData ? formDataJson : formData,
|
|
1592
1661
|
});
|
|
1593
|
-
if (response &&
|
|
1594
|
-
(
|
|
1595
|
-
|
|
1596
|
-
: response.status < 200 || response.status >= 300)) {
|
|
1597
|
-
hasError = true;
|
|
1598
|
-
onError && onError({ response });
|
|
1599
|
-
type = String(response.status);
|
|
1662
|
+
if (response && !validateStatus(response.status)) {
|
|
1663
|
+
onError({ response });
|
|
1664
|
+
return { type: String(response.status) };
|
|
1600
1665
|
}
|
|
1601
1666
|
else {
|
|
1602
|
-
onSuccess
|
|
1667
|
+
onSuccess({ response });
|
|
1603
1668
|
}
|
|
1604
1669
|
}
|
|
1605
1670
|
catch (error) {
|
|
1606
|
-
|
|
1607
|
-
|
|
1671
|
+
onError({ error });
|
|
1672
|
+
return { type: '' };
|
|
1608
1673
|
}
|
|
1609
1674
|
}
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1675
|
+
if (isFunction(action)) {
|
|
1676
|
+
try {
|
|
1677
|
+
await action(formData);
|
|
1678
|
+
}
|
|
1679
|
+
catch (error) {
|
|
1680
|
+
onError({ error });
|
|
1681
|
+
return { type: '' };
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
// Return nothing when successful.
|
|
1685
|
+
return;
|
|
1686
|
+
});
|
|
1619
1687
|
}, [
|
|
1620
1688
|
control,
|
|
1621
1689
|
onSubmit,
|
|
@@ -1627,15 +1695,28 @@ function Form(props) {
|
|
|
1627
1695
|
onError,
|
|
1628
1696
|
onSuccess,
|
|
1629
1697
|
]);
|
|
1698
|
+
const submit = React.useCallback(async (event) => {
|
|
1699
|
+
const err = await handleSubmit(event);
|
|
1700
|
+
if (err && control) {
|
|
1701
|
+
control._subjects.state.next({ isSubmitSuccessful: false });
|
|
1702
|
+
control.setError('root.server', err);
|
|
1703
|
+
}
|
|
1704
|
+
}, [handleSubmit, control]);
|
|
1630
1705
|
React.useEffect(() => {
|
|
1631
1706
|
setMounted(true);
|
|
1632
1707
|
}, []);
|
|
1633
|
-
|
|
1634
|
-
submit
|
|
1635
|
-
}
|
|
1708
|
+
if (render) {
|
|
1709
|
+
return render({ submit });
|
|
1710
|
+
}
|
|
1711
|
+
// React forbids passing `method`/`encType` alongside a function `action`
|
|
1712
|
+
// (a Server-Action-style submission) -- it manages those itself and warns
|
|
1713
|
+
// if they're present, so they're only rendered for string/URL actions.
|
|
1714
|
+
return (React.createElement("form", { noValidate: mounted, action: action, ...(!isFunction(action) && { method, encType }), onSubmit: submit, ...rest }, children));
|
|
1636
1715
|
}
|
|
1637
1716
|
|
|
1638
|
-
const
|
|
1717
|
+
const FormState = ({ control, disabled, exact, name, render, }) => render(useFormState({ control, name, disabled, exact }));
|
|
1718
|
+
/** @deprecated Use `FormState` instead. Kept as an alias for backward compatibility. */
|
|
1719
|
+
const FormStateSubscribe = FormState;
|
|
1639
1720
|
|
|
1640
1721
|
var createSubject = () => {
|
|
1641
1722
|
let _observers = [];
|
|
@@ -1691,6 +1772,24 @@ var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
|
|
|
1691
1772
|
|
|
1692
1773
|
var live = (ref) => isHTMLElement(ref) && ref.isConnected;
|
|
1693
1774
|
|
|
1775
|
+
function isDirtyContainer(value) {
|
|
1776
|
+
return Array.isArray(value) || isObject(value);
|
|
1777
|
+
}
|
|
1778
|
+
function collectDirtyFieldNames(dirtyTree, cachedDirtyFields, prefix = '', names = []) {
|
|
1779
|
+
for (const key in dirtyTree) {
|
|
1780
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1781
|
+
const value = dirtyTree[key];
|
|
1782
|
+
if (isDirtyContainer(value) &&
|
|
1783
|
+
isDirtyContainer(get(cachedDirtyFields, path))) {
|
|
1784
|
+
collectDirtyFieldNames(value, cachedDirtyFields, path, names);
|
|
1785
|
+
}
|
|
1786
|
+
else {
|
|
1787
|
+
names.push(path);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
return names;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1694
1793
|
var objectHasFunction = (data) => {
|
|
1695
1794
|
for (const key in data) {
|
|
1696
1795
|
if (isFunction(data[key])) {
|
|
@@ -1794,7 +1893,7 @@ function getFieldValue(_f) {
|
|
|
1794
1893
|
if (isCheckBoxInput(ref)) {
|
|
1795
1894
|
return getCheckboxValue(_f.refs).value;
|
|
1796
1895
|
}
|
|
1797
|
-
return getFieldValueAs(
|
|
1896
|
+
return getFieldValueAs(ref.value, _f);
|
|
1798
1897
|
}
|
|
1799
1898
|
|
|
1800
1899
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
@@ -1885,8 +1984,7 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
1885
1984
|
|
|
1886
1985
|
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
1887
1986
|
updateFormState(formStateData);
|
|
1888
|
-
const
|
|
1889
|
-
const keys = Object.keys(formState);
|
|
1987
|
+
const keys = Object.keys(formStateData).filter((key) => key !== 'name');
|
|
1890
1988
|
return (!keys.length ||
|
|
1891
1989
|
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
1892
1990
|
keys.find((key) => _proxyFormState[key] ===
|
|
@@ -1918,7 +2016,12 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
1918
2016
|
return true;
|
|
1919
2017
|
};
|
|
1920
2018
|
|
|
1921
|
-
var unsetEmptyArray = (ref, name) =>
|
|
2019
|
+
var unsetEmptyArray = (ref, name) => {
|
|
2020
|
+
const array = get(ref, name);
|
|
2021
|
+
!compact(array).length &&
|
|
2022
|
+
!(array === null || array === void 0 ? void 0 : array.root) &&
|
|
2023
|
+
unset(ref, name);
|
|
2024
|
+
};
|
|
1922
2025
|
|
|
1923
2026
|
const defaultOptions = {
|
|
1924
2027
|
mode: VALIDATION_MODE.onSubmit,
|
|
@@ -1967,6 +2070,7 @@ function createFormControl(props = {}) {
|
|
|
1967
2070
|
: cloneObject(_defaultValues);
|
|
1968
2071
|
let _state = {
|
|
1969
2072
|
action: false,
|
|
2073
|
+
actionArrayLengths: new Map(),
|
|
1970
2074
|
mount: false,
|
|
1971
2075
|
watch: false,
|
|
1972
2076
|
keepIsValid: false,
|
|
@@ -2062,13 +2166,22 @@ function createFormControl(props = {}) {
|
|
|
2062
2166
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
2063
2167
|
if (args && method && !_options.disabled) {
|
|
2064
2168
|
_state.action = true;
|
|
2169
|
+
if (!_state.actionArrayLengths.has(name)) {
|
|
2170
|
+
const preActionFields = get(_fields, name);
|
|
2171
|
+
_state.actionArrayLengths.set(name, Array.isArray(preActionFields) ? preActionFields.length : 0);
|
|
2172
|
+
}
|
|
2065
2173
|
if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
|
|
2066
2174
|
const fieldValues = method(get(_fields, name), args.argA, args.argB);
|
|
2067
2175
|
shouldSetValues && set(_fields, name, fieldValues);
|
|
2068
2176
|
}
|
|
2069
2177
|
if (shouldUpdateFieldsAndState &&
|
|
2070
2178
|
Array.isArray(get(_formState.errors, name))) {
|
|
2071
|
-
const
|
|
2179
|
+
const fieldArrayErrors = get(_formState.errors, name);
|
|
2180
|
+
const rootError = fieldArrayErrors.root;
|
|
2181
|
+
const errors = method(fieldArrayErrors, args.argA, args.argB) || fieldArrayErrors;
|
|
2182
|
+
if (rootError) {
|
|
2183
|
+
errors.root = rootError;
|
|
2184
|
+
}
|
|
2072
2185
|
shouldSetValues && set(_formState.errors, name, errors);
|
|
2073
2186
|
unsetEmptyArray(_formState.errors, name);
|
|
2074
2187
|
}
|
|
@@ -2124,10 +2237,40 @@ function createFormControl(props = {}) {
|
|
|
2124
2237
|
}
|
|
2125
2238
|
return false;
|
|
2126
2239
|
};
|
|
2240
|
+
const isStaleArrayIndex = (name) => {
|
|
2241
|
+
if (!_state.actionArrayLengths.size) {
|
|
2242
|
+
return false;
|
|
2243
|
+
}
|
|
2244
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
2245
|
+
let node = _formValues;
|
|
2246
|
+
let path = '';
|
|
2247
|
+
let ownerDepth = -1;
|
|
2248
|
+
let ownerPreActionLength = 0;
|
|
2249
|
+
for (let i = 0; i < segments.length; i++) {
|
|
2250
|
+
if (isNullOrUndefined(node)) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
const key = segments[i];
|
|
2254
|
+
path = path ? `${path}.${key}` : key;
|
|
2255
|
+
if (Array.isArray(node) && +key >= node.length) {
|
|
2256
|
+
return ownerDepth === -1
|
|
2257
|
+
? false
|
|
2258
|
+
: i === ownerDepth
|
|
2259
|
+
? +key < ownerPreActionLength
|
|
2260
|
+
: true;
|
|
2261
|
+
}
|
|
2262
|
+
if (_state.actionArrayLengths.has(path)) {
|
|
2263
|
+
ownerDepth = i + 1;
|
|
2264
|
+
ownerPreActionLength = _state.actionArrayLengths.get(path);
|
|
2265
|
+
}
|
|
2266
|
+
node = node[key];
|
|
2267
|
+
}
|
|
2268
|
+
return false;
|
|
2269
|
+
};
|
|
2127
2270
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
2128
2271
|
const field = get(_fields, name);
|
|
2129
2272
|
if (field) {
|
|
2130
|
-
if (hasExplicitNullIntermediate(name)) {
|
|
2273
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayIndex(name)) {
|
|
2131
2274
|
return;
|
|
2132
2275
|
}
|
|
2133
2276
|
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
@@ -2375,14 +2518,12 @@ function createFormControl(props = {}) {
|
|
|
2375
2518
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
2376
2519
|
...(_state.mount
|
|
2377
2520
|
? _formValues
|
|
2378
|
-
: isUndefined(defaultValue)
|
|
2521
|
+
: isUndefined(defaultValue) || isString(names)
|
|
2379
2522
|
? _defaultValues
|
|
2380
|
-
:
|
|
2381
|
-
? { [names]: defaultValue }
|
|
2382
|
-
: defaultValue),
|
|
2523
|
+
: defaultValue),
|
|
2383
2524
|
}, isGlobal, defaultValue);
|
|
2384
2525
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
2385
|
-
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
|
|
2526
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
2386
2527
|
const field = get(_fields, name);
|
|
2387
2528
|
let fieldValue = value;
|
|
2388
2529
|
if (field) {
|
|
@@ -2420,7 +2561,7 @@ function createFormControl(props = {}) {
|
|
|
2420
2561
|
}
|
|
2421
2562
|
else {
|
|
2422
2563
|
fieldReference.ref.value = fieldValue;
|
|
2423
|
-
if (!fieldReference.ref.type && !skipRender) {
|
|
2564
|
+
if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
|
|
2424
2565
|
_subjects.state.next({
|
|
2425
2566
|
name,
|
|
2426
2567
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
@@ -2436,7 +2577,13 @@ function createFormControl(props = {}) {
|
|
|
2436
2577
|
delayError: options.delayError,
|
|
2437
2578
|
});
|
|
2438
2579
|
};
|
|
2439
|
-
const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
|
|
2580
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
2581
|
+
if (_names.array.has(name)) {
|
|
2582
|
+
_subjects.array.next({
|
|
2583
|
+
name,
|
|
2584
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2440
2587
|
for (const fieldKey in value) {
|
|
2441
2588
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
2442
2589
|
return;
|
|
@@ -2448,8 +2595,8 @@ function createFormControl(props = {}) {
|
|
|
2448
2595
|
isObject(fieldValue) ||
|
|
2449
2596
|
(field && !field._f)) &&
|
|
2450
2597
|
!isDateObject(fieldValue)
|
|
2451
|
-
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
|
|
2452
|
-
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
|
|
2598
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
|
|
2599
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
|
|
2453
2600
|
}
|
|
2454
2601
|
};
|
|
2455
2602
|
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
@@ -2484,11 +2631,12 @@ function createFormControl(props = {}) {
|
|
|
2484
2631
|
else {
|
|
2485
2632
|
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
2486
2633
|
isEmptyObject(cloneValue);
|
|
2634
|
+
const skipValueRender = !isValueUnchanged && !skipStateEmit;
|
|
2487
2635
|
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
2488
|
-
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2636
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2489
2637
|
}
|
|
2490
2638
|
else {
|
|
2491
|
-
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2639
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2492
2640
|
}
|
|
2493
2641
|
}
|
|
2494
2642
|
if (!isValueUnchanged && !skipStateEmit) {
|
|
@@ -2972,6 +3120,7 @@ function createFormControl(props = {}) {
|
|
|
2972
3120
|
}
|
|
2973
3121
|
};
|
|
2974
3122
|
const handleSubmit = (onValid, onInvalid) => async (e) => {
|
|
3123
|
+
let result = undefined;
|
|
2975
3124
|
let onValidError = undefined;
|
|
2976
3125
|
if (e) {
|
|
2977
3126
|
e.preventDefault && e.preventDefault();
|
|
@@ -3005,7 +3154,7 @@ function createFormControl(props = {}) {
|
|
|
3005
3154
|
errors: {},
|
|
3006
3155
|
});
|
|
3007
3156
|
try {
|
|
3008
|
-
await onValid(fieldValues, e);
|
|
3157
|
+
result = await onValid(fieldValues, e);
|
|
3009
3158
|
}
|
|
3010
3159
|
catch (error) {
|
|
3011
3160
|
onValidError = error;
|
|
@@ -3028,6 +3177,7 @@ function createFormControl(props = {}) {
|
|
|
3028
3177
|
if (onValidError) {
|
|
3029
3178
|
throw onValidError;
|
|
3030
3179
|
}
|
|
3180
|
+
return result;
|
|
3031
3181
|
};
|
|
3032
3182
|
const resetField = (name, options = {}) => {
|
|
3033
3183
|
if (get(_fields, name)) {
|
|
@@ -3067,7 +3217,7 @@ function createFormControl(props = {}) {
|
|
|
3067
3217
|
if (keepStateOptions.keepDirtyValues) {
|
|
3068
3218
|
const fieldsToCheck = new Set([
|
|
3069
3219
|
..._names.mount,
|
|
3070
|
-
...
|
|
3220
|
+
...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
|
|
3071
3221
|
]);
|
|
3072
3222
|
for (const fieldName of Array.from(fieldsToCheck)) {
|
|
3073
3223
|
const isDirty = get(_formState.dirtyFields, fieldName);
|
|
@@ -3148,6 +3298,7 @@ function createFormControl(props = {}) {
|
|
|
3148
3298
|
_state.watch = !!_options.shouldUnregister;
|
|
3149
3299
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
3150
3300
|
_state.action = false;
|
|
3301
|
+
_state.actionArrayLengths.clear();
|
|
3151
3302
|
if (!keepStateOptions.keepErrors) {
|
|
3152
3303
|
_formState.errors = {};
|
|
3153
3304
|
}
|
|
@@ -3220,6 +3371,7 @@ function createFormControl(props = {}) {
|
|
|
3220
3371
|
...formState,
|
|
3221
3372
|
};
|
|
3222
3373
|
};
|
|
3374
|
+
_subjects.state.subscribe({ next: _setFormState });
|
|
3223
3375
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
3224
3376
|
_options.defaultValues().then((values) => {
|
|
3225
3377
|
reset(values, _options.resetOptions);
|
|
@@ -3389,8 +3541,14 @@ function useForm(props = {}) {
|
|
|
3389
3541
|
}
|
|
3390
3542
|
const control = _formControl.current.control;
|
|
3391
3543
|
control._options = props;
|
|
3544
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
3392
3545
|
useIsomorphicLayoutEffect(() => {
|
|
3393
|
-
const
|
|
3546
|
+
const getCurrentFormState = () => ({
|
|
3547
|
+
...control._formState,
|
|
3548
|
+
defaultValues: control._defaultValues,
|
|
3549
|
+
});
|
|
3550
|
+
resyncIfNeeded(true, getCurrentFormState, updateFormState);
|
|
3551
|
+
const unsubscribe = control._subscribe({
|
|
3394
3552
|
formState: control._proxyFormState,
|
|
3395
3553
|
callback: () => updateFormState({
|
|
3396
3554
|
...control._formState,
|
|
@@ -3403,8 +3561,11 @@ function useForm(props = {}) {
|
|
|
3403
3561
|
isReady: true,
|
|
3404
3562
|
}));
|
|
3405
3563
|
control._formState.isReady = true;
|
|
3406
|
-
return
|
|
3407
|
-
|
|
3564
|
+
return () => {
|
|
3565
|
+
unsubscribe();
|
|
3566
|
+
snapshot(true, getCurrentFormState);
|
|
3567
|
+
};
|
|
3568
|
+
}, [control, resyncIfNeeded, snapshot]);
|
|
3408
3569
|
React.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]);
|
|
3409
3570
|
React.useEffect(() => {
|
|
3410
3571
|
if (props.mode) {
|
|
@@ -3496,5 +3657,5 @@ function useForm(props = {}) {
|
|
|
3496
3657
|
*/
|
|
3497
3658
|
const Watch = (props) => props.render(useWatch({ name: props.names, ...props }));
|
|
3498
3659
|
|
|
3499
|
-
export { Controller, FieldArray, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
|
|
3660
|
+
export { Controller, FieldArray, Form, FormProvider, FormState, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
|
|
3500
3661
|
//# sourceMappingURL=index.esm.mjs.map
|