vee-validate 4.5.9 → 4.6.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 +38 -22
- package/dist/vee-validate.d.ts +547 -292
- package/dist/vee-validate.esm.js +230 -95
- package/dist/vee-validate.js +226 -93
- package/dist/vee-validate.min.js +2 -2
- package/package.json +3 -3
- package/CHANGELOG.md +0 -888
package/dist/vee-validate.esm.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vee-validate v4.
|
|
2
|
+
* vee-validate v4.6.0
|
|
3
3
|
* (c) 2022 Abdelrahman Awad
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
|
-
import { inject, getCurrentInstance, warn as warn$1, ref, unref, computed, reactive, watch, onUnmounted, nextTick, onMounted, provide, isRef, onBeforeUnmount, defineComponent, toRef, resolveDynamicComponent, h, watchEffect, markRaw
|
|
6
|
+
import { inject, getCurrentInstance, warn as warn$1, ref, unref, computed, reactive, watch, onUnmounted, nextTick, onMounted, provide, isRef, onBeforeUnmount, defineComponent, toRef, resolveDynamicComponent, h, watchEffect, markRaw } from 'vue';
|
|
7
7
|
import { setupDevtoolsPlugin } from '@vue/devtools-api';
|
|
8
8
|
|
|
9
9
|
function isCallable(fn) {
|
|
@@ -53,18 +53,6 @@ const IS_ABSENT = Symbol('Default empty value');
|
|
|
53
53
|
function isLocator(value) {
|
|
54
54
|
return isCallable(value) && !!value.__locatorRef;
|
|
55
55
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Checks if an tag name is a native HTML tag and not a Vue component
|
|
58
|
-
*/
|
|
59
|
-
function isHTMLTag(tag) {
|
|
60
|
-
return ['input', 'textarea', 'select'].includes(tag);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Checks if an input is of type file
|
|
64
|
-
*/
|
|
65
|
-
function isFileInputNode(tag, attrs) {
|
|
66
|
-
return isHTMLTag(tag) && attrs.type === 'file';
|
|
67
|
-
}
|
|
68
56
|
function isYupValidator(value) {
|
|
69
57
|
return !!value && isCallable(value.validate);
|
|
70
58
|
}
|
|
@@ -117,7 +105,7 @@ function isNativeMultiSelectNode(tag, attrs) {
|
|
|
117
105
|
* For multi-selects because the value binding will reset the value
|
|
118
106
|
*/
|
|
119
107
|
function shouldHaveValueBinding(tag, attrs) {
|
|
120
|
-
return isNativeMultiSelectNode(tag, attrs)
|
|
108
|
+
return !isNativeMultiSelectNode(tag, attrs) && attrs.type !== 'file' && !hasCheckedAttr(attrs.type);
|
|
121
109
|
}
|
|
122
110
|
function isFormSubmitEvent(evt) {
|
|
123
111
|
return isEvent(evt) && evt.target && 'submit' in evt.target;
|
|
@@ -301,6 +289,15 @@ function debounceAsync(inner, ms = 0) {
|
|
|
301
289
|
}, ms);
|
|
302
290
|
return new Promise(resolve => resolves.push(resolve));
|
|
303
291
|
};
|
|
292
|
+
}
|
|
293
|
+
function applyModelModifiers(value, modifiers) {
|
|
294
|
+
if (!isObject(modifiers)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (modifiers.number) {
|
|
298
|
+
return toNumber(value);
|
|
299
|
+
}
|
|
300
|
+
return value;
|
|
304
301
|
}
|
|
305
302
|
|
|
306
303
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -344,7 +341,8 @@ function normalizeEventValue(value) {
|
|
|
344
341
|
return getBoundValue(input);
|
|
345
342
|
}
|
|
346
343
|
if (input.type === 'file' && input.files) {
|
|
347
|
-
|
|
344
|
+
const files = Array.from(input.files);
|
|
345
|
+
return input.multiple ? files : files[0];
|
|
348
346
|
}
|
|
349
347
|
if (isNativeMultiSelect(input)) {
|
|
350
348
|
return Array.from(input.options)
|
|
@@ -503,18 +501,34 @@ async function _validate(field, value) {
|
|
|
503
501
|
if (isYupValidator(field.rules)) {
|
|
504
502
|
return validateFieldWithYup(value, field.rules, { bails: field.bails });
|
|
505
503
|
}
|
|
506
|
-
// if a generic function
|
|
507
|
-
if (isCallable(field.rules)) {
|
|
504
|
+
// if a generic function or chain of generic functions
|
|
505
|
+
if (isCallable(field.rules) || Array.isArray(field.rules)) {
|
|
508
506
|
const ctx = {
|
|
509
507
|
field: field.name,
|
|
510
508
|
form: field.formData,
|
|
511
509
|
value: value,
|
|
512
510
|
};
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
const
|
|
511
|
+
// Normalize the pipeline
|
|
512
|
+
const pipeline = Array.isArray(field.rules) ? field.rules : [field.rules];
|
|
513
|
+
const length = pipeline.length;
|
|
514
|
+
const errors = [];
|
|
515
|
+
for (let i = 0; i < length; i++) {
|
|
516
|
+
const rule = pipeline[i];
|
|
517
|
+
const result = await rule(value, ctx);
|
|
518
|
+
const isValid = typeof result !== 'string' && result;
|
|
519
|
+
if (isValid) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const message = typeof result === 'string' ? result : _generateFieldError(ctx);
|
|
523
|
+
errors.push(message);
|
|
524
|
+
if (field.bails) {
|
|
525
|
+
return {
|
|
526
|
+
errors,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
}
|
|
516
530
|
return {
|
|
517
|
-
errors
|
|
531
|
+
errors,
|
|
518
532
|
};
|
|
519
533
|
}
|
|
520
534
|
const normalizedContext = Object.assign(Object.assign({}, field), { rules: normalizeRules(field.rules) });
|
|
@@ -827,8 +841,8 @@ function useFieldState(path, init) {
|
|
|
827
841
|
/**
|
|
828
842
|
* Creates the field value and resolves the initial value
|
|
829
843
|
*/
|
|
830
|
-
function _useFieldValue(path, modelValue, shouldInjectForm) {
|
|
831
|
-
const form = shouldInjectForm ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
844
|
+
function _useFieldValue(path, modelValue, shouldInjectForm = true) {
|
|
845
|
+
const form = shouldInjectForm === true ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
832
846
|
const modelRef = ref(unref(modelValue));
|
|
833
847
|
function resolveInitialValue() {
|
|
834
848
|
if (!form) {
|
|
@@ -858,7 +872,7 @@ function _useFieldValue(path, modelValue, shouldInjectForm) {
|
|
|
858
872
|
// prioritize model value over form values
|
|
859
873
|
// #3429
|
|
860
874
|
const currentValue = modelValue ? unref(modelValue) : getFromPath(form.values, unref(path), unref(initialValue));
|
|
861
|
-
form.stageInitialValue(unref(path), currentValue);
|
|
875
|
+
form.stageInitialValue(unref(path), currentValue, true);
|
|
862
876
|
// otherwise use a computed setter that triggers the `setFieldValue`
|
|
863
877
|
const value = computed({
|
|
864
878
|
get() {
|
|
@@ -1297,12 +1311,17 @@ function useField(name, rules, opts) {
|
|
|
1297
1311
|
return _useField(name, rules, opts);
|
|
1298
1312
|
}
|
|
1299
1313
|
function _useField(name, rules, opts) {
|
|
1300
|
-
const { initialValue: modelValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue, standalone, } = normalizeOptions(unref(name), opts);
|
|
1314
|
+
const { initialValue: modelValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue, standalone, keepValueOnUnmount, modelPropName, syncVModel, } = normalizeOptions(unref(name), opts);
|
|
1301
1315
|
const form = !standalone ? injectWithSelf(FormContextKey) : undefined;
|
|
1316
|
+
// a flag indicating if the field is about to be removed/unmounted.
|
|
1317
|
+
let markedForRemoval = false;
|
|
1302
1318
|
const { id, value, initialValue, meta, setState, errors, errorMessage } = useFieldState(name, {
|
|
1303
1319
|
modelValue,
|
|
1304
1320
|
standalone,
|
|
1305
1321
|
});
|
|
1322
|
+
if (syncVModel) {
|
|
1323
|
+
useVModel({ value, prop: modelPropName, handleChange });
|
|
1324
|
+
}
|
|
1306
1325
|
/**
|
|
1307
1326
|
* Handles common onBlur meta update
|
|
1308
1327
|
*/
|
|
@@ -1315,7 +1334,7 @@ function _useField(name, rules, opts) {
|
|
|
1315
1334
|
if (schema && !isYupValidator(schema)) {
|
|
1316
1335
|
rulesValue = extractRuleFromSchema(schema, unref(name)) || rulesValue;
|
|
1317
1336
|
}
|
|
1318
|
-
if (isYupValidator(rulesValue) || isCallable(rulesValue)) {
|
|
1337
|
+
if (isYupValidator(rulesValue) || isCallable(rulesValue) || Array.isArray(rulesValue)) {
|
|
1319
1338
|
return rulesValue;
|
|
1320
1339
|
}
|
|
1321
1340
|
return normalizeRules(rulesValue);
|
|
@@ -1335,12 +1354,19 @@ function _useField(name, rules, opts) {
|
|
|
1335
1354
|
meta.pending = true;
|
|
1336
1355
|
meta.validated = true;
|
|
1337
1356
|
const result = await validateCurrentValue('validated-only');
|
|
1357
|
+
if (markedForRemoval) {
|
|
1358
|
+
result.valid = true;
|
|
1359
|
+
result.errors = [];
|
|
1360
|
+
}
|
|
1338
1361
|
setState({ errors: result.errors });
|
|
1339
1362
|
meta.pending = false;
|
|
1340
1363
|
return result;
|
|
1341
1364
|
}
|
|
1342
1365
|
async function validateValidStateOnly() {
|
|
1343
1366
|
const result = await validateCurrentValue('silent');
|
|
1367
|
+
if (markedForRemoval) {
|
|
1368
|
+
result.valid = true;
|
|
1369
|
+
}
|
|
1344
1370
|
meta.valid = result.valid;
|
|
1345
1371
|
return result;
|
|
1346
1372
|
}
|
|
@@ -1354,13 +1380,13 @@ function _useField(name, rules, opts) {
|
|
|
1354
1380
|
return validateValidStateOnly();
|
|
1355
1381
|
}
|
|
1356
1382
|
// Common input/change event handler
|
|
1357
|
-
|
|
1383
|
+
function handleChange(e, shouldValidate = true) {
|
|
1358
1384
|
const newValue = normalizeEventValue(e);
|
|
1359
1385
|
value.value = newValue;
|
|
1360
1386
|
if (!validateOnValueUpdate && shouldValidate) {
|
|
1361
1387
|
validateWithStateMutation();
|
|
1362
1388
|
}
|
|
1363
|
-
}
|
|
1389
|
+
}
|
|
1364
1390
|
// Runs the initial validation
|
|
1365
1391
|
onMounted(() => {
|
|
1366
1392
|
if (validateOnMount) {
|
|
@@ -1377,7 +1403,13 @@ function _useField(name, rules, opts) {
|
|
|
1377
1403
|
}
|
|
1378
1404
|
let unwatchValue;
|
|
1379
1405
|
function watchValue() {
|
|
1380
|
-
unwatchValue = watch(value,
|
|
1406
|
+
unwatchValue = watch(value, (val, oldVal) => {
|
|
1407
|
+
if (es6(val, oldVal)) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
const validateFn = validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly;
|
|
1411
|
+
validateFn();
|
|
1412
|
+
}, {
|
|
1381
1413
|
deep: true,
|
|
1382
1414
|
});
|
|
1383
1415
|
}
|
|
@@ -1418,6 +1450,7 @@ function _useField(name, rules, opts) {
|
|
|
1418
1450
|
checkedValue,
|
|
1419
1451
|
uncheckedValue,
|
|
1420
1452
|
bails,
|
|
1453
|
+
keepValueOnUnmount,
|
|
1421
1454
|
resetField,
|
|
1422
1455
|
handleReset: () => resetField(),
|
|
1423
1456
|
validate: validate$1,
|
|
@@ -1455,13 +1488,14 @@ function _useField(name, rules, opts) {
|
|
|
1455
1488
|
// associate the field with the given form
|
|
1456
1489
|
form.register(field);
|
|
1457
1490
|
onBeforeUnmount(() => {
|
|
1491
|
+
markedForRemoval = true;
|
|
1458
1492
|
form.unregister(field);
|
|
1459
1493
|
});
|
|
1460
1494
|
// extract cross-field dependencies in a computed prop
|
|
1461
1495
|
const dependencies = computed(() => {
|
|
1462
1496
|
const rulesVal = normalizedRules.value;
|
|
1463
1497
|
// is falsy, a function schema or a yup schema
|
|
1464
|
-
if (!rulesVal || isCallable(rulesVal) || isYupValidator(rulesVal)) {
|
|
1498
|
+
if (!rulesVal || isCallable(rulesVal) || isYupValidator(rulesVal) || Array.isArray(rulesVal)) {
|
|
1465
1499
|
return {};
|
|
1466
1500
|
}
|
|
1467
1501
|
return Object.keys(rulesVal).reduce((acc, rule) => {
|
|
@@ -1503,6 +1537,9 @@ function normalizeOptions(name, opts) {
|
|
|
1503
1537
|
label: name,
|
|
1504
1538
|
validateOnValueUpdate: true,
|
|
1505
1539
|
standalone: false,
|
|
1540
|
+
keepValueOnUnmount: undefined,
|
|
1541
|
+
modelPropName: 'modelValue',
|
|
1542
|
+
syncVModel: true,
|
|
1506
1543
|
});
|
|
1507
1544
|
if (!opts) {
|
|
1508
1545
|
return defaults();
|
|
@@ -1534,8 +1571,8 @@ function useCheckboxField(name, rules, opts) {
|
|
|
1534
1571
|
return Array.isArray(currentValue) ? currentValue.includes(checkedVal) : checkedVal === currentValue;
|
|
1535
1572
|
});
|
|
1536
1573
|
function handleCheckboxChange(e, shouldValidate = true) {
|
|
1537
|
-
var _a
|
|
1538
|
-
if (checked.value === ((
|
|
1574
|
+
var _a;
|
|
1575
|
+
if (checked.value === ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.checked)) {
|
|
1539
1576
|
return;
|
|
1540
1577
|
}
|
|
1541
1578
|
let newValue = normalizeEventValue(e);
|
|
@@ -1546,8 +1583,10 @@ function useCheckboxField(name, rules, opts) {
|
|
|
1546
1583
|
handleChange(newValue, shouldValidate);
|
|
1547
1584
|
}
|
|
1548
1585
|
onBeforeUnmount(() => {
|
|
1549
|
-
|
|
1550
|
-
|
|
1586
|
+
var _a, _b;
|
|
1587
|
+
const shouldKeepValue = (_b = (_a = unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : unref(form === null || form === void 0 ? void 0 : form.keepValuesOnUnmount)) !== null && _b !== void 0 ? _b : false;
|
|
1588
|
+
// toggles the checkbox value if it was checked and the unset behavior is set
|
|
1589
|
+
if (checked.value && !shouldKeepValue) {
|
|
1551
1590
|
handleCheckboxChange(unref(checkedValue), false);
|
|
1552
1591
|
}
|
|
1553
1592
|
});
|
|
@@ -1556,6 +1595,41 @@ function useCheckboxField(name, rules, opts) {
|
|
|
1556
1595
|
uncheckedValue, handleChange: handleCheckboxChange });
|
|
1557
1596
|
}
|
|
1558
1597
|
return patchCheckboxApi(_useField(name, rules, opts));
|
|
1598
|
+
}
|
|
1599
|
+
function useVModel({ prop, value, handleChange }) {
|
|
1600
|
+
const vm = getCurrentInstance();
|
|
1601
|
+
/* istanbul ignore next */
|
|
1602
|
+
if (!vm) {
|
|
1603
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1604
|
+
console.warn('Failed to setup model events because `useField` was not called in setup.');
|
|
1605
|
+
}
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
const propName = prop || 'modelValue';
|
|
1609
|
+
const emitName = `update:${propName}`;
|
|
1610
|
+
// Component doesn't have a model prop setup (must be defined on the props)
|
|
1611
|
+
if (!(propName in vm.props)) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
watch(value, newValue => {
|
|
1615
|
+
if (es6(newValue, getCurrentModelValue(vm, propName))) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
vm.emit(emitName, newValue);
|
|
1619
|
+
});
|
|
1620
|
+
watch(() => getCurrentModelValue(vm, propName), propValue => {
|
|
1621
|
+
if (propValue === IS_ABSENT && value.value === undefined) {
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
const newValue = propValue === IS_ABSENT ? undefined : propValue;
|
|
1625
|
+
if (es6(newValue, applyModelModifiers(value.value, vm.props.modelModifiers))) {
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
handleChange(newValue);
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
function getCurrentModelValue(vm, propName) {
|
|
1632
|
+
return vm.props[propName];
|
|
1559
1633
|
}
|
|
1560
1634
|
|
|
1561
1635
|
const FieldImpl = defineComponent({
|
|
@@ -1622,13 +1696,17 @@ const FieldImpl = defineComponent({
|
|
|
1622
1696
|
type: Boolean,
|
|
1623
1697
|
default: false,
|
|
1624
1698
|
},
|
|
1699
|
+
keepValue: {
|
|
1700
|
+
type: Boolean,
|
|
1701
|
+
default: undefined,
|
|
1702
|
+
},
|
|
1625
1703
|
},
|
|
1626
1704
|
setup(props, ctx) {
|
|
1627
1705
|
const rules = toRef(props, 'rules');
|
|
1628
1706
|
const name = toRef(props, 'name');
|
|
1629
1707
|
const label = toRef(props, 'label');
|
|
1630
1708
|
const uncheckedValue = toRef(props, 'uncheckedValue');
|
|
1631
|
-
const
|
|
1709
|
+
const keepValue = toRef(props, 'keepValue');
|
|
1632
1710
|
const { errors, value, errorMessage, validate: validateField, handleChange, handleBlur, setTouched, resetField, handleReset, meta, checked, setErrors, } = useField(name, rules, {
|
|
1633
1711
|
validateOnMount: props.validateOnMount,
|
|
1634
1712
|
bails: props.bails,
|
|
@@ -1640,25 +1718,22 @@ const FieldImpl = defineComponent({
|
|
|
1640
1718
|
uncheckedValue,
|
|
1641
1719
|
label,
|
|
1642
1720
|
validateOnValueUpdate: false,
|
|
1721
|
+
keepValueOnUnmount: keepValue,
|
|
1643
1722
|
});
|
|
1644
1723
|
// If there is a v-model applied on the component we need to emit the `update:modelValue` whenever the value binding changes
|
|
1645
|
-
const onChangeHandler =
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
}
|
|
1650
|
-
: handleChange;
|
|
1724
|
+
const onChangeHandler = function handleChangeWithModel(e, shouldValidate = true) {
|
|
1725
|
+
handleChange(e, shouldValidate);
|
|
1726
|
+
ctx.emit('update:modelValue', value.value);
|
|
1727
|
+
};
|
|
1651
1728
|
const handleInput = (e) => {
|
|
1652
1729
|
if (!hasCheckedAttr(ctx.attrs.type)) {
|
|
1653
1730
|
value.value = normalizeEventValue(e);
|
|
1654
1731
|
}
|
|
1655
1732
|
};
|
|
1656
|
-
const onInputHandler =
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
}
|
|
1661
|
-
: handleInput;
|
|
1733
|
+
const onInputHandler = function handleInputWithModel(e) {
|
|
1734
|
+
handleInput(e);
|
|
1735
|
+
ctx.emit('update:modelValue', value.value);
|
|
1736
|
+
};
|
|
1662
1737
|
const fieldProps = computed(() => {
|
|
1663
1738
|
const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(props);
|
|
1664
1739
|
const baseOnBlur = [handleBlur, ctx.attrs.onBlur, validateOnBlur ? validateField : undefined].filter(Boolean);
|
|
@@ -1674,26 +1749,12 @@ const FieldImpl = defineComponent({
|
|
|
1674
1749
|
if (hasCheckedAttr(ctx.attrs.type) && checked) {
|
|
1675
1750
|
attrs.checked = checked.value;
|
|
1676
1751
|
}
|
|
1677
|
-
else {
|
|
1678
|
-
attrs.value = value.value;
|
|
1679
|
-
}
|
|
1680
1752
|
const tag = resolveTag(props, ctx);
|
|
1681
1753
|
if (shouldHaveValueBinding(tag, ctx.attrs)) {
|
|
1682
|
-
|
|
1754
|
+
attrs.value = value.value;
|
|
1683
1755
|
}
|
|
1684
1756
|
return attrs;
|
|
1685
1757
|
});
|
|
1686
|
-
const modelValue = toRef(props, 'modelValue');
|
|
1687
|
-
watch(modelValue, newModelValue => {
|
|
1688
|
-
// Don't attempt to sync absent values
|
|
1689
|
-
if (newModelValue === IS_ABSENT && value.value === undefined) {
|
|
1690
|
-
return;
|
|
1691
|
-
}
|
|
1692
|
-
if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) {
|
|
1693
|
-
value.value = newModelValue === IS_ABSENT ? undefined : newModelValue;
|
|
1694
|
-
validateField();
|
|
1695
|
-
}
|
|
1696
|
-
});
|
|
1697
1758
|
function slotProps() {
|
|
1698
1759
|
return {
|
|
1699
1760
|
field: fieldProps.value,
|
|
@@ -1745,12 +1806,6 @@ function resolveValidationTriggers(props) {
|
|
|
1745
1806
|
validateOnModelUpdate: (_d = props.validateOnModelUpdate) !== null && _d !== void 0 ? _d : validateOnModelUpdate,
|
|
1746
1807
|
};
|
|
1747
1808
|
}
|
|
1748
|
-
function applyModifiers(value, modifiers) {
|
|
1749
|
-
if (modifiers.number) {
|
|
1750
|
-
return toNumber(value);
|
|
1751
|
-
}
|
|
1752
|
-
return value;
|
|
1753
|
-
}
|
|
1754
1809
|
function resolveInitialValue(props, ctx) {
|
|
1755
1810
|
// Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
|
|
1756
1811
|
// For checkboxes and radio buttons it will always be the model value not the `value` attribute
|
|
@@ -1763,6 +1818,7 @@ const Field = FieldImpl;
|
|
|
1763
1818
|
|
|
1764
1819
|
let FORM_COUNTER = 0;
|
|
1765
1820
|
function useForm(opts) {
|
|
1821
|
+
var _a;
|
|
1766
1822
|
const formId = FORM_COUNTER++;
|
|
1767
1823
|
// Prevents fields from double resetting their values, which causes checkboxes to toggle their initial value
|
|
1768
1824
|
// TODO: This won't be needed if we centralize all the state inside the `form` for form inputs
|
|
@@ -1773,8 +1829,8 @@ function useForm(opts) {
|
|
|
1773
1829
|
const isSubmitting = ref(false);
|
|
1774
1830
|
// The number of times the user tried to submit the form
|
|
1775
1831
|
const submitCount = ref(0);
|
|
1776
|
-
//
|
|
1777
|
-
const
|
|
1832
|
+
// field arrays managed by this form
|
|
1833
|
+
const fieldArrays = [];
|
|
1778
1834
|
// a private ref for all form values
|
|
1779
1835
|
const formValues = reactive(klona(unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {}));
|
|
1780
1836
|
// the source of errors for the form fields
|
|
@@ -1821,10 +1877,11 @@ function useForm(opts) {
|
|
|
1821
1877
|
// mutable non-reactive reference to initial errors
|
|
1822
1878
|
// we need this to process initial errors then unset them
|
|
1823
1879
|
const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
|
|
1880
|
+
const keepValuesOnUnmount = (_a = opts === null || opts === void 0 ? void 0 : opts.keepValuesOnUnmount) !== null && _a !== void 0 ? _a : false;
|
|
1824
1881
|
// initial form values
|
|
1825
1882
|
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(fieldsByPath, formValues, opts === null || opts === void 0 ? void 0 : opts.initialValues);
|
|
1826
1883
|
// form meta aggregations
|
|
1827
|
-
const meta = useFormMeta(fieldsByPath, formValues,
|
|
1884
|
+
const meta = useFormMeta(fieldsByPath, formValues, originalInitialValues, errors);
|
|
1828
1885
|
const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
|
|
1829
1886
|
const formCtx = {
|
|
1830
1887
|
formId,
|
|
@@ -1836,7 +1893,8 @@ function useForm(opts) {
|
|
|
1836
1893
|
submitCount,
|
|
1837
1894
|
meta,
|
|
1838
1895
|
isSubmitting,
|
|
1839
|
-
|
|
1896
|
+
fieldArrays,
|
|
1897
|
+
keepValuesOnUnmount,
|
|
1840
1898
|
validateSchema: unref(schema) ? validateSchema : undefined,
|
|
1841
1899
|
validate,
|
|
1842
1900
|
register: registerField,
|
|
@@ -1854,6 +1912,7 @@ function useForm(opts) {
|
|
|
1854
1912
|
stageInitialValue,
|
|
1855
1913
|
unsetInitialValue,
|
|
1856
1914
|
setFieldInitialValue,
|
|
1915
|
+
useFieldModel,
|
|
1857
1916
|
};
|
|
1858
1917
|
function isFieldGroup(fieldOrGroup) {
|
|
1859
1918
|
return Array.isArray(fieldOrGroup);
|
|
@@ -1923,7 +1982,22 @@ function useForm(opts) {
|
|
|
1923
1982
|
setFieldValue(path, fields[path]);
|
|
1924
1983
|
});
|
|
1925
1984
|
// regenerate the arrays when the form values change
|
|
1926
|
-
|
|
1985
|
+
fieldArrays.forEach(f => f && f.reset());
|
|
1986
|
+
}
|
|
1987
|
+
function createModel(path) {
|
|
1988
|
+
const { value } = _useFieldValue(path);
|
|
1989
|
+
watch(value, () => {
|
|
1990
|
+
if (!fieldExists(unref(path))) {
|
|
1991
|
+
validate({ mode: 'validated-only' });
|
|
1992
|
+
}
|
|
1993
|
+
});
|
|
1994
|
+
return value;
|
|
1995
|
+
}
|
|
1996
|
+
function useFieldModel(path) {
|
|
1997
|
+
if (!Array.isArray(path)) {
|
|
1998
|
+
return createModel(path);
|
|
1999
|
+
}
|
|
2000
|
+
return path.map(createModel);
|
|
1927
2001
|
}
|
|
1928
2002
|
/**
|
|
1929
2003
|
* Sets the touched meta state on a field
|
|
@@ -2047,13 +2121,26 @@ function useForm(opts) {
|
|
|
2047
2121
|
}
|
|
2048
2122
|
function unregisterField(field) {
|
|
2049
2123
|
const fieldName = unref(field.name);
|
|
2124
|
+
const fieldInstance = fieldsByPath.value[fieldName];
|
|
2125
|
+
const isGroup = !!fieldInstance && isFieldGroup(fieldInstance);
|
|
2050
2126
|
removeFieldFromPath(field, fieldName);
|
|
2051
2127
|
nextTick(() => {
|
|
2128
|
+
var _a;
|
|
2052
2129
|
// clears a field error on unmounted
|
|
2053
2130
|
// we wait till next tick to make sure if the field is completely removed and doesn't have any siblings like checkboxes
|
|
2054
2131
|
// #3384
|
|
2055
2132
|
if (!fieldExists(fieldName)) {
|
|
2056
2133
|
setFieldError(fieldName, undefined);
|
|
2134
|
+
// Checks if the field was configured to be unset during unmount or not
|
|
2135
|
+
// Checks both the form-level config and field-level one
|
|
2136
|
+
// Field has the priority if it is set, otherwise it goes to the form settings
|
|
2137
|
+
const shouldKeepValue = (_a = unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : unref(keepValuesOnUnmount);
|
|
2138
|
+
if (shouldKeepValue) {
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
if (isGroup && !isEmptyContainer(getFromPath(formValues, fieldName))) {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2057
2144
|
unsetPath(formValues, fieldName);
|
|
2058
2145
|
}
|
|
2059
2146
|
});
|
|
@@ -2160,9 +2247,12 @@ function useForm(opts) {
|
|
|
2160
2247
|
/**
|
|
2161
2248
|
* Sneaky function to set initial field values
|
|
2162
2249
|
*/
|
|
2163
|
-
function stageInitialValue(path, value) {
|
|
2250
|
+
function stageInitialValue(path, value, updateOriginal = false) {
|
|
2164
2251
|
setInPath(formValues, path, value);
|
|
2165
2252
|
setFieldInitialValue(path, value);
|
|
2253
|
+
if (updateOriginal) {
|
|
2254
|
+
setInPath(originalInitialValues.value, path, klona(value));
|
|
2255
|
+
}
|
|
2166
2256
|
}
|
|
2167
2257
|
async function _validateSchema() {
|
|
2168
2258
|
const schemaValue = unref(schema);
|
|
@@ -2179,10 +2269,12 @@ function useForm(opts) {
|
|
|
2179
2269
|
}
|
|
2180
2270
|
/**
|
|
2181
2271
|
* Batches validation runs in 5ms batches
|
|
2272
|
+
* Must have two distinct batch queues to make sure they don't override each other settings #3783
|
|
2182
2273
|
*/
|
|
2183
|
-
const
|
|
2274
|
+
const debouncedSilentValidation = debounceAsync(_validateSchema, 5);
|
|
2275
|
+
const debouncedValidation = debounceAsync(_validateSchema, 5);
|
|
2184
2276
|
async function validateSchema(mode) {
|
|
2185
|
-
const formResult = await
|
|
2277
|
+
const formResult = await (mode === 'silent' ? debouncedSilentValidation() : debouncedValidation());
|
|
2186
2278
|
// fields by id lookup
|
|
2187
2279
|
const fieldsById = formCtx.fieldsByPath.value || {};
|
|
2188
2280
|
// errors fields names, we need it to also check if custom errors are updated
|
|
@@ -2278,6 +2370,7 @@ function useForm(opts) {
|
|
|
2278
2370
|
setValues,
|
|
2279
2371
|
setFieldTouched,
|
|
2280
2372
|
setTouched,
|
|
2373
|
+
useFieldModel,
|
|
2281
2374
|
};
|
|
2282
2375
|
}
|
|
2283
2376
|
/**
|
|
@@ -2429,16 +2522,22 @@ const FormImpl = defineComponent({
|
|
|
2429
2522
|
type: Function,
|
|
2430
2523
|
default: undefined,
|
|
2431
2524
|
},
|
|
2525
|
+
keepValues: {
|
|
2526
|
+
type: Boolean,
|
|
2527
|
+
default: false,
|
|
2528
|
+
},
|
|
2432
2529
|
},
|
|
2433
2530
|
setup(props, ctx) {
|
|
2434
2531
|
const initialValues = toRef(props, 'initialValues');
|
|
2435
2532
|
const validationSchema = toRef(props, 'validationSchema');
|
|
2533
|
+
const keepValues = toRef(props, 'keepValues');
|
|
2436
2534
|
const { errors, values, meta, isSubmitting, submitCount, validate, validateField, handleReset, resetForm, handleSubmit, submitForm, setErrors, setFieldError, setFieldValue, setValues, setFieldTouched, setTouched, } = useForm({
|
|
2437
2535
|
validationSchema: validationSchema.value ? validationSchema : undefined,
|
|
2438
2536
|
initialValues,
|
|
2439
2537
|
initialErrors: props.initialErrors,
|
|
2440
2538
|
initialTouched: props.initialTouched,
|
|
2441
2539
|
validateOnMount: props.validateOnMount,
|
|
2540
|
+
keepValuesOnUnmount: keepValues,
|
|
2442
2541
|
});
|
|
2443
2542
|
const onSubmit = props.onSubmit ? handleSubmit(props.onSubmit, props.onInvalidSubmit) : submitForm;
|
|
2444
2543
|
function handleFormReset(e) {
|
|
@@ -2508,15 +2607,13 @@ const FormImpl = defineComponent({
|
|
|
2508
2607
|
});
|
|
2509
2608
|
const Form = FormImpl;
|
|
2510
2609
|
|
|
2511
|
-
let FIELD_ARRAY_COUNTER = 0;
|
|
2512
2610
|
function useFieldArray(arrayPath) {
|
|
2513
|
-
const id = FIELD_ARRAY_COUNTER++;
|
|
2514
2611
|
const form = injectWithSelf(FormContextKey, undefined);
|
|
2515
2612
|
const fields = ref([]);
|
|
2516
2613
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
2517
2614
|
const noOp = () => { };
|
|
2518
2615
|
const noOpApi = {
|
|
2519
|
-
fields
|
|
2616
|
+
fields,
|
|
2520
2617
|
remove: noOp,
|
|
2521
2618
|
push: noOp,
|
|
2522
2619
|
swap: noOp,
|
|
@@ -2524,6 +2621,7 @@ function useFieldArray(arrayPath) {
|
|
|
2524
2621
|
update: noOp,
|
|
2525
2622
|
replace: noOp,
|
|
2526
2623
|
prepend: noOp,
|
|
2624
|
+
move: noOp,
|
|
2527
2625
|
};
|
|
2528
2626
|
if (!form) {
|
|
2529
2627
|
warn('FieldArray requires being a child of `<Form/>` or `useForm` being called before it. Array fields may not work correctly');
|
|
@@ -2533,9 +2631,13 @@ function useFieldArray(arrayPath) {
|
|
|
2533
2631
|
warn('FieldArray requires a field path to be provided, did you forget to pass the `name` prop?');
|
|
2534
2632
|
return noOpApi;
|
|
2535
2633
|
}
|
|
2634
|
+
const alreadyExists = form.fieldArrays.find(a => unref(a.path) === unref(arrayPath));
|
|
2635
|
+
if (alreadyExists) {
|
|
2636
|
+
return alreadyExists;
|
|
2637
|
+
}
|
|
2536
2638
|
let entryCounter = 0;
|
|
2537
2639
|
function initFields() {
|
|
2538
|
-
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []);
|
|
2640
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []) || [];
|
|
2539
2641
|
fields.value = currentValues.map(createEntry);
|
|
2540
2642
|
updateEntryFlags();
|
|
2541
2643
|
}
|
|
@@ -2552,10 +2654,20 @@ function useFieldArray(arrayPath) {
|
|
|
2552
2654
|
const key = entryCounter++;
|
|
2553
2655
|
const entry = {
|
|
2554
2656
|
key,
|
|
2555
|
-
value: computed(
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2657
|
+
value: computed({
|
|
2658
|
+
get() {
|
|
2659
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []) || [];
|
|
2660
|
+
const idx = fields.value.findIndex(e => e.key === key);
|
|
2661
|
+
return idx === -1 ? value : currentValues[idx];
|
|
2662
|
+
},
|
|
2663
|
+
set(value) {
|
|
2664
|
+
const idx = fields.value.findIndex(e => e.key === key);
|
|
2665
|
+
if (idx === -1) {
|
|
2666
|
+
warn(`Attempting to update a non-existent array item`);
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
update(idx, value);
|
|
2670
|
+
},
|
|
2559
2671
|
}),
|
|
2560
2672
|
isFirst: false,
|
|
2561
2673
|
isLast: false,
|
|
@@ -2648,14 +2760,26 @@ function useFieldArray(arrayPath) {
|
|
|
2648
2760
|
fields.value.unshift(createEntry(value));
|
|
2649
2761
|
updateEntryFlags();
|
|
2650
2762
|
}
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2763
|
+
function move(oldIdx, newIdx) {
|
|
2764
|
+
const pathName = unref(arrayPath);
|
|
2765
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2766
|
+
const newValue = isNullOrUndefined(pathValue) ? [] : [...pathValue];
|
|
2767
|
+
if (!Array.isArray(pathValue) || !(oldIdx in pathValue) || !(newIdx in pathValue)) {
|
|
2768
|
+
return;
|
|
2769
|
+
}
|
|
2770
|
+
const newFields = [...fields.value];
|
|
2771
|
+
const movedItem = newFields[oldIdx];
|
|
2772
|
+
newFields.splice(oldIdx, 1);
|
|
2773
|
+
newFields.splice(newIdx, 0, movedItem);
|
|
2774
|
+
const movedValue = newValue[oldIdx];
|
|
2775
|
+
newValue.splice(oldIdx, 1);
|
|
2776
|
+
newValue.splice(newIdx, 0, movedValue);
|
|
2777
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2778
|
+
fields.value = newFields;
|
|
2779
|
+
updateEntryFlags();
|
|
2780
|
+
}
|
|
2781
|
+
const fieldArrayCtx = {
|
|
2782
|
+
fields,
|
|
2659
2783
|
remove,
|
|
2660
2784
|
push,
|
|
2661
2785
|
swap,
|
|
@@ -2663,7 +2787,16 @@ function useFieldArray(arrayPath) {
|
|
|
2663
2787
|
update,
|
|
2664
2788
|
replace,
|
|
2665
2789
|
prepend,
|
|
2790
|
+
move,
|
|
2666
2791
|
};
|
|
2792
|
+
form.fieldArrays.push(Object.assign({ path: arrayPath, reset: initFields }, fieldArrayCtx));
|
|
2793
|
+
onBeforeUnmount(() => {
|
|
2794
|
+
const idx = form.fieldArrays.findIndex(i => unref(i.path) === unref(arrayPath));
|
|
2795
|
+
if (idx >= 0) {
|
|
2796
|
+
form.fieldArrays.splice(idx, 1);
|
|
2797
|
+
}
|
|
2798
|
+
});
|
|
2799
|
+
return fieldArrayCtx;
|
|
2667
2800
|
}
|
|
2668
2801
|
|
|
2669
2802
|
const FieldArrayImpl = defineComponent({
|
|
@@ -2676,7 +2809,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2676
2809
|
},
|
|
2677
2810
|
},
|
|
2678
2811
|
setup(props, ctx) {
|
|
2679
|
-
const { push, remove, swap, insert, replace, update, prepend, fields } = useFieldArray(toRef(props, 'name'));
|
|
2812
|
+
const { push, remove, swap, insert, replace, update, prepend, move, fields } = useFieldArray(toRef(props, 'name'));
|
|
2680
2813
|
function slotProps() {
|
|
2681
2814
|
return {
|
|
2682
2815
|
fields: fields.value,
|
|
@@ -2687,6 +2820,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2687
2820
|
update,
|
|
2688
2821
|
replace,
|
|
2689
2822
|
prepend,
|
|
2823
|
+
move,
|
|
2690
2824
|
};
|
|
2691
2825
|
}
|
|
2692
2826
|
ctx.expose({
|
|
@@ -2697,6 +2831,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2697
2831
|
update,
|
|
2698
2832
|
replace,
|
|
2699
2833
|
prepend,
|
|
2834
|
+
move,
|
|
2700
2835
|
});
|
|
2701
2836
|
return () => {
|
|
2702
2837
|
const children = normalizeChildren(undefined, ctx, slotProps);
|
|
@@ -2996,4 +3131,4 @@ function useSubmitForm(cb) {
|
|
|
2996
3131
|
};
|
|
2997
3132
|
}
|
|
2998
3133
|
|
|
2999
|
-
export { ErrorMessage, Field, FieldArray, FieldContextKey, Form, FormContextKey, configure, defineRule, useField, useFieldArray, useFieldError, useFieldValue, useForm, useFormErrors, useFormValues, useIsFieldDirty, useIsFieldTouched, useIsFieldValid, useIsFormDirty, useIsFormTouched, useIsFormValid, useIsSubmitting, useResetForm, useSubmitCount, useSubmitForm, useValidateField, useValidateForm, validate };
|
|
3134
|
+
export { ErrorMessage, Field, FieldArray, FieldContextKey, Form, FormContextKey, IS_ABSENT, configure, defineRule, useField, useFieldArray, useFieldError, useFieldValue, useForm, useFormErrors, useFormValues, useIsFieldDirty, useIsFieldTouched, useIsFieldValid, useIsFormDirty, useIsFormTouched, useIsFormValid, useIsSubmitting, useResetForm, useSubmitCount, useSubmitForm, useValidateField, useValidateForm, validate };
|