vee-validate 4.5.11 → 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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * vee-validate v4.5.11
2
+ * vee-validate v4.6.0
3
3
  * (c) 2022 Abdelrahman Awad
4
4
  * @license MIT
5
5
  */
@@ -56,18 +56,6 @@
56
56
  function isLocator(value) {
57
57
  return isCallable(value) && !!value.__locatorRef;
58
58
  }
59
- /**
60
- * Checks if an tag name is a native HTML tag and not a Vue component
61
- */
62
- function isHTMLTag(tag) {
63
- return ['input', 'textarea', 'select'].includes(tag);
64
- }
65
- /**
66
- * Checks if an input is of type file
67
- */
68
- function isFileInputNode(tag, attrs) {
69
- return isHTMLTag(tag) && attrs.type === 'file';
70
- }
71
59
  function isYupValidator(value) {
72
60
  return !!value && isCallable(value.validate);
73
61
  }
@@ -120,7 +108,7 @@
120
108
  * For multi-selects because the value binding will reset the value
121
109
  */
122
110
  function shouldHaveValueBinding(tag, attrs) {
123
- return isNativeMultiSelectNode(tag, attrs) || isFileInputNode(tag, attrs);
111
+ return !isNativeMultiSelectNode(tag, attrs) && attrs.type !== 'file' && !hasCheckedAttr(attrs.type);
124
112
  }
125
113
  function isFormSubmitEvent(evt) {
126
114
  return isEvent(evt) && evt.target && 'submit' in evt.target;
@@ -286,6 +274,15 @@
286
274
  }, ms);
287
275
  return new Promise(resolve => resolves.push(resolve));
288
276
  };
277
+ }
278
+ function applyModelModifiers(value, modifiers) {
279
+ if (!isObject(modifiers)) {
280
+ return;
281
+ }
282
+ if (modifiers.number) {
283
+ return toNumber(value);
284
+ }
285
+ return value;
289
286
  }
290
287
 
291
288
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -329,7 +326,8 @@
329
326
  return getBoundValue(input);
330
327
  }
331
328
  if (input.type === 'file' && input.files) {
332
- return Array.from(input.files);
329
+ const files = Array.from(input.files);
330
+ return input.multiple ? files : files[0];
333
331
  }
334
332
  if (isNativeMultiSelect(input)) {
335
333
  return Array.from(input.options)
@@ -828,8 +826,8 @@
828
826
  /**
829
827
  * Creates the field value and resolves the initial value
830
828
  */
831
- function _useFieldValue(path, modelValue, shouldInjectForm) {
832
- const form = shouldInjectForm ? injectWithSelf(FormContextKey, undefined) : undefined;
829
+ function _useFieldValue(path, modelValue, shouldInjectForm = true) {
830
+ const form = shouldInjectForm === true ? injectWithSelf(FormContextKey, undefined) : undefined;
833
831
  const modelRef = vue.ref(vue.unref(modelValue));
834
832
  function resolveInitialValue() {
835
833
  if (!form) {
@@ -859,7 +857,7 @@
859
857
  // prioritize model value over form values
860
858
  // #3429
861
859
  const currentValue = modelValue ? vue.unref(modelValue) : getFromPath(form.values, vue.unref(path), vue.unref(initialValue));
862
- form.stageInitialValue(vue.unref(path), currentValue);
860
+ form.stageInitialValue(vue.unref(path), currentValue, true);
863
861
  // otherwise use a computed setter that triggers the `setFieldValue`
864
862
  const value = vue.computed({
865
863
  get() {
@@ -938,7 +936,7 @@
938
936
  return _useField(name, rules, opts);
939
937
  }
940
938
  function _useField(name, rules, opts) {
941
- const { initialValue: modelValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue, standalone, } = normalizeOptions(vue.unref(name), opts);
939
+ const { initialValue: modelValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue, standalone, keepValueOnUnmount, modelPropName, syncVModel, } = normalizeOptions(vue.unref(name), opts);
942
940
  const form = !standalone ? injectWithSelf(FormContextKey) : undefined;
943
941
  // a flag indicating if the field is about to be removed/unmounted.
944
942
  let markedForRemoval = false;
@@ -946,6 +944,9 @@
946
944
  modelValue,
947
945
  standalone,
948
946
  });
947
+ if (syncVModel) {
948
+ useVModel({ value, prop: modelPropName, handleChange });
949
+ }
949
950
  /**
950
951
  * Handles common onBlur meta update
951
952
  */
@@ -1004,13 +1005,13 @@
1004
1005
  return validateValidStateOnly();
1005
1006
  }
1006
1007
  // Common input/change event handler
1007
- const handleChange = (e, shouldValidate = true) => {
1008
+ function handleChange(e, shouldValidate = true) {
1008
1009
  const newValue = normalizeEventValue(e);
1009
1010
  value.value = newValue;
1010
1011
  if (!validateOnValueUpdate && shouldValidate) {
1011
1012
  validateWithStateMutation();
1012
1013
  }
1013
- };
1014
+ }
1014
1015
  // Runs the initial validation
1015
1016
  vue.onMounted(() => {
1016
1017
  if (validateOnMount) {
@@ -1027,7 +1028,13 @@
1027
1028
  }
1028
1029
  let unwatchValue;
1029
1030
  function watchValue() {
1030
- unwatchValue = vue.watch(value, validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly, {
1031
+ unwatchValue = vue.watch(value, (val, oldVal) => {
1032
+ if (es6(val, oldVal)) {
1033
+ return;
1034
+ }
1035
+ const validateFn = validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly;
1036
+ validateFn();
1037
+ }, {
1031
1038
  deep: true,
1032
1039
  });
1033
1040
  }
@@ -1068,6 +1075,7 @@
1068
1075
  checkedValue,
1069
1076
  uncheckedValue,
1070
1077
  bails,
1078
+ keepValueOnUnmount,
1071
1079
  resetField,
1072
1080
  handleReset: () => resetField(),
1073
1081
  validate: validate$1,
@@ -1145,6 +1153,9 @@
1145
1153
  label: name,
1146
1154
  validateOnValueUpdate: true,
1147
1155
  standalone: false,
1156
+ keepValueOnUnmount: undefined,
1157
+ modelPropName: 'modelValue',
1158
+ syncVModel: true,
1148
1159
  });
1149
1160
  if (!opts) {
1150
1161
  return defaults();
@@ -1176,8 +1187,8 @@
1176
1187
  return Array.isArray(currentValue) ? currentValue.includes(checkedVal) : checkedVal === currentValue;
1177
1188
  });
1178
1189
  function handleCheckboxChange(e, shouldValidate = true) {
1179
- var _a, _b;
1180
- if (checked.value === ((_b = (_a = e) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.checked)) {
1190
+ var _a;
1191
+ if (checked.value === ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.checked)) {
1181
1192
  return;
1182
1193
  }
1183
1194
  let newValue = normalizeEventValue(e);
@@ -1188,8 +1199,10 @@
1188
1199
  handleChange(newValue, shouldValidate);
1189
1200
  }
1190
1201
  vue.onBeforeUnmount(() => {
1191
- // toggles the checkbox value if it was checked
1192
- if (checked.value) {
1202
+ var _a, _b;
1203
+ const shouldKeepValue = (_b = (_a = vue.unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : vue.unref(form === null || form === void 0 ? void 0 : form.keepValuesOnUnmount)) !== null && _b !== void 0 ? _b : false;
1204
+ // toggles the checkbox value if it was checked and the unset behavior is set
1205
+ if (checked.value && !shouldKeepValue) {
1193
1206
  handleCheckboxChange(vue.unref(checkedValue), false);
1194
1207
  }
1195
1208
  });
@@ -1198,6 +1211,38 @@
1198
1211
  uncheckedValue, handleChange: handleCheckboxChange });
1199
1212
  }
1200
1213
  return patchCheckboxApi(_useField(name, rules, opts));
1214
+ }
1215
+ function useVModel({ prop, value, handleChange }) {
1216
+ const vm = vue.getCurrentInstance();
1217
+ /* istanbul ignore next */
1218
+ if (!vm) {
1219
+ return;
1220
+ }
1221
+ const propName = prop || 'modelValue';
1222
+ const emitName = `update:${propName}`;
1223
+ // Component doesn't have a model prop setup (must be defined on the props)
1224
+ if (!(propName in vm.props)) {
1225
+ return;
1226
+ }
1227
+ vue.watch(value, newValue => {
1228
+ if (es6(newValue, getCurrentModelValue(vm, propName))) {
1229
+ return;
1230
+ }
1231
+ vm.emit(emitName, newValue);
1232
+ });
1233
+ vue.watch(() => getCurrentModelValue(vm, propName), propValue => {
1234
+ if (propValue === IS_ABSENT && value.value === undefined) {
1235
+ return;
1236
+ }
1237
+ const newValue = propValue === IS_ABSENT ? undefined : propValue;
1238
+ if (es6(newValue, applyModelModifiers(value.value, vm.props.modelModifiers))) {
1239
+ return;
1240
+ }
1241
+ handleChange(newValue);
1242
+ });
1243
+ }
1244
+ function getCurrentModelValue(vm, propName) {
1245
+ return vm.props[propName];
1201
1246
  }
1202
1247
 
1203
1248
  const FieldImpl = vue.defineComponent({
@@ -1264,13 +1309,17 @@
1264
1309
  type: Boolean,
1265
1310
  default: false,
1266
1311
  },
1312
+ keepValue: {
1313
+ type: Boolean,
1314
+ default: undefined,
1315
+ },
1267
1316
  },
1268
1317
  setup(props, ctx) {
1269
1318
  const rules = vue.toRef(props, 'rules');
1270
1319
  const name = vue.toRef(props, 'name');
1271
1320
  const label = vue.toRef(props, 'label');
1272
1321
  const uncheckedValue = vue.toRef(props, 'uncheckedValue');
1273
- const hasModelEvents = isPropPresent(props, 'onUpdate:modelValue');
1322
+ const keepValue = vue.toRef(props, 'keepValue');
1274
1323
  const { errors, value, errorMessage, validate: validateField, handleChange, handleBlur, setTouched, resetField, handleReset, meta, checked, setErrors, } = useField(name, rules, {
1275
1324
  validateOnMount: props.validateOnMount,
1276
1325
  bails: props.bails,
@@ -1282,25 +1331,22 @@
1282
1331
  uncheckedValue,
1283
1332
  label,
1284
1333
  validateOnValueUpdate: false,
1334
+ keepValueOnUnmount: keepValue,
1285
1335
  });
1286
1336
  // If there is a v-model applied on the component we need to emit the `update:modelValue` whenever the value binding changes
1287
- const onChangeHandler = hasModelEvents
1288
- ? function handleChangeWithModel(e, shouldValidate = true) {
1289
- handleChange(e, shouldValidate);
1290
- ctx.emit('update:modelValue', value.value);
1291
- }
1292
- : handleChange;
1337
+ const onChangeHandler = function handleChangeWithModel(e, shouldValidate = true) {
1338
+ handleChange(e, shouldValidate);
1339
+ ctx.emit('update:modelValue', value.value);
1340
+ };
1293
1341
  const handleInput = (e) => {
1294
1342
  if (!hasCheckedAttr(ctx.attrs.type)) {
1295
1343
  value.value = normalizeEventValue(e);
1296
1344
  }
1297
1345
  };
1298
- const onInputHandler = hasModelEvents
1299
- ? function handleInputWithModel(e) {
1300
- handleInput(e);
1301
- ctx.emit('update:modelValue', value.value);
1302
- }
1303
- : handleInput;
1346
+ const onInputHandler = function handleInputWithModel(e) {
1347
+ handleInput(e);
1348
+ ctx.emit('update:modelValue', value.value);
1349
+ };
1304
1350
  const fieldProps = vue.computed(() => {
1305
1351
  const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(props);
1306
1352
  const baseOnBlur = [handleBlur, ctx.attrs.onBlur, validateOnBlur ? validateField : undefined].filter(Boolean);
@@ -1316,26 +1362,12 @@
1316
1362
  if (hasCheckedAttr(ctx.attrs.type) && checked) {
1317
1363
  attrs.checked = checked.value;
1318
1364
  }
1319
- else {
1320
- attrs.value = value.value;
1321
- }
1322
1365
  const tag = resolveTag(props, ctx);
1323
1366
  if (shouldHaveValueBinding(tag, ctx.attrs)) {
1324
- delete attrs.value;
1367
+ attrs.value = value.value;
1325
1368
  }
1326
1369
  return attrs;
1327
1370
  });
1328
- const modelValue = vue.toRef(props, 'modelValue');
1329
- vue.watch(modelValue, newModelValue => {
1330
- // Don't attempt to sync absent values
1331
- if (newModelValue === IS_ABSENT && value.value === undefined) {
1332
- return;
1333
- }
1334
- if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) {
1335
- value.value = newModelValue === IS_ABSENT ? undefined : newModelValue;
1336
- validateField();
1337
- }
1338
- });
1339
1371
  function slotProps() {
1340
1372
  return {
1341
1373
  field: fieldProps.value,
@@ -1387,12 +1419,6 @@
1387
1419
  validateOnModelUpdate: (_d = props.validateOnModelUpdate) !== null && _d !== void 0 ? _d : validateOnModelUpdate,
1388
1420
  };
1389
1421
  }
1390
- function applyModifiers(value, modifiers) {
1391
- if (modifiers.number) {
1392
- return toNumber(value);
1393
- }
1394
- return value;
1395
- }
1396
1422
  function resolveInitialValue(props, ctx) {
1397
1423
  // Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
1398
1424
  // For checkboxes and radio buttons it will always be the model value not the `value` attribute
@@ -1405,6 +1431,7 @@
1405
1431
 
1406
1432
  let FORM_COUNTER = 0;
1407
1433
  function useForm(opts) {
1434
+ var _a;
1408
1435
  const formId = FORM_COUNTER++;
1409
1436
  // Prevents fields from double resetting their values, which causes checkboxes to toggle their initial value
1410
1437
  // TODO: This won't be needed if we centralize all the state inside the `form` for form inputs
@@ -1415,8 +1442,8 @@
1415
1442
  const isSubmitting = vue.ref(false);
1416
1443
  // The number of times the user tried to submit the form
1417
1444
  const submitCount = vue.ref(0);
1418
- // dictionary for field arrays to receive various signals like reset
1419
- const fieldArraysLookup = {};
1445
+ // field arrays managed by this form
1446
+ const fieldArrays = [];
1420
1447
  // a private ref for all form values
1421
1448
  const formValues = vue.reactive(klona(vue.unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {}));
1422
1449
  // the source of errors for the form fields
@@ -1463,10 +1490,11 @@
1463
1490
  // mutable non-reactive reference to initial errors
1464
1491
  // we need this to process initial errors then unset them
1465
1492
  const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
1493
+ const keepValuesOnUnmount = (_a = opts === null || opts === void 0 ? void 0 : opts.keepValuesOnUnmount) !== null && _a !== void 0 ? _a : false;
1466
1494
  // initial form values
1467
1495
  const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(fieldsByPath, formValues, opts === null || opts === void 0 ? void 0 : opts.initialValues);
1468
1496
  // form meta aggregations
1469
- const meta = useFormMeta(fieldsByPath, formValues, initialValues, errors);
1497
+ const meta = useFormMeta(fieldsByPath, formValues, originalInitialValues, errors);
1470
1498
  const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
1471
1499
  const formCtx = {
1472
1500
  formId,
@@ -1478,7 +1506,8 @@
1478
1506
  submitCount,
1479
1507
  meta,
1480
1508
  isSubmitting,
1481
- fieldArraysLookup,
1509
+ fieldArrays,
1510
+ keepValuesOnUnmount,
1482
1511
  validateSchema: vue.unref(schema) ? validateSchema : undefined,
1483
1512
  validate,
1484
1513
  register: registerField,
@@ -1496,6 +1525,7 @@
1496
1525
  stageInitialValue,
1497
1526
  unsetInitialValue,
1498
1527
  setFieldInitialValue,
1528
+ useFieldModel,
1499
1529
  };
1500
1530
  function isFieldGroup(fieldOrGroup) {
1501
1531
  return Array.isArray(fieldOrGroup);
@@ -1565,7 +1595,22 @@
1565
1595
  setFieldValue(path, fields[path]);
1566
1596
  });
1567
1597
  // regenerate the arrays when the form values change
1568
- Object.values(fieldArraysLookup).forEach(f => f && f.reset());
1598
+ fieldArrays.forEach(f => f && f.reset());
1599
+ }
1600
+ function createModel(path) {
1601
+ const { value } = _useFieldValue(path);
1602
+ vue.watch(value, () => {
1603
+ if (!fieldExists(vue.unref(path))) {
1604
+ validate({ mode: 'validated-only' });
1605
+ }
1606
+ });
1607
+ return value;
1608
+ }
1609
+ function useFieldModel(path) {
1610
+ if (!Array.isArray(path)) {
1611
+ return createModel(path);
1612
+ }
1613
+ return path.map(createModel);
1569
1614
  }
1570
1615
  /**
1571
1616
  * Sets the touched meta state on a field
@@ -1689,13 +1734,26 @@
1689
1734
  }
1690
1735
  function unregisterField(field) {
1691
1736
  const fieldName = vue.unref(field.name);
1737
+ const fieldInstance = fieldsByPath.value[fieldName];
1738
+ const isGroup = !!fieldInstance && isFieldGroup(fieldInstance);
1692
1739
  removeFieldFromPath(field, fieldName);
1693
1740
  vue.nextTick(() => {
1741
+ var _a;
1694
1742
  // clears a field error on unmounted
1695
1743
  // we wait till next tick to make sure if the field is completely removed and doesn't have any siblings like checkboxes
1696
1744
  // #3384
1697
1745
  if (!fieldExists(fieldName)) {
1698
1746
  setFieldError(fieldName, undefined);
1747
+ // Checks if the field was configured to be unset during unmount or not
1748
+ // Checks both the form-level config and field-level one
1749
+ // Field has the priority if it is set, otherwise it goes to the form settings
1750
+ const shouldKeepValue = (_a = vue.unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : vue.unref(keepValuesOnUnmount);
1751
+ if (shouldKeepValue) {
1752
+ return;
1753
+ }
1754
+ if (isGroup && !isEmptyContainer(getFromPath(formValues, fieldName))) {
1755
+ return;
1756
+ }
1699
1757
  unsetPath(formValues, fieldName);
1700
1758
  }
1701
1759
  });
@@ -1802,9 +1860,12 @@
1802
1860
  /**
1803
1861
  * Sneaky function to set initial field values
1804
1862
  */
1805
- function stageInitialValue(path, value) {
1863
+ function stageInitialValue(path, value, updateOriginal = false) {
1806
1864
  setInPath(formValues, path, value);
1807
1865
  setFieldInitialValue(path, value);
1866
+ if (updateOriginal) {
1867
+ setInPath(originalInitialValues.value, path, klona(value));
1868
+ }
1808
1869
  }
1809
1870
  async function _validateSchema() {
1810
1871
  const schemaValue = vue.unref(schema);
@@ -1821,10 +1882,12 @@
1821
1882
  }
1822
1883
  /**
1823
1884
  * Batches validation runs in 5ms batches
1885
+ * Must have two distinct batch queues to make sure they don't override each other settings #3783
1824
1886
  */
1825
- const debouncedSchemaValidation = debounceAsync(_validateSchema, 5);
1887
+ const debouncedSilentValidation = debounceAsync(_validateSchema, 5);
1888
+ const debouncedValidation = debounceAsync(_validateSchema, 5);
1826
1889
  async function validateSchema(mode) {
1827
- const formResult = await debouncedSchemaValidation();
1890
+ const formResult = await (mode === 'silent' ? debouncedSilentValidation() : debouncedValidation());
1828
1891
  // fields by id lookup
1829
1892
  const fieldsById = formCtx.fieldsByPath.value || {};
1830
1893
  // errors fields names, we need it to also check if custom errors are updated
@@ -1914,6 +1977,7 @@
1914
1977
  setValues,
1915
1978
  setFieldTouched,
1916
1979
  setTouched,
1980
+ useFieldModel,
1917
1981
  };
1918
1982
  }
1919
1983
  /**
@@ -2065,16 +2129,22 @@
2065
2129
  type: Function,
2066
2130
  default: undefined,
2067
2131
  },
2132
+ keepValues: {
2133
+ type: Boolean,
2134
+ default: false,
2135
+ },
2068
2136
  },
2069
2137
  setup(props, ctx) {
2070
2138
  const initialValues = vue.toRef(props, 'initialValues');
2071
2139
  const validationSchema = vue.toRef(props, 'validationSchema');
2140
+ const keepValues = vue.toRef(props, 'keepValues');
2072
2141
  const { errors, values, meta, isSubmitting, submitCount, validate, validateField, handleReset, resetForm, handleSubmit, submitForm, setErrors, setFieldError, setFieldValue, setValues, setFieldTouched, setTouched, } = useForm({
2073
2142
  validationSchema: validationSchema.value ? validationSchema : undefined,
2074
2143
  initialValues,
2075
2144
  initialErrors: props.initialErrors,
2076
2145
  initialTouched: props.initialTouched,
2077
2146
  validateOnMount: props.validateOnMount,
2147
+ keepValuesOnUnmount: keepValues,
2078
2148
  });
2079
2149
  const onSubmit = props.onSubmit ? handleSubmit(props.onSubmit, props.onInvalidSubmit) : submitForm;
2080
2150
  function handleFormReset(e) {
@@ -2144,15 +2214,13 @@
2144
2214
  });
2145
2215
  const Form = FormImpl;
2146
2216
 
2147
- let FIELD_ARRAY_COUNTER = 0;
2148
2217
  function useFieldArray(arrayPath) {
2149
- const id = FIELD_ARRAY_COUNTER++;
2150
2218
  const form = injectWithSelf(FormContextKey, undefined);
2151
2219
  const fields = vue.ref([]);
2152
2220
  // eslint-disable-next-line @typescript-eslint/no-empty-function
2153
2221
  const noOp = () => { };
2154
2222
  const noOpApi = {
2155
- fields: vue.readonly(fields),
2223
+ fields,
2156
2224
  remove: noOp,
2157
2225
  push: noOp,
2158
2226
  swap: noOp,
@@ -2160,6 +2228,7 @@
2160
2228
  update: noOp,
2161
2229
  replace: noOp,
2162
2230
  prepend: noOp,
2231
+ move: noOp,
2163
2232
  };
2164
2233
  if (!form) {
2165
2234
  warn('FieldArray requires being a child of `<Form/>` or `useForm` being called before it. Array fields may not work correctly');
@@ -2169,9 +2238,13 @@
2169
2238
  warn('FieldArray requires a field path to be provided, did you forget to pass the `name` prop?');
2170
2239
  return noOpApi;
2171
2240
  }
2241
+ const alreadyExists = form.fieldArrays.find(a => vue.unref(a.path) === vue.unref(arrayPath));
2242
+ if (alreadyExists) {
2243
+ return alreadyExists;
2244
+ }
2172
2245
  let entryCounter = 0;
2173
2246
  function initFields() {
2174
- const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []);
2247
+ const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []) || [];
2175
2248
  fields.value = currentValues.map(createEntry);
2176
2249
  updateEntryFlags();
2177
2250
  }
@@ -2188,10 +2261,20 @@
2188
2261
  const key = entryCounter++;
2189
2262
  const entry = {
2190
2263
  key,
2191
- value: vue.computed(() => {
2192
- const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []);
2193
- const idx = fields.value.findIndex(e => e.key === key);
2194
- return idx === -1 ? value : currentValues[idx];
2264
+ value: vue.computed({
2265
+ get() {
2266
+ const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []) || [];
2267
+ const idx = fields.value.findIndex(e => e.key === key);
2268
+ return idx === -1 ? value : currentValues[idx];
2269
+ },
2270
+ set(value) {
2271
+ const idx = fields.value.findIndex(e => e.key === key);
2272
+ if (idx === -1) {
2273
+ warn(`Attempting to update a non-existent array item`);
2274
+ return;
2275
+ }
2276
+ update(idx, value);
2277
+ },
2195
2278
  }),
2196
2279
  isFirst: false,
2197
2280
  isLast: false,
@@ -2284,14 +2367,26 @@
2284
2367
  fields.value.unshift(createEntry(value));
2285
2368
  updateEntryFlags();
2286
2369
  }
2287
- form.fieldArraysLookup[id] = {
2288
- reset: initFields,
2289
- };
2290
- vue.onBeforeUnmount(() => {
2291
- delete form.fieldArraysLookup[id];
2292
- });
2293
- return {
2294
- fields: vue.readonly(fields),
2370
+ function move(oldIdx, newIdx) {
2371
+ const pathName = vue.unref(arrayPath);
2372
+ const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
2373
+ const newValue = isNullOrUndefined(pathValue) ? [] : [...pathValue];
2374
+ if (!Array.isArray(pathValue) || !(oldIdx in pathValue) || !(newIdx in pathValue)) {
2375
+ return;
2376
+ }
2377
+ const newFields = [...fields.value];
2378
+ const movedItem = newFields[oldIdx];
2379
+ newFields.splice(oldIdx, 1);
2380
+ newFields.splice(newIdx, 0, movedItem);
2381
+ const movedValue = newValue[oldIdx];
2382
+ newValue.splice(oldIdx, 1);
2383
+ newValue.splice(newIdx, 0, movedValue);
2384
+ form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
2385
+ fields.value = newFields;
2386
+ updateEntryFlags();
2387
+ }
2388
+ const fieldArrayCtx = {
2389
+ fields,
2295
2390
  remove,
2296
2391
  push,
2297
2392
  swap,
@@ -2299,7 +2394,16 @@
2299
2394
  update,
2300
2395
  replace,
2301
2396
  prepend,
2397
+ move,
2302
2398
  };
2399
+ form.fieldArrays.push(Object.assign({ path: arrayPath, reset: initFields }, fieldArrayCtx));
2400
+ vue.onBeforeUnmount(() => {
2401
+ const idx = form.fieldArrays.findIndex(i => vue.unref(i.path) === vue.unref(arrayPath));
2402
+ if (idx >= 0) {
2403
+ form.fieldArrays.splice(idx, 1);
2404
+ }
2405
+ });
2406
+ return fieldArrayCtx;
2303
2407
  }
2304
2408
 
2305
2409
  const FieldArrayImpl = vue.defineComponent({
@@ -2312,7 +2416,7 @@
2312
2416
  },
2313
2417
  },
2314
2418
  setup(props, ctx) {
2315
- const { push, remove, swap, insert, replace, update, prepend, fields } = useFieldArray(vue.toRef(props, 'name'));
2419
+ const { push, remove, swap, insert, replace, update, prepend, move, fields } = useFieldArray(vue.toRef(props, 'name'));
2316
2420
  function slotProps() {
2317
2421
  return {
2318
2422
  fields: fields.value,
@@ -2323,6 +2427,7 @@
2323
2427
  update,
2324
2428
  replace,
2325
2429
  prepend,
2430
+ move,
2326
2431
  };
2327
2432
  }
2328
2433
  ctx.expose({
@@ -2333,6 +2438,7 @@
2333
2438
  update,
2334
2439
  replace,
2335
2440
  prepend,
2441
+ move,
2336
2442
  });
2337
2443
  return () => {
2338
2444
  const children = normalizeChildren(undefined, ctx, slotProps);
@@ -2638,6 +2744,7 @@
2638
2744
  exports.FieldContextKey = FieldContextKey;
2639
2745
  exports.Form = Form;
2640
2746
  exports.FormContextKey = FormContextKey;
2747
+ exports.IS_ABSENT = IS_ABSENT;
2641
2748
  exports.configure = configure;
2642
2749
  exports.defineRule = defineRule;
2643
2750
  exports.useField = useField;