vee-validate 4.5.11 → 4.6.2
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 -291
- package/dist/vee-validate.esm.js +219 -98
- package/dist/vee-validate.js +215 -96
- package/dist/vee-validate.min.js +2 -2
- package/package.json +3 -3
- package/CHANGELOG.md +0 -912
package/dist/vee-validate.esm.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vee-validate v4.
|
|
2
|
+
* vee-validate v4.6.2
|
|
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)
|
|
@@ -843,8 +841,8 @@ function useFieldState(path, init) {
|
|
|
843
841
|
/**
|
|
844
842
|
* Creates the field value and resolves the initial value
|
|
845
843
|
*/
|
|
846
|
-
function _useFieldValue(path, modelValue, shouldInjectForm) {
|
|
847
|
-
const form = shouldInjectForm ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
844
|
+
function _useFieldValue(path, modelValue, shouldInjectForm = true) {
|
|
845
|
+
const form = shouldInjectForm === true ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
848
846
|
const modelRef = ref(unref(modelValue));
|
|
849
847
|
function resolveInitialValue() {
|
|
850
848
|
if (!form) {
|
|
@@ -874,7 +872,7 @@ function _useFieldValue(path, modelValue, shouldInjectForm) {
|
|
|
874
872
|
// prioritize model value over form values
|
|
875
873
|
// #3429
|
|
876
874
|
const currentValue = modelValue ? unref(modelValue) : getFromPath(form.values, unref(path), unref(initialValue));
|
|
877
|
-
form.stageInitialValue(unref(path), currentValue);
|
|
875
|
+
form.stageInitialValue(unref(path), currentValue, true);
|
|
878
876
|
// otherwise use a computed setter that triggers the `setFieldValue`
|
|
879
877
|
const value = computed({
|
|
880
878
|
get() {
|
|
@@ -1313,7 +1311,7 @@ function useField(name, rules, opts) {
|
|
|
1313
1311
|
return _useField(name, rules, opts);
|
|
1314
1312
|
}
|
|
1315
1313
|
function _useField(name, rules, opts) {
|
|
1316
|
-
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);
|
|
1317
1315
|
const form = !standalone ? injectWithSelf(FormContextKey) : undefined;
|
|
1318
1316
|
// a flag indicating if the field is about to be removed/unmounted.
|
|
1319
1317
|
let markedForRemoval = false;
|
|
@@ -1321,6 +1319,9 @@ function _useField(name, rules, opts) {
|
|
|
1321
1319
|
modelValue,
|
|
1322
1320
|
standalone,
|
|
1323
1321
|
});
|
|
1322
|
+
if (syncVModel) {
|
|
1323
|
+
useVModel({ value, prop: modelPropName, handleChange });
|
|
1324
|
+
}
|
|
1324
1325
|
/**
|
|
1325
1326
|
* Handles common onBlur meta update
|
|
1326
1327
|
*/
|
|
@@ -1379,13 +1380,13 @@ function _useField(name, rules, opts) {
|
|
|
1379
1380
|
return validateValidStateOnly();
|
|
1380
1381
|
}
|
|
1381
1382
|
// Common input/change event handler
|
|
1382
|
-
|
|
1383
|
+
function handleChange(e, shouldValidate = true) {
|
|
1383
1384
|
const newValue = normalizeEventValue(e);
|
|
1384
1385
|
value.value = newValue;
|
|
1385
1386
|
if (!validateOnValueUpdate && shouldValidate) {
|
|
1386
1387
|
validateWithStateMutation();
|
|
1387
1388
|
}
|
|
1388
|
-
}
|
|
1389
|
+
}
|
|
1389
1390
|
// Runs the initial validation
|
|
1390
1391
|
onMounted(() => {
|
|
1391
1392
|
if (validateOnMount) {
|
|
@@ -1402,7 +1403,13 @@ function _useField(name, rules, opts) {
|
|
|
1402
1403
|
}
|
|
1403
1404
|
let unwatchValue;
|
|
1404
1405
|
function watchValue() {
|
|
1405
|
-
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
|
+
}, {
|
|
1406
1413
|
deep: true,
|
|
1407
1414
|
});
|
|
1408
1415
|
}
|
|
@@ -1443,6 +1450,7 @@ function _useField(name, rules, opts) {
|
|
|
1443
1450
|
checkedValue,
|
|
1444
1451
|
uncheckedValue,
|
|
1445
1452
|
bails,
|
|
1453
|
+
keepValueOnUnmount,
|
|
1446
1454
|
resetField,
|
|
1447
1455
|
handleReset: () => resetField(),
|
|
1448
1456
|
validate: validate$1,
|
|
@@ -1529,6 +1537,9 @@ function normalizeOptions(name, opts) {
|
|
|
1529
1537
|
label: name,
|
|
1530
1538
|
validateOnValueUpdate: true,
|
|
1531
1539
|
standalone: false,
|
|
1540
|
+
keepValueOnUnmount: undefined,
|
|
1541
|
+
modelPropName: 'modelValue',
|
|
1542
|
+
syncVModel: true,
|
|
1532
1543
|
});
|
|
1533
1544
|
if (!opts) {
|
|
1534
1545
|
return defaults();
|
|
@@ -1560,8 +1571,8 @@ function useCheckboxField(name, rules, opts) {
|
|
|
1560
1571
|
return Array.isArray(currentValue) ? currentValue.includes(checkedVal) : checkedVal === currentValue;
|
|
1561
1572
|
});
|
|
1562
1573
|
function handleCheckboxChange(e, shouldValidate = true) {
|
|
1563
|
-
var _a
|
|
1564
|
-
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)) {
|
|
1565
1576
|
return;
|
|
1566
1577
|
}
|
|
1567
1578
|
let newValue = normalizeEventValue(e);
|
|
@@ -1571,17 +1582,46 @@ function useCheckboxField(name, rules, opts) {
|
|
|
1571
1582
|
}
|
|
1572
1583
|
handleChange(newValue, shouldValidate);
|
|
1573
1584
|
}
|
|
1574
|
-
onBeforeUnmount(() => {
|
|
1575
|
-
// toggles the checkbox value if it was checked
|
|
1576
|
-
if (checked.value) {
|
|
1577
|
-
handleCheckboxChange(unref(checkedValue), false);
|
|
1578
|
-
}
|
|
1579
|
-
});
|
|
1580
1585
|
return Object.assign(Object.assign({}, field), { checked,
|
|
1581
1586
|
checkedValue,
|
|
1582
1587
|
uncheckedValue, handleChange: handleCheckboxChange });
|
|
1583
1588
|
}
|
|
1584
1589
|
return patchCheckboxApi(_useField(name, rules, opts));
|
|
1590
|
+
}
|
|
1591
|
+
function useVModel({ prop, value, handleChange }) {
|
|
1592
|
+
const vm = getCurrentInstance();
|
|
1593
|
+
/* istanbul ignore next */
|
|
1594
|
+
if (!vm) {
|
|
1595
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1596
|
+
console.warn('Failed to setup model events because `useField` was not called in setup.');
|
|
1597
|
+
}
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
const propName = prop || 'modelValue';
|
|
1601
|
+
const emitName = `update:${propName}`;
|
|
1602
|
+
// Component doesn't have a model prop setup (must be defined on the props)
|
|
1603
|
+
if (!(propName in vm.props)) {
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
watch(value, newValue => {
|
|
1607
|
+
if (es6(newValue, getCurrentModelValue(vm, propName))) {
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
vm.emit(emitName, newValue);
|
|
1611
|
+
});
|
|
1612
|
+
watch(() => getCurrentModelValue(vm, propName), propValue => {
|
|
1613
|
+
if (propValue === IS_ABSENT && value.value === undefined) {
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
const newValue = propValue === IS_ABSENT ? undefined : propValue;
|
|
1617
|
+
if (es6(newValue, applyModelModifiers(value.value, vm.props.modelModifiers))) {
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
handleChange(newValue);
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
function getCurrentModelValue(vm, propName) {
|
|
1624
|
+
return vm.props[propName];
|
|
1585
1625
|
}
|
|
1586
1626
|
|
|
1587
1627
|
const FieldImpl = defineComponent({
|
|
@@ -1648,13 +1688,17 @@ const FieldImpl = defineComponent({
|
|
|
1648
1688
|
type: Boolean,
|
|
1649
1689
|
default: false,
|
|
1650
1690
|
},
|
|
1691
|
+
keepValue: {
|
|
1692
|
+
type: Boolean,
|
|
1693
|
+
default: undefined,
|
|
1694
|
+
},
|
|
1651
1695
|
},
|
|
1652
1696
|
setup(props, ctx) {
|
|
1653
1697
|
const rules = toRef(props, 'rules');
|
|
1654
1698
|
const name = toRef(props, 'name');
|
|
1655
1699
|
const label = toRef(props, 'label');
|
|
1656
1700
|
const uncheckedValue = toRef(props, 'uncheckedValue');
|
|
1657
|
-
const
|
|
1701
|
+
const keepValue = toRef(props, 'keepValue');
|
|
1658
1702
|
const { errors, value, errorMessage, validate: validateField, handleChange, handleBlur, setTouched, resetField, handleReset, meta, checked, setErrors, } = useField(name, rules, {
|
|
1659
1703
|
validateOnMount: props.validateOnMount,
|
|
1660
1704
|
bails: props.bails,
|
|
@@ -1666,25 +1710,22 @@ const FieldImpl = defineComponent({
|
|
|
1666
1710
|
uncheckedValue,
|
|
1667
1711
|
label,
|
|
1668
1712
|
validateOnValueUpdate: false,
|
|
1713
|
+
keepValueOnUnmount: keepValue,
|
|
1669
1714
|
});
|
|
1670
1715
|
// If there is a v-model applied on the component we need to emit the `update:modelValue` whenever the value binding changes
|
|
1671
|
-
const onChangeHandler =
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
}
|
|
1676
|
-
: handleChange;
|
|
1716
|
+
const onChangeHandler = function handleChangeWithModel(e, shouldValidate = true) {
|
|
1717
|
+
handleChange(e, shouldValidate);
|
|
1718
|
+
ctx.emit('update:modelValue', value.value);
|
|
1719
|
+
};
|
|
1677
1720
|
const handleInput = (e) => {
|
|
1678
1721
|
if (!hasCheckedAttr(ctx.attrs.type)) {
|
|
1679
1722
|
value.value = normalizeEventValue(e);
|
|
1680
1723
|
}
|
|
1681
1724
|
};
|
|
1682
|
-
const onInputHandler =
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
}
|
|
1687
|
-
: handleInput;
|
|
1725
|
+
const onInputHandler = function handleInputWithModel(e) {
|
|
1726
|
+
handleInput(e);
|
|
1727
|
+
ctx.emit('update:modelValue', value.value);
|
|
1728
|
+
};
|
|
1688
1729
|
const fieldProps = computed(() => {
|
|
1689
1730
|
const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(props);
|
|
1690
1731
|
const baseOnBlur = [handleBlur, ctx.attrs.onBlur, validateOnBlur ? validateField : undefined].filter(Boolean);
|
|
@@ -1700,26 +1741,12 @@ const FieldImpl = defineComponent({
|
|
|
1700
1741
|
if (hasCheckedAttr(ctx.attrs.type) && checked) {
|
|
1701
1742
|
attrs.checked = checked.value;
|
|
1702
1743
|
}
|
|
1703
|
-
else {
|
|
1704
|
-
attrs.value = value.value;
|
|
1705
|
-
}
|
|
1706
1744
|
const tag = resolveTag(props, ctx);
|
|
1707
1745
|
if (shouldHaveValueBinding(tag, ctx.attrs)) {
|
|
1708
|
-
|
|
1746
|
+
attrs.value = value.value;
|
|
1709
1747
|
}
|
|
1710
1748
|
return attrs;
|
|
1711
1749
|
});
|
|
1712
|
-
const modelValue = toRef(props, 'modelValue');
|
|
1713
|
-
watch(modelValue, newModelValue => {
|
|
1714
|
-
// Don't attempt to sync absent values
|
|
1715
|
-
if (newModelValue === IS_ABSENT && value.value === undefined) {
|
|
1716
|
-
return;
|
|
1717
|
-
}
|
|
1718
|
-
if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) {
|
|
1719
|
-
value.value = newModelValue === IS_ABSENT ? undefined : newModelValue;
|
|
1720
|
-
validateField();
|
|
1721
|
-
}
|
|
1722
|
-
});
|
|
1723
1750
|
function slotProps() {
|
|
1724
1751
|
return {
|
|
1725
1752
|
field: fieldProps.value,
|
|
@@ -1771,12 +1798,6 @@ function resolveValidationTriggers(props) {
|
|
|
1771
1798
|
validateOnModelUpdate: (_d = props.validateOnModelUpdate) !== null && _d !== void 0 ? _d : validateOnModelUpdate,
|
|
1772
1799
|
};
|
|
1773
1800
|
}
|
|
1774
|
-
function applyModifiers(value, modifiers) {
|
|
1775
|
-
if (modifiers.number) {
|
|
1776
|
-
return toNumber(value);
|
|
1777
|
-
}
|
|
1778
|
-
return value;
|
|
1779
|
-
}
|
|
1780
1801
|
function resolveInitialValue(props, ctx) {
|
|
1781
1802
|
// Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
|
|
1782
1803
|
// For checkboxes and radio buttons it will always be the model value not the `value` attribute
|
|
@@ -1789,6 +1810,7 @@ const Field = FieldImpl;
|
|
|
1789
1810
|
|
|
1790
1811
|
let FORM_COUNTER = 0;
|
|
1791
1812
|
function useForm(opts) {
|
|
1813
|
+
var _a;
|
|
1792
1814
|
const formId = FORM_COUNTER++;
|
|
1793
1815
|
// Prevents fields from double resetting their values, which causes checkboxes to toggle their initial value
|
|
1794
1816
|
// TODO: This won't be needed if we centralize all the state inside the `form` for form inputs
|
|
@@ -1799,8 +1821,8 @@ function useForm(opts) {
|
|
|
1799
1821
|
const isSubmitting = ref(false);
|
|
1800
1822
|
// The number of times the user tried to submit the form
|
|
1801
1823
|
const submitCount = ref(0);
|
|
1802
|
-
//
|
|
1803
|
-
const
|
|
1824
|
+
// field arrays managed by this form
|
|
1825
|
+
const fieldArrays = [];
|
|
1804
1826
|
// a private ref for all form values
|
|
1805
1827
|
const formValues = reactive(klona(unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {}));
|
|
1806
1828
|
// the source of errors for the form fields
|
|
@@ -1847,10 +1869,11 @@ function useForm(opts) {
|
|
|
1847
1869
|
// mutable non-reactive reference to initial errors
|
|
1848
1870
|
// we need this to process initial errors then unset them
|
|
1849
1871
|
const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
|
|
1872
|
+
const keepValuesOnUnmount = (_a = opts === null || opts === void 0 ? void 0 : opts.keepValuesOnUnmount) !== null && _a !== void 0 ? _a : false;
|
|
1850
1873
|
// initial form values
|
|
1851
1874
|
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(fieldsByPath, formValues, opts === null || opts === void 0 ? void 0 : opts.initialValues);
|
|
1852
1875
|
// form meta aggregations
|
|
1853
|
-
const meta = useFormMeta(fieldsByPath, formValues,
|
|
1876
|
+
const meta = useFormMeta(fieldsByPath, formValues, originalInitialValues, errors);
|
|
1854
1877
|
const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
|
|
1855
1878
|
const formCtx = {
|
|
1856
1879
|
formId,
|
|
@@ -1862,7 +1885,8 @@ function useForm(opts) {
|
|
|
1862
1885
|
submitCount,
|
|
1863
1886
|
meta,
|
|
1864
1887
|
isSubmitting,
|
|
1865
|
-
|
|
1888
|
+
fieldArrays,
|
|
1889
|
+
keepValuesOnUnmount,
|
|
1866
1890
|
validateSchema: unref(schema) ? validateSchema : undefined,
|
|
1867
1891
|
validate,
|
|
1868
1892
|
register: registerField,
|
|
@@ -1880,6 +1904,7 @@ function useForm(opts) {
|
|
|
1880
1904
|
stageInitialValue,
|
|
1881
1905
|
unsetInitialValue,
|
|
1882
1906
|
setFieldInitialValue,
|
|
1907
|
+
useFieldModel,
|
|
1883
1908
|
};
|
|
1884
1909
|
function isFieldGroup(fieldOrGroup) {
|
|
1885
1910
|
return Array.isArray(fieldOrGroup);
|
|
@@ -1949,7 +1974,22 @@ function useForm(opts) {
|
|
|
1949
1974
|
setFieldValue(path, fields[path]);
|
|
1950
1975
|
});
|
|
1951
1976
|
// regenerate the arrays when the form values change
|
|
1952
|
-
|
|
1977
|
+
fieldArrays.forEach(f => f && f.reset());
|
|
1978
|
+
}
|
|
1979
|
+
function createModel(path) {
|
|
1980
|
+
const { value } = _useFieldValue(path);
|
|
1981
|
+
watch(value, () => {
|
|
1982
|
+
if (!fieldExists(unref(path))) {
|
|
1983
|
+
validate({ mode: 'validated-only' });
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1986
|
+
return value;
|
|
1987
|
+
}
|
|
1988
|
+
function useFieldModel(path) {
|
|
1989
|
+
if (!Array.isArray(path)) {
|
|
1990
|
+
return createModel(path);
|
|
1991
|
+
}
|
|
1992
|
+
return path.map(createModel);
|
|
1953
1993
|
}
|
|
1954
1994
|
/**
|
|
1955
1995
|
* Sets the touched meta state on a field
|
|
@@ -2027,10 +2067,6 @@ function useForm(opts) {
|
|
|
2027
2067
|
return;
|
|
2028
2068
|
}
|
|
2029
2069
|
fieldAtPath.splice(idx, 1);
|
|
2030
|
-
if (fieldAtPath.length === 1) {
|
|
2031
|
-
fieldsByPath.value[fieldPath] = fieldAtPath[0];
|
|
2032
|
-
return;
|
|
2033
|
-
}
|
|
2034
2070
|
if (!fieldAtPath.length) {
|
|
2035
2071
|
delete fieldsByPath.value[fieldPath];
|
|
2036
2072
|
}
|
|
@@ -2073,13 +2109,45 @@ function useForm(opts) {
|
|
|
2073
2109
|
}
|
|
2074
2110
|
function unregisterField(field) {
|
|
2075
2111
|
const fieldName = unref(field.name);
|
|
2112
|
+
const fieldInstance = fieldsByPath.value[fieldName];
|
|
2113
|
+
const isGroup = !!fieldInstance && isFieldGroup(fieldInstance);
|
|
2076
2114
|
removeFieldFromPath(field, fieldName);
|
|
2115
|
+
// clears a field error on unmounted
|
|
2116
|
+
// we wait till next tick to make sure if the field is completely removed and doesn't have any siblings like checkboxes
|
|
2077
2117
|
nextTick(() => {
|
|
2078
|
-
|
|
2079
|
-
|
|
2118
|
+
var _a;
|
|
2119
|
+
const shouldKeepValue = (_a = unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : unref(keepValuesOnUnmount);
|
|
2120
|
+
const currentGroupValue = getFromPath(formValues, fieldName);
|
|
2121
|
+
// The boolean here is we check if the field still belongs to the same control group with that name
|
|
2122
|
+
// if another group claimed the name, we should avoid handling it since it is no longer the same group
|
|
2123
|
+
// this happens with `v-for` over some checkboxes and field arrays.
|
|
2124
|
+
// also if the group no longer exist we can assume this group was the last one that controlled it
|
|
2125
|
+
const isSameGroup = isGroup && (fieldInstance === fieldsByPath.value[fieldName] || !fieldsByPath.value[fieldName]);
|
|
2126
|
+
// group field that still has a dangling value, the field may exist or not after it was removed.
|
|
2127
|
+
// This used to be handled in the useField composable but the form has better context on when it should/not happen.
|
|
2128
|
+
// if it does belong to it that means the group still exists
|
|
2129
|
+
// #3844
|
|
2130
|
+
if (isSameGroup && Array.isArray(currentGroupValue) && !shouldKeepValue) {
|
|
2131
|
+
const valueIdx = currentGroupValue.findIndex(i => es6(i, unref(field.checkedValue)));
|
|
2132
|
+
if (valueIdx > -1) {
|
|
2133
|
+
const newVal = [...currentGroupValue];
|
|
2134
|
+
newVal.splice(valueIdx, 1);
|
|
2135
|
+
setFieldValue(fieldName, newVal, { force: true });
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
// Field was removed entirely, we should unset its path
|
|
2080
2139
|
// #3384
|
|
2081
2140
|
if (!fieldExists(fieldName)) {
|
|
2082
2141
|
setFieldError(fieldName, undefined);
|
|
2142
|
+
// Checks if the field was configured to be unset during unmount or not
|
|
2143
|
+
// Checks both the form-level config and field-level one
|
|
2144
|
+
// Field has the priority if it is set, otherwise it goes to the form settings
|
|
2145
|
+
if (shouldKeepValue) {
|
|
2146
|
+
return;
|
|
2147
|
+
}
|
|
2148
|
+
if (isGroup && !isEmptyContainer(getFromPath(formValues, fieldName))) {
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2083
2151
|
unsetPath(formValues, fieldName);
|
|
2084
2152
|
}
|
|
2085
2153
|
});
|
|
@@ -2186,9 +2254,12 @@ function useForm(opts) {
|
|
|
2186
2254
|
/**
|
|
2187
2255
|
* Sneaky function to set initial field values
|
|
2188
2256
|
*/
|
|
2189
|
-
function stageInitialValue(path, value) {
|
|
2257
|
+
function stageInitialValue(path, value, updateOriginal = false) {
|
|
2190
2258
|
setInPath(formValues, path, value);
|
|
2191
2259
|
setFieldInitialValue(path, value);
|
|
2260
|
+
if (updateOriginal) {
|
|
2261
|
+
setInPath(originalInitialValues.value, path, klona(value));
|
|
2262
|
+
}
|
|
2192
2263
|
}
|
|
2193
2264
|
async function _validateSchema() {
|
|
2194
2265
|
const schemaValue = unref(schema);
|
|
@@ -2205,10 +2276,12 @@ function useForm(opts) {
|
|
|
2205
2276
|
}
|
|
2206
2277
|
/**
|
|
2207
2278
|
* Batches validation runs in 5ms batches
|
|
2279
|
+
* Must have two distinct batch queues to make sure they don't override each other settings #3783
|
|
2208
2280
|
*/
|
|
2209
|
-
const
|
|
2281
|
+
const debouncedSilentValidation = debounceAsync(_validateSchema, 5);
|
|
2282
|
+
const debouncedValidation = debounceAsync(_validateSchema, 5);
|
|
2210
2283
|
async function validateSchema(mode) {
|
|
2211
|
-
const formResult = await
|
|
2284
|
+
const formResult = await (mode === 'silent' ? debouncedSilentValidation() : debouncedValidation());
|
|
2212
2285
|
// fields by id lookup
|
|
2213
2286
|
const fieldsById = formCtx.fieldsByPath.value || {};
|
|
2214
2287
|
// errors fields names, we need it to also check if custom errors are updated
|
|
@@ -2304,6 +2377,7 @@ function useForm(opts) {
|
|
|
2304
2377
|
setValues,
|
|
2305
2378
|
setFieldTouched,
|
|
2306
2379
|
setTouched,
|
|
2380
|
+
useFieldModel,
|
|
2307
2381
|
};
|
|
2308
2382
|
}
|
|
2309
2383
|
/**
|
|
@@ -2455,17 +2529,28 @@ const FormImpl = defineComponent({
|
|
|
2455
2529
|
type: Function,
|
|
2456
2530
|
default: undefined,
|
|
2457
2531
|
},
|
|
2532
|
+
keepValues: {
|
|
2533
|
+
type: Boolean,
|
|
2534
|
+
default: false,
|
|
2535
|
+
},
|
|
2458
2536
|
},
|
|
2459
2537
|
setup(props, ctx) {
|
|
2460
2538
|
const initialValues = toRef(props, 'initialValues');
|
|
2461
2539
|
const validationSchema = toRef(props, 'validationSchema');
|
|
2462
|
-
const
|
|
2540
|
+
const keepValues = toRef(props, 'keepValues');
|
|
2541
|
+
const { errors, values, meta, isSubmitting, submitCount, validate, validateField, handleReset, resetForm, handleSubmit, setErrors, setFieldError, setFieldValue, setValues, setFieldTouched, setTouched, } = useForm({
|
|
2463
2542
|
validationSchema: validationSchema.value ? validationSchema : undefined,
|
|
2464
2543
|
initialValues,
|
|
2465
2544
|
initialErrors: props.initialErrors,
|
|
2466
2545
|
initialTouched: props.initialTouched,
|
|
2467
2546
|
validateOnMount: props.validateOnMount,
|
|
2547
|
+
keepValuesOnUnmount: keepValues,
|
|
2468
2548
|
});
|
|
2549
|
+
const submitForm = handleSubmit((_, { evt }) => {
|
|
2550
|
+
if (isFormSubmitEvent(evt)) {
|
|
2551
|
+
evt.target.submit();
|
|
2552
|
+
}
|
|
2553
|
+
}, props.onInvalidSubmit);
|
|
2469
2554
|
const onSubmit = props.onSubmit ? handleSubmit(props.onSubmit, props.onInvalidSubmit) : submitForm;
|
|
2470
2555
|
function handleFormReset(e) {
|
|
2471
2556
|
if (isEvent(e)) {
|
|
@@ -2534,15 +2619,13 @@ const FormImpl = defineComponent({
|
|
|
2534
2619
|
});
|
|
2535
2620
|
const Form = FormImpl;
|
|
2536
2621
|
|
|
2537
|
-
let FIELD_ARRAY_COUNTER = 0;
|
|
2538
2622
|
function useFieldArray(arrayPath) {
|
|
2539
|
-
const id = FIELD_ARRAY_COUNTER++;
|
|
2540
2623
|
const form = injectWithSelf(FormContextKey, undefined);
|
|
2541
2624
|
const fields = ref([]);
|
|
2542
2625
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
2543
2626
|
const noOp = () => { };
|
|
2544
2627
|
const noOpApi = {
|
|
2545
|
-
fields
|
|
2628
|
+
fields,
|
|
2546
2629
|
remove: noOp,
|
|
2547
2630
|
push: noOp,
|
|
2548
2631
|
swap: noOp,
|
|
@@ -2550,6 +2633,7 @@ function useFieldArray(arrayPath) {
|
|
|
2550
2633
|
update: noOp,
|
|
2551
2634
|
replace: noOp,
|
|
2552
2635
|
prepend: noOp,
|
|
2636
|
+
move: noOp,
|
|
2553
2637
|
};
|
|
2554
2638
|
if (!form) {
|
|
2555
2639
|
warn('FieldArray requires being a child of `<Form/>` or `useForm` being called before it. Array fields may not work correctly');
|
|
@@ -2559,9 +2643,13 @@ function useFieldArray(arrayPath) {
|
|
|
2559
2643
|
warn('FieldArray requires a field path to be provided, did you forget to pass the `name` prop?');
|
|
2560
2644
|
return noOpApi;
|
|
2561
2645
|
}
|
|
2646
|
+
const alreadyExists = form.fieldArrays.find(a => unref(a.path) === unref(arrayPath));
|
|
2647
|
+
if (alreadyExists) {
|
|
2648
|
+
return alreadyExists;
|
|
2649
|
+
}
|
|
2562
2650
|
let entryCounter = 0;
|
|
2563
2651
|
function initFields() {
|
|
2564
|
-
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []);
|
|
2652
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []) || [];
|
|
2565
2653
|
fields.value = currentValues.map(createEntry);
|
|
2566
2654
|
updateEntryFlags();
|
|
2567
2655
|
}
|
|
@@ -2578,10 +2666,20 @@ function useFieldArray(arrayPath) {
|
|
|
2578
2666
|
const key = entryCounter++;
|
|
2579
2667
|
const entry = {
|
|
2580
2668
|
key,
|
|
2581
|
-
value: computed(
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2669
|
+
value: computed({
|
|
2670
|
+
get() {
|
|
2671
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, unref(arrayPath), []) || [];
|
|
2672
|
+
const idx = fields.value.findIndex(e => e.key === key);
|
|
2673
|
+
return idx === -1 ? value : currentValues[idx];
|
|
2674
|
+
},
|
|
2675
|
+
set(value) {
|
|
2676
|
+
const idx = fields.value.findIndex(e => e.key === key);
|
|
2677
|
+
if (idx === -1) {
|
|
2678
|
+
warn(`Attempting to update a non-existent array item`);
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
update(idx, value);
|
|
2682
|
+
},
|
|
2585
2683
|
}),
|
|
2586
2684
|
isFirst: false,
|
|
2587
2685
|
isLast: false,
|
|
@@ -2674,14 +2772,26 @@ function useFieldArray(arrayPath) {
|
|
|
2674
2772
|
fields.value.unshift(createEntry(value));
|
|
2675
2773
|
updateEntryFlags();
|
|
2676
2774
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2775
|
+
function move(oldIdx, newIdx) {
|
|
2776
|
+
const pathName = unref(arrayPath);
|
|
2777
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2778
|
+
const newValue = isNullOrUndefined(pathValue) ? [] : [...pathValue];
|
|
2779
|
+
if (!Array.isArray(pathValue) || !(oldIdx in pathValue) || !(newIdx in pathValue)) {
|
|
2780
|
+
return;
|
|
2781
|
+
}
|
|
2782
|
+
const newFields = [...fields.value];
|
|
2783
|
+
const movedItem = newFields[oldIdx];
|
|
2784
|
+
newFields.splice(oldIdx, 1);
|
|
2785
|
+
newFields.splice(newIdx, 0, movedItem);
|
|
2786
|
+
const movedValue = newValue[oldIdx];
|
|
2787
|
+
newValue.splice(oldIdx, 1);
|
|
2788
|
+
newValue.splice(newIdx, 0, movedValue);
|
|
2789
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2790
|
+
fields.value = newFields;
|
|
2791
|
+
updateEntryFlags();
|
|
2792
|
+
}
|
|
2793
|
+
const fieldArrayCtx = {
|
|
2794
|
+
fields,
|
|
2685
2795
|
remove,
|
|
2686
2796
|
push,
|
|
2687
2797
|
swap,
|
|
@@ -2689,7 +2799,16 @@ function useFieldArray(arrayPath) {
|
|
|
2689
2799
|
update,
|
|
2690
2800
|
replace,
|
|
2691
2801
|
prepend,
|
|
2802
|
+
move,
|
|
2692
2803
|
};
|
|
2804
|
+
form.fieldArrays.push(Object.assign({ path: arrayPath, reset: initFields }, fieldArrayCtx));
|
|
2805
|
+
onBeforeUnmount(() => {
|
|
2806
|
+
const idx = form.fieldArrays.findIndex(i => unref(i.path) === unref(arrayPath));
|
|
2807
|
+
if (idx >= 0) {
|
|
2808
|
+
form.fieldArrays.splice(idx, 1);
|
|
2809
|
+
}
|
|
2810
|
+
});
|
|
2811
|
+
return fieldArrayCtx;
|
|
2693
2812
|
}
|
|
2694
2813
|
|
|
2695
2814
|
const FieldArrayImpl = defineComponent({
|
|
@@ -2702,7 +2821,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2702
2821
|
},
|
|
2703
2822
|
},
|
|
2704
2823
|
setup(props, ctx) {
|
|
2705
|
-
const { push, remove, swap, insert, replace, update, prepend, fields } = useFieldArray(toRef(props, 'name'));
|
|
2824
|
+
const { push, remove, swap, insert, replace, update, prepend, move, fields } = useFieldArray(toRef(props, 'name'));
|
|
2706
2825
|
function slotProps() {
|
|
2707
2826
|
return {
|
|
2708
2827
|
fields: fields.value,
|
|
@@ -2713,6 +2832,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2713
2832
|
update,
|
|
2714
2833
|
replace,
|
|
2715
2834
|
prepend,
|
|
2835
|
+
move,
|
|
2716
2836
|
};
|
|
2717
2837
|
}
|
|
2718
2838
|
ctx.expose({
|
|
@@ -2723,6 +2843,7 @@ const FieldArrayImpl = defineComponent({
|
|
|
2723
2843
|
update,
|
|
2724
2844
|
replace,
|
|
2725
2845
|
prepend,
|
|
2846
|
+
move,
|
|
2726
2847
|
});
|
|
2727
2848
|
return () => {
|
|
2728
2849
|
const children = normalizeChildren(undefined, ctx, slotProps);
|
|
@@ -3022,4 +3143,4 @@ function useSubmitForm(cb) {
|
|
|
3022
3143
|
};
|
|
3023
3144
|
}
|
|
3024
3145
|
|
|
3025
|
-
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 };
|
|
3146
|
+
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 };
|