vee-validate 4.8.5 → 4.9.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 +1 -0
- package/dist/vee-validate.d.ts +265 -71
- package/dist/vee-validate.esm.js +648 -578
- package/dist/vee-validate.js +535 -492
- package/dist/vee-validate.min.js +2 -2
- package/package.json +1 -1
package/dist/vee-validate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vee-validate v4.
|
|
2
|
+
* vee-validate v4.9.0
|
|
3
3
|
* (c) 2023 Abdelrahman Awad
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
@@ -23,6 +23,19 @@
|
|
|
23
23
|
const n = parseFloat(value);
|
|
24
24
|
return isNaN(n) ? value : n;
|
|
25
25
|
}
|
|
26
|
+
function merge(target, source) {
|
|
27
|
+
Object.keys(source).forEach(key => {
|
|
28
|
+
if (isObject(source[key])) {
|
|
29
|
+
if (!target[key]) {
|
|
30
|
+
target[key] = {};
|
|
31
|
+
}
|
|
32
|
+
merge(target[key], source[key]);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
target[key] = source[key];
|
|
36
|
+
});
|
|
37
|
+
return target;
|
|
38
|
+
}
|
|
26
39
|
|
|
27
40
|
const RULES = {};
|
|
28
41
|
/**
|
|
@@ -393,15 +406,6 @@
|
|
|
393
406
|
function warn(message) {
|
|
394
407
|
vue.warn(`[vee-validate]: ${message}`);
|
|
395
408
|
}
|
|
396
|
-
/**
|
|
397
|
-
* Ensures we deal with a singular field value
|
|
398
|
-
*/
|
|
399
|
-
function normalizeField(field) {
|
|
400
|
-
if (Array.isArray(field)) {
|
|
401
|
-
return field[0];
|
|
402
|
-
}
|
|
403
|
-
return field;
|
|
404
|
-
}
|
|
405
409
|
function resolveNextCheckboxValue(currentValue, checkedValue, uncheckedValue) {
|
|
406
410
|
if (Array.isArray(currentValue)) {
|
|
407
411
|
const newVal = [...currentValue];
|
|
@@ -482,6 +486,27 @@
|
|
|
482
486
|
function lazyToRef(value) {
|
|
483
487
|
return vue.computed(() => unravel(value));
|
|
484
488
|
}
|
|
489
|
+
function normalizeErrorItem(message) {
|
|
490
|
+
return Array.isArray(message) ? message : message ? [message] : [];
|
|
491
|
+
}
|
|
492
|
+
function resolveFieldOrPathState(path) {
|
|
493
|
+
const form = injectWithSelf(FormContextKey);
|
|
494
|
+
const state = path ? vue.computed(() => form === null || form === void 0 ? void 0 : form.getPathState(vue.unref(path))) : undefined;
|
|
495
|
+
const field = path ? undefined : vue.inject(FieldContextKey);
|
|
496
|
+
if (!field && !(state === null || state === void 0 ? void 0 : state.value)) {
|
|
497
|
+
warn(`field with name ${vue.unref(path)} was not found`);
|
|
498
|
+
}
|
|
499
|
+
return state || field;
|
|
500
|
+
}
|
|
501
|
+
function omit(obj, keys) {
|
|
502
|
+
const target = {};
|
|
503
|
+
for (const key in obj) {
|
|
504
|
+
if (!keys.includes(key)) {
|
|
505
|
+
target[key] = obj[key];
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return target;
|
|
509
|
+
}
|
|
485
510
|
|
|
486
511
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
487
512
|
const normalizeChildren = (tag, context, slotProps) => {
|
|
@@ -906,32 +931,64 @@
|
|
|
906
931
|
let ID_COUNTER = 0;
|
|
907
932
|
function useFieldState(path, init) {
|
|
908
933
|
const { value, initialValue, setInitialValue } = _useFieldValue(path, init.modelValue, init.form);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
934
|
+
if (!init.form) {
|
|
935
|
+
const { errors, setErrors } = createFieldErrors();
|
|
936
|
+
const id = ID_COUNTER >= Number.MAX_SAFE_INTEGER ? 0 : ++ID_COUNTER;
|
|
937
|
+
const meta = createFieldMeta(value, initialValue, errors);
|
|
938
|
+
function setState(state) {
|
|
939
|
+
var _a;
|
|
940
|
+
if ('value' in state) {
|
|
941
|
+
value.value = state.value;
|
|
942
|
+
}
|
|
943
|
+
if ('errors' in state) {
|
|
944
|
+
setErrors(state.errors);
|
|
945
|
+
}
|
|
946
|
+
if ('touched' in state) {
|
|
947
|
+
meta.touched = (_a = state.touched) !== null && _a !== void 0 ? _a : meta.touched;
|
|
948
|
+
}
|
|
949
|
+
if ('initialValue' in state) {
|
|
950
|
+
setInitialValue(state.initialValue);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
id,
|
|
955
|
+
path,
|
|
956
|
+
value,
|
|
957
|
+
initialValue,
|
|
958
|
+
meta,
|
|
959
|
+
errors,
|
|
960
|
+
setState,
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
const state = init.form.createPathState(path, {
|
|
964
|
+
bails: init.bails,
|
|
965
|
+
label: init.label,
|
|
966
|
+
type: init.type,
|
|
967
|
+
validate: init.validate,
|
|
968
|
+
});
|
|
969
|
+
const errors = vue.computed(() => state.errors);
|
|
912
970
|
function setState(state) {
|
|
913
|
-
var _a;
|
|
971
|
+
var _a, _b, _c;
|
|
914
972
|
if ('value' in state) {
|
|
915
973
|
value.value = state.value;
|
|
916
974
|
}
|
|
917
975
|
if ('errors' in state) {
|
|
918
|
-
|
|
976
|
+
(_a = init.form) === null || _a === void 0 ? void 0 : _a.setFieldError(vue.unref(path), state.errors);
|
|
919
977
|
}
|
|
920
978
|
if ('touched' in state) {
|
|
921
|
-
|
|
979
|
+
(_b = init.form) === null || _b === void 0 ? void 0 : _b.setFieldTouched(vue.unref(path), (_c = state.touched) !== null && _c !== void 0 ? _c : false);
|
|
922
980
|
}
|
|
923
981
|
if ('initialValue' in state) {
|
|
924
982
|
setInitialValue(state.initialValue);
|
|
925
983
|
}
|
|
926
984
|
}
|
|
927
985
|
return {
|
|
928
|
-
id,
|
|
986
|
+
id: Array.isArray(state.id) ? state.id[state.id.length - 1] : state.id,
|
|
929
987
|
path,
|
|
930
988
|
value,
|
|
931
|
-
initialValue,
|
|
932
|
-
meta,
|
|
933
989
|
errors,
|
|
934
|
-
|
|
990
|
+
meta: state,
|
|
991
|
+
initialValue,
|
|
935
992
|
setState,
|
|
936
993
|
};
|
|
937
994
|
}
|
|
@@ -944,7 +1001,7 @@
|
|
|
944
1001
|
if (!form) {
|
|
945
1002
|
return vue.unref(modelRef);
|
|
946
1003
|
}
|
|
947
|
-
return getFromPath(form.
|
|
1004
|
+
return getFromPath(form.initialValues.value, vue.unref(path), vue.unref(modelRef));
|
|
948
1005
|
}
|
|
949
1006
|
function setInitialValue(value) {
|
|
950
1007
|
if (!form) {
|
|
@@ -1002,7 +1059,7 @@
|
|
|
1002
1059
|
/**
|
|
1003
1060
|
* Creates meta flags state and some associated effects with them
|
|
1004
1061
|
*/
|
|
1005
|
-
function
|
|
1062
|
+
function createFieldMeta(currentValue, initialValue, errors) {
|
|
1006
1063
|
const meta = vue.reactive({
|
|
1007
1064
|
touched: false,
|
|
1008
1065
|
pending: false,
|
|
@@ -1024,29 +1081,12 @@
|
|
|
1024
1081
|
/**
|
|
1025
1082
|
* Creates the error message state for the field state
|
|
1026
1083
|
*/
|
|
1027
|
-
function
|
|
1028
|
-
|
|
1029
|
-
if (!messages) {
|
|
1030
|
-
return [];
|
|
1031
|
-
}
|
|
1032
|
-
return Array.isArray(messages) ? messages : [messages];
|
|
1033
|
-
}
|
|
1034
|
-
if (!form) {
|
|
1035
|
-
const errors = vue.ref([]);
|
|
1036
|
-
return {
|
|
1037
|
-
errors,
|
|
1038
|
-
errorMessage: vue.computed(() => errors.value[0]),
|
|
1039
|
-
setErrors: (messages) => {
|
|
1040
|
-
errors.value = normalizeErrors(messages);
|
|
1041
|
-
},
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
const errors = vue.computed(() => form.errorBag.value[vue.unref(path)] || []);
|
|
1084
|
+
function createFieldErrors() {
|
|
1085
|
+
const errors = vue.ref([]);
|
|
1045
1086
|
return {
|
|
1046
1087
|
errors,
|
|
1047
|
-
errorMessage: vue.computed(() => errors.value[0]),
|
|
1048
1088
|
setErrors: (messages) => {
|
|
1049
|
-
|
|
1089
|
+
errors.value = normalizeErrorItem(messages);
|
|
1050
1090
|
},
|
|
1051
1091
|
};
|
|
1052
1092
|
}
|
|
@@ -1056,7 +1096,7 @@
|
|
|
1056
1096
|
*/
|
|
1057
1097
|
function useField(path, rules, opts) {
|
|
1058
1098
|
if (hasCheckedAttr(opts === null || opts === void 0 ? void 0 : opts.type)) {
|
|
1059
|
-
return
|
|
1099
|
+
return useFieldWithChecked(path, rules, opts);
|
|
1060
1100
|
}
|
|
1061
1101
|
return _useField(path, rules, opts);
|
|
1062
1102
|
}
|
|
@@ -1065,12 +1105,30 @@
|
|
|
1065
1105
|
const injectedForm = controlled ? injectWithSelf(FormContextKey) : undefined;
|
|
1066
1106
|
const form = controlForm || injectedForm;
|
|
1067
1107
|
const name = lazyToRef(path);
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1108
|
+
let PENDING_UNMOUNT = false;
|
|
1109
|
+
const validator = vue.computed(() => {
|
|
1110
|
+
const schema = vue.unref(form === null || form === void 0 ? void 0 : form.schema);
|
|
1111
|
+
if (schema) {
|
|
1112
|
+
return undefined;
|
|
1113
|
+
}
|
|
1114
|
+
const rulesValue = vue.unref(rules);
|
|
1115
|
+
if (isYupValidator(rulesValue) ||
|
|
1116
|
+
isTypedSchema(rulesValue) ||
|
|
1117
|
+
isCallable(rulesValue) ||
|
|
1118
|
+
Array.isArray(rulesValue)) {
|
|
1119
|
+
return rulesValue;
|
|
1120
|
+
}
|
|
1121
|
+
return normalizeRules(rulesValue);
|
|
1122
|
+
});
|
|
1123
|
+
const { id, value, initialValue, meta, setState, errors } = useFieldState(name, {
|
|
1071
1124
|
modelValue,
|
|
1072
1125
|
form,
|
|
1126
|
+
bails,
|
|
1127
|
+
label,
|
|
1128
|
+
type,
|
|
1129
|
+
validate: validator.value ? validate$1 : undefined,
|
|
1073
1130
|
});
|
|
1131
|
+
const errorMessage = vue.computed(() => errors.value[0]);
|
|
1074
1132
|
if (syncVModel) {
|
|
1075
1133
|
useVModel({ value, prop: modelPropName, handleChange });
|
|
1076
1134
|
}
|
|
@@ -1080,51 +1138,37 @@
|
|
|
1080
1138
|
const handleBlur = () => {
|
|
1081
1139
|
meta.touched = true;
|
|
1082
1140
|
};
|
|
1083
|
-
const normalizedRules = vue.computed(() => {
|
|
1084
|
-
let rulesValue = vue.unref(rules);
|
|
1085
|
-
const schema = vue.unref(form === null || form === void 0 ? void 0 : form.schema);
|
|
1086
|
-
if (schema && !isYupValidator(schema) && !isTypedSchema(schema)) {
|
|
1087
|
-
rulesValue = extractRuleFromSchema(schema, vue.unref(name)) || rulesValue;
|
|
1088
|
-
}
|
|
1089
|
-
if (isYupValidator(rulesValue) ||
|
|
1090
|
-
isTypedSchema(rulesValue) ||
|
|
1091
|
-
isCallable(rulesValue) ||
|
|
1092
|
-
Array.isArray(rulesValue)) {
|
|
1093
|
-
return rulesValue;
|
|
1094
|
-
}
|
|
1095
|
-
return normalizeRules(rulesValue);
|
|
1096
|
-
});
|
|
1097
1141
|
async function validateCurrentValue(mode) {
|
|
1098
1142
|
var _a, _b;
|
|
1099
1143
|
if (form === null || form === void 0 ? void 0 : form.validateSchema) {
|
|
1100
1144
|
return (_a = (await form.validateSchema(mode)).results[vue.unref(name)]) !== null && _a !== void 0 ? _a : { valid: true, errors: [] };
|
|
1101
1145
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1146
|
+
if (validator.value) {
|
|
1147
|
+
return validate(value.value, validator.value, {
|
|
1148
|
+
name: vue.unref(name),
|
|
1149
|
+
label: vue.unref(label),
|
|
1150
|
+
values: (_b = form === null || form === void 0 ? void 0 : form.values) !== null && _b !== void 0 ? _b : {},
|
|
1151
|
+
bails,
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
return { valid: true, errors: [] };
|
|
1108
1155
|
}
|
|
1109
1156
|
const validateWithStateMutation = withLatest(async () => {
|
|
1110
1157
|
meta.pending = true;
|
|
1111
1158
|
meta.validated = true;
|
|
1112
1159
|
return validateCurrentValue('validated-only');
|
|
1113
1160
|
}, result => {
|
|
1114
|
-
if (
|
|
1115
|
-
|
|
1116
|
-
result.errors = [];
|
|
1161
|
+
if (PENDING_UNMOUNT) {
|
|
1162
|
+
return;
|
|
1117
1163
|
}
|
|
1118
1164
|
setState({ errors: result.errors });
|
|
1119
1165
|
meta.pending = false;
|
|
1166
|
+
meta.valid = result.valid;
|
|
1120
1167
|
return result;
|
|
1121
1168
|
});
|
|
1122
1169
|
const validateValidStateOnly = withLatest(async () => {
|
|
1123
1170
|
return validateCurrentValue('silent');
|
|
1124
1171
|
}, result => {
|
|
1125
|
-
if (markedForRemoval) {
|
|
1126
|
-
result.valid = true;
|
|
1127
|
-
}
|
|
1128
1172
|
meta.valid = result.valid;
|
|
1129
1173
|
return result;
|
|
1130
1174
|
});
|
|
@@ -1137,7 +1181,7 @@
|
|
|
1137
1181
|
// Common input/change event handler
|
|
1138
1182
|
function handleChange(e, shouldValidate = true) {
|
|
1139
1183
|
const newValue = normalizeEventValue(e);
|
|
1140
|
-
|
|
1184
|
+
setValue(newValue, false);
|
|
1141
1185
|
if (!validateOnValueUpdate && shouldValidate) {
|
|
1142
1186
|
validateWithStateMutation();
|
|
1143
1187
|
}
|
|
@@ -1156,24 +1200,8 @@
|
|
|
1156
1200
|
function setTouched(isTouched) {
|
|
1157
1201
|
meta.touched = isTouched;
|
|
1158
1202
|
}
|
|
1159
|
-
let unwatchValue;
|
|
1160
|
-
let lastWatchedValue = klona(value.value);
|
|
1161
|
-
function watchValue() {
|
|
1162
|
-
unwatchValue = vue.watch(value, (val, oldVal) => {
|
|
1163
|
-
if (isEqual(val, oldVal) && isEqual(val, lastWatchedValue)) {
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
const validateFn = validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly;
|
|
1167
|
-
validateFn();
|
|
1168
|
-
lastWatchedValue = klona(val);
|
|
1169
|
-
}, {
|
|
1170
|
-
deep: true,
|
|
1171
|
-
});
|
|
1172
|
-
}
|
|
1173
|
-
watchValue();
|
|
1174
1203
|
function resetField(state) {
|
|
1175
1204
|
var _a;
|
|
1176
|
-
unwatchValue === null || unwatchValue === void 0 ? void 0 : unwatchValue();
|
|
1177
1205
|
const newValue = state && 'value' in state ? state.value : initialValue.value;
|
|
1178
1206
|
setState({
|
|
1179
1207
|
value: klona(newValue),
|
|
@@ -1184,22 +1212,31 @@
|
|
|
1184
1212
|
meta.pending = false;
|
|
1185
1213
|
meta.validated = false;
|
|
1186
1214
|
validateValidStateOnly();
|
|
1187
|
-
// need to watch at next tick to avoid triggering the value watcher
|
|
1188
|
-
vue.nextTick(() => {
|
|
1189
|
-
watchValue();
|
|
1190
|
-
});
|
|
1191
1215
|
}
|
|
1192
|
-
function setValue(newValue) {
|
|
1216
|
+
function setValue(newValue, validate = true) {
|
|
1193
1217
|
value.value = newValue;
|
|
1218
|
+
if (!validate) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const validateFn = validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly;
|
|
1222
|
+
validateFn();
|
|
1194
1223
|
}
|
|
1195
1224
|
function setErrors(errors) {
|
|
1196
1225
|
setState({ errors: Array.isArray(errors) ? errors : [errors] });
|
|
1197
1226
|
}
|
|
1227
|
+
const valueProxy = vue.computed({
|
|
1228
|
+
get() {
|
|
1229
|
+
return value.value;
|
|
1230
|
+
},
|
|
1231
|
+
set(newValue) {
|
|
1232
|
+
setValue(newValue, validateOnValueUpdate);
|
|
1233
|
+
},
|
|
1234
|
+
});
|
|
1198
1235
|
const field = {
|
|
1199
1236
|
id,
|
|
1200
1237
|
name,
|
|
1201
1238
|
label,
|
|
1202
|
-
value,
|
|
1239
|
+
value: valueProxy,
|
|
1203
1240
|
meta,
|
|
1204
1241
|
errors,
|
|
1205
1242
|
errorMessage,
|
|
@@ -1234,14 +1271,9 @@
|
|
|
1234
1271
|
return field;
|
|
1235
1272
|
}
|
|
1236
1273
|
// associate the field with the given form
|
|
1237
|
-
form.register(field);
|
|
1238
|
-
vue.onBeforeUnmount(() => {
|
|
1239
|
-
markedForRemoval = true;
|
|
1240
|
-
form.unregister(field);
|
|
1241
|
-
});
|
|
1242
1274
|
// extract cross-field dependencies in a computed prop
|
|
1243
1275
|
const dependencies = vue.computed(() => {
|
|
1244
|
-
const rulesVal =
|
|
1276
|
+
const rulesVal = validator.value;
|
|
1245
1277
|
// is falsy, a function schema or a yup schema
|
|
1246
1278
|
if (!rulesVal ||
|
|
1247
1279
|
isCallable(rulesVal) ||
|
|
@@ -1275,6 +1307,37 @@
|
|
|
1275
1307
|
meta.validated ? validateWithStateMutation() : validateValidStateOnly();
|
|
1276
1308
|
}
|
|
1277
1309
|
});
|
|
1310
|
+
vue.onBeforeUnmount(() => {
|
|
1311
|
+
var _a;
|
|
1312
|
+
PENDING_UNMOUNT = true;
|
|
1313
|
+
const shouldKeepValue = (_a = vue.unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : vue.unref(form.keepValuesOnUnmount);
|
|
1314
|
+
if (shouldKeepValue || !form) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
const path = unravel(name);
|
|
1318
|
+
const pathState = form.getPathState(path);
|
|
1319
|
+
const matchesId = Array.isArray(pathState === null || pathState === void 0 ? void 0 : pathState.id) && (pathState === null || pathState === void 0 ? void 0 : pathState.multiple)
|
|
1320
|
+
? pathState === null || pathState === void 0 ? void 0 : pathState.id.includes(field.id)
|
|
1321
|
+
: (pathState === null || pathState === void 0 ? void 0 : pathState.id) === field.id;
|
|
1322
|
+
if (!matchesId) {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if ((pathState === null || pathState === void 0 ? void 0 : pathState.multiple) && Array.isArray(pathState.value)) {
|
|
1326
|
+
const valueIdx = pathState.value.findIndex(i => isEqual(i, vue.unref(field.checkedValue)));
|
|
1327
|
+
if (valueIdx > -1) {
|
|
1328
|
+
const newVal = [...pathState.value];
|
|
1329
|
+
newVal.splice(valueIdx, 1);
|
|
1330
|
+
form.setFieldValue(path, newVal);
|
|
1331
|
+
}
|
|
1332
|
+
if (Array.isArray(pathState.id)) {
|
|
1333
|
+
pathState.id.splice(pathState.id.indexOf(field.id), 1);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
form.unsetPathValue(path);
|
|
1338
|
+
}
|
|
1339
|
+
form.removePathState(path);
|
|
1340
|
+
});
|
|
1278
1341
|
return field;
|
|
1279
1342
|
}
|
|
1280
1343
|
/**
|
|
@@ -1305,22 +1368,11 @@
|
|
|
1305
1368
|
const controlled = 'standalone' in opts ? !opts.standalone : opts.controlled;
|
|
1306
1369
|
return Object.assign(Object.assign(Object.assign({}, defaults()), (opts || {})), { initialValue, controlled: controlled !== null && controlled !== void 0 ? controlled : true, checkedValue });
|
|
1307
1370
|
}
|
|
1308
|
-
|
|
1309
|
-
* Extracts the validation rules from a schema
|
|
1310
|
-
*/
|
|
1311
|
-
function extractRuleFromSchema(schema, fieldName) {
|
|
1312
|
-
// no schema at all
|
|
1313
|
-
if (!schema) {
|
|
1314
|
-
return undefined;
|
|
1315
|
-
}
|
|
1316
|
-
// there is a key on the schema object for this field
|
|
1317
|
-
return schema[fieldName];
|
|
1318
|
-
}
|
|
1319
|
-
function useCheckboxField(name, rules, opts) {
|
|
1371
|
+
function useFieldWithChecked(name, rules, opts) {
|
|
1320
1372
|
const form = !(opts === null || opts === void 0 ? void 0 : opts.standalone) ? injectWithSelf(FormContextKey) : undefined;
|
|
1321
1373
|
const checkedValue = opts === null || opts === void 0 ? void 0 : opts.checkedValue;
|
|
1322
1374
|
const uncheckedValue = opts === null || opts === void 0 ? void 0 : opts.uncheckedValue;
|
|
1323
|
-
function
|
|
1375
|
+
function patchCheckedApi(field) {
|
|
1324
1376
|
const handleChange = field.handleChange;
|
|
1325
1377
|
const checked = vue.computed(() => {
|
|
1326
1378
|
const currentValue = vue.unref(field.value);
|
|
@@ -1337,9 +1389,15 @@
|
|
|
1337
1389
|
}
|
|
1338
1390
|
return;
|
|
1339
1391
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1392
|
+
const path = unravel(name);
|
|
1393
|
+
const pathState = form === null || form === void 0 ? void 0 : form.getPathState(path);
|
|
1394
|
+
const value = normalizeEventValue(e);
|
|
1395
|
+
let newValue;
|
|
1396
|
+
if (form && (pathState === null || pathState === void 0 ? void 0 : pathState.multiple) && pathState.type === 'checkbox') {
|
|
1397
|
+
newValue = resolveNextCheckboxValue(getFromPath(form.values, path) || [], value, undefined);
|
|
1398
|
+
}
|
|
1399
|
+
else {
|
|
1400
|
+
// Single checkbox field without a form to toggle it's value
|
|
1343
1401
|
newValue = resolveNextCheckboxValue(vue.unref(field.value), vue.unref(checkedValue), vue.unref(uncheckedValue));
|
|
1344
1402
|
}
|
|
1345
1403
|
handleChange(newValue, shouldValidate);
|
|
@@ -1348,7 +1406,7 @@
|
|
|
1348
1406
|
checkedValue,
|
|
1349
1407
|
uncheckedValue, handleChange: handleCheckboxChange });
|
|
1350
1408
|
}
|
|
1351
|
-
return
|
|
1409
|
+
return patchCheckedApi(_useField(name, rules, opts));
|
|
1352
1410
|
}
|
|
1353
1411
|
function useVModel({ prop, value, handleChange }) {
|
|
1354
1412
|
const vm = vue.getCurrentInstance();
|
|
@@ -1571,6 +1629,7 @@
|
|
|
1571
1629
|
const Field = FieldImpl;
|
|
1572
1630
|
|
|
1573
1631
|
let FORM_COUNTER = 0;
|
|
1632
|
+
const PRIVATE_PATH_STATE_KEYS = ['bails', 'fieldsCount', 'id', 'multiple', 'type', 'validate'];
|
|
1574
1633
|
function resolveInitialValues(opts) {
|
|
1575
1634
|
const providedValues = vue.unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {};
|
|
1576
1635
|
const schema = vue.unref(opts === null || opts === void 0 ? void 0 : opts.validationSchema);
|
|
@@ -1582,12 +1641,8 @@
|
|
|
1582
1641
|
function useForm(opts) {
|
|
1583
1642
|
var _a;
|
|
1584
1643
|
const formId = FORM_COUNTER++;
|
|
1585
|
-
const controlledModelPaths = new Set();
|
|
1586
1644
|
// Prevents fields from double resetting their values, which causes checkboxes to toggle their initial value
|
|
1587
|
-
|
|
1588
|
-
let RESET_LOCK = false;
|
|
1589
|
-
// A lookup containing fields or field groups
|
|
1590
|
-
const fieldsByPath = vue.ref({});
|
|
1645
|
+
let FIELD_ID_COUNTER = 0;
|
|
1591
1646
|
// If the form is currently submitting
|
|
1592
1647
|
const isSubmitting = vue.ref(false);
|
|
1593
1648
|
// The number of times the user tried to submit the form
|
|
@@ -1596,44 +1651,62 @@
|
|
|
1596
1651
|
const fieldArrays = [];
|
|
1597
1652
|
// a private ref for all form values
|
|
1598
1653
|
const formValues = vue.reactive(resolveInitialValues(opts));
|
|
1599
|
-
|
|
1600
|
-
const
|
|
1654
|
+
const pathStates = vue.ref([]);
|
|
1655
|
+
const extraErrorsBag = vue.ref({});
|
|
1656
|
+
/**
|
|
1657
|
+
* Manually sets an error message on a specific field
|
|
1658
|
+
*/
|
|
1659
|
+
function setFieldError(field, message) {
|
|
1660
|
+
const state = findPathState(field);
|
|
1661
|
+
if (!state) {
|
|
1662
|
+
extraErrorsBag.value[field] = normalizeErrorItem(message);
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
state.errors = normalizeErrorItem(message);
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Sets errors for the fields specified in the object
|
|
1669
|
+
*/
|
|
1670
|
+
function setErrors(paths) {
|
|
1671
|
+
keysOf(paths).forEach(path => {
|
|
1672
|
+
setFieldError(path, paths[path]);
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
if (opts === null || opts === void 0 ? void 0 : opts.initialErrors) {
|
|
1676
|
+
setErrors(opts.initialErrors);
|
|
1677
|
+
}
|
|
1678
|
+
const errorBag = vue.computed(() => {
|
|
1679
|
+
const pathErrors = pathStates.value.reduce((acc, state) => {
|
|
1680
|
+
if (state.errors.length) {
|
|
1681
|
+
acc[state.path] = state.errors;
|
|
1682
|
+
}
|
|
1683
|
+
return acc;
|
|
1684
|
+
}, {});
|
|
1685
|
+
return Object.assign(Object.assign({}, extraErrorsBag.value), pathErrors);
|
|
1686
|
+
});
|
|
1601
1687
|
// Gets the first error of each field
|
|
1602
1688
|
const errors = vue.computed(() => {
|
|
1603
1689
|
return keysOf(errorBag.value).reduce((acc, key) => {
|
|
1604
|
-
const
|
|
1605
|
-
if (
|
|
1606
|
-
acc[key] =
|
|
1690
|
+
const errors = errorBag.value[key];
|
|
1691
|
+
if (errors === null || errors === void 0 ? void 0 : errors.length) {
|
|
1692
|
+
acc[key] = errors[0];
|
|
1607
1693
|
}
|
|
1608
1694
|
return acc;
|
|
1609
1695
|
}, {});
|
|
1610
1696
|
});
|
|
1611
|
-
function getFirstFieldAtPath(path) {
|
|
1612
|
-
const fieldOrGroup = fieldsByPath.value[path];
|
|
1613
|
-
return Array.isArray(fieldOrGroup) ? fieldOrGroup[0] : fieldOrGroup;
|
|
1614
|
-
}
|
|
1615
|
-
function fieldExists(path) {
|
|
1616
|
-
return !!fieldsByPath.value[path];
|
|
1617
|
-
}
|
|
1618
1697
|
/**
|
|
1619
1698
|
* Holds a computed reference to all fields names and labels
|
|
1620
1699
|
*/
|
|
1621
1700
|
const fieldNames = vue.computed(() => {
|
|
1622
|
-
return
|
|
1623
|
-
|
|
1624
|
-
if (field) {
|
|
1625
|
-
names[path] = { name: vue.unref(field.name) || '', label: vue.unref(field.label) || '' };
|
|
1626
|
-
}
|
|
1701
|
+
return pathStates.value.reduce((names, state) => {
|
|
1702
|
+
names[state.path] = { name: state.path || '', label: state.label || '' };
|
|
1627
1703
|
return names;
|
|
1628
1704
|
}, {});
|
|
1629
1705
|
});
|
|
1630
1706
|
const fieldBailsMap = vue.computed(() => {
|
|
1631
|
-
return
|
|
1707
|
+
return pathStates.value.reduce((map, state) => {
|
|
1632
1708
|
var _a;
|
|
1633
|
-
|
|
1634
|
-
if (field) {
|
|
1635
|
-
map[path] = (_a = field.bails) !== null && _a !== void 0 ? _a : true;
|
|
1636
|
-
}
|
|
1709
|
+
map[state.path] = (_a = state.bails) !== null && _a !== void 0 ? _a : true;
|
|
1637
1710
|
return map;
|
|
1638
1711
|
}, {});
|
|
1639
1712
|
});
|
|
@@ -1642,17 +1715,74 @@
|
|
|
1642
1715
|
const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
|
|
1643
1716
|
const keepValuesOnUnmount = (_a = opts === null || opts === void 0 ? void 0 : opts.keepValuesOnUnmount) !== null && _a !== void 0 ? _a : false;
|
|
1644
1717
|
// initial form values
|
|
1645
|
-
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(
|
|
1718
|
+
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(pathStates, formValues, opts);
|
|
1646
1719
|
// form meta aggregations
|
|
1647
|
-
const meta = useFormMeta(
|
|
1720
|
+
const meta = useFormMeta(pathStates, formValues, originalInitialValues, errors);
|
|
1648
1721
|
const controlledValues = vue.computed(() => {
|
|
1649
|
-
return
|
|
1650
|
-
const value = getFromPath(formValues, path);
|
|
1651
|
-
setInPath(acc, path, value);
|
|
1722
|
+
return pathStates.value.reduce((acc, state) => {
|
|
1723
|
+
const value = getFromPath(formValues, state.path);
|
|
1724
|
+
setInPath(acc, state.path, value);
|
|
1652
1725
|
return acc;
|
|
1653
1726
|
}, {});
|
|
1654
1727
|
});
|
|
1655
1728
|
const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
|
|
1729
|
+
function createPathState(path, config) {
|
|
1730
|
+
var _a, _b;
|
|
1731
|
+
const initialValue = vue.computed(() => getFromPath(initialValues.value, unravel(path)));
|
|
1732
|
+
const pathStateExists = pathStates.value.find(state => state.path === vue.unref(path));
|
|
1733
|
+
if (pathStateExists) {
|
|
1734
|
+
if ((config === null || config === void 0 ? void 0 : config.type) === 'checkbox' || (config === null || config === void 0 ? void 0 : config.type) === 'radio') {
|
|
1735
|
+
pathStateExists.multiple = true;
|
|
1736
|
+
}
|
|
1737
|
+
if (Array.isArray(pathStateExists.id)) {
|
|
1738
|
+
pathStateExists.id.push(FIELD_ID_COUNTER++);
|
|
1739
|
+
}
|
|
1740
|
+
else {
|
|
1741
|
+
pathStateExists.id = [pathStateExists.id, FIELD_ID_COUNTER++];
|
|
1742
|
+
}
|
|
1743
|
+
pathStateExists.fieldsCount++;
|
|
1744
|
+
return pathStateExists;
|
|
1745
|
+
}
|
|
1746
|
+
const currentValue = vue.computed(() => getFromPath(formValues, unravel(path)));
|
|
1747
|
+
const pathValue = unravel(path);
|
|
1748
|
+
const state = vue.reactive({
|
|
1749
|
+
id: FIELD_ID_COUNTER++,
|
|
1750
|
+
path,
|
|
1751
|
+
touched: false,
|
|
1752
|
+
pending: false,
|
|
1753
|
+
valid: true,
|
|
1754
|
+
validated: !!((_a = initialErrors[pathValue]) === null || _a === void 0 ? void 0 : _a.length),
|
|
1755
|
+
initialValue,
|
|
1756
|
+
errors: vue.shallowRef([]),
|
|
1757
|
+
bails: (_b = config === null || config === void 0 ? void 0 : config.bails) !== null && _b !== void 0 ? _b : false,
|
|
1758
|
+
label: config === null || config === void 0 ? void 0 : config.label,
|
|
1759
|
+
type: (config === null || config === void 0 ? void 0 : config.type) || 'default',
|
|
1760
|
+
value: currentValue,
|
|
1761
|
+
multiple: false,
|
|
1762
|
+
fieldsCount: 1,
|
|
1763
|
+
validate: config === null || config === void 0 ? void 0 : config.validate,
|
|
1764
|
+
dirty: vue.computed(() => {
|
|
1765
|
+
return !isEqual(vue.unref(currentValue), vue.unref(initialValue));
|
|
1766
|
+
}),
|
|
1767
|
+
});
|
|
1768
|
+
pathStates.value.push(state);
|
|
1769
|
+
// if it has errors before, validate it.
|
|
1770
|
+
if (errors.value[pathValue] && !initialErrors[pathValue]) {
|
|
1771
|
+
vue.nextTick(() => {
|
|
1772
|
+
validateField(pathValue);
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
// Handles when a path changes
|
|
1776
|
+
if (vue.isRef(path)) {
|
|
1777
|
+
vue.watch(path, newPath => {
|
|
1778
|
+
const nextValue = klona(currentValue.value);
|
|
1779
|
+
vue.nextTick(() => {
|
|
1780
|
+
setInPath(formValues, newPath, nextValue);
|
|
1781
|
+
});
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
return state;
|
|
1785
|
+
}
|
|
1656
1786
|
/**
|
|
1657
1787
|
* Batches validation runs in 5ms batches
|
|
1658
1788
|
* Must have two distinct batch queues to make sure they don't override each other settings #3783
|
|
@@ -1663,17 +1793,17 @@
|
|
|
1663
1793
|
return (await mode) === 'silent' ? debouncedSilentValidation() : debouncedValidation();
|
|
1664
1794
|
}, (formResult, [mode]) => {
|
|
1665
1795
|
// fields by id lookup
|
|
1666
|
-
const fieldsById = formCtx.fieldsByPath.value || {};
|
|
1667
1796
|
// errors fields names, we need it to also check if custom errors are updated
|
|
1668
1797
|
const currentErrorsPaths = keysOf(formCtx.errorBag.value);
|
|
1669
1798
|
// collect all the keys from the schema and all fields
|
|
1670
|
-
// this ensures we have a complete
|
|
1799
|
+
// this ensures we have a complete key map of all the fields
|
|
1671
1800
|
const paths = [
|
|
1672
|
-
...new Set([...keysOf(formResult.results), ...
|
|
1801
|
+
...new Set([...keysOf(formResult.results), ...pathStates.value.map(p => p.path), ...currentErrorsPaths]),
|
|
1673
1802
|
];
|
|
1674
1803
|
// aggregates the paths into a single result object while applying the results on the fields
|
|
1675
|
-
return paths.reduce((validation,
|
|
1676
|
-
const
|
|
1804
|
+
return paths.reduce((validation, _path) => {
|
|
1805
|
+
const path = _path;
|
|
1806
|
+
const pathState = findPathState(path);
|
|
1677
1807
|
const messages = (formResult.results[path] || { errors: [] }).errors;
|
|
1678
1808
|
const fieldResult = {
|
|
1679
1809
|
errors: messages,
|
|
@@ -1683,24 +1813,37 @@
|
|
|
1683
1813
|
if (!fieldResult.valid) {
|
|
1684
1814
|
validation.errors[path] = fieldResult.errors[0];
|
|
1685
1815
|
}
|
|
1816
|
+
// clean up extra errors if path state exists
|
|
1817
|
+
if (pathState && extraErrorsBag.value[path]) {
|
|
1818
|
+
delete extraErrorsBag.value[path];
|
|
1819
|
+
}
|
|
1686
1820
|
// field not rendered
|
|
1687
|
-
if (!
|
|
1821
|
+
if (!pathState) {
|
|
1688
1822
|
setFieldError(path, messages);
|
|
1689
1823
|
return validation;
|
|
1690
1824
|
}
|
|
1691
1825
|
// always update the valid flag regardless of the mode
|
|
1692
|
-
|
|
1826
|
+
pathState.valid = fieldResult.valid;
|
|
1693
1827
|
if (mode === 'silent') {
|
|
1694
1828
|
return validation;
|
|
1695
1829
|
}
|
|
1696
|
-
|
|
1697
|
-
if (mode === 'validated-only' && !wasValidated) {
|
|
1830
|
+
if (mode === 'validated-only' && !pathState.validated) {
|
|
1698
1831
|
return validation;
|
|
1699
1832
|
}
|
|
1700
|
-
|
|
1833
|
+
setFieldError(pathState, fieldResult.errors);
|
|
1701
1834
|
return validation;
|
|
1702
1835
|
}, { valid: formResult.valid, results: {}, errors: {} });
|
|
1703
1836
|
});
|
|
1837
|
+
function mutateAllPathState(mutation) {
|
|
1838
|
+
pathStates.value.forEach(mutation);
|
|
1839
|
+
}
|
|
1840
|
+
function findPathState(path) {
|
|
1841
|
+
const pathState = typeof path === 'string' ? pathStates.value.find(state => state.path === path) : path;
|
|
1842
|
+
return pathState;
|
|
1843
|
+
}
|
|
1844
|
+
function unsetPathValue(path) {
|
|
1845
|
+
unsetPath(formValues, path);
|
|
1846
|
+
}
|
|
1704
1847
|
function makeSubmissionFactory(onlyControlled) {
|
|
1705
1848
|
return function submitHandlerFactory(fn, onValidationError) {
|
|
1706
1849
|
return function submissionHandler(e) {
|
|
@@ -1709,10 +1852,7 @@
|
|
|
1709
1852
|
e.stopPropagation();
|
|
1710
1853
|
}
|
|
1711
1854
|
// Touch all fields
|
|
1712
|
-
|
|
1713
|
-
acc[field] = true;
|
|
1714
|
-
return acc;
|
|
1715
|
-
}, {}));
|
|
1855
|
+
mutateAllPathState(s => (s.touched = true));
|
|
1716
1856
|
isSubmitting.value = true;
|
|
1717
1857
|
submitCount.value++;
|
|
1718
1858
|
return validate()
|
|
@@ -1720,7 +1860,7 @@
|
|
|
1720
1860
|
const values = klona(formValues);
|
|
1721
1861
|
if (result.valid && typeof fn === 'function') {
|
|
1722
1862
|
const controlled = klona(controlledValues.value);
|
|
1723
|
-
let submittedValues = onlyControlled ? controlled : values;
|
|
1863
|
+
let submittedValues = (onlyControlled ? controlled : values);
|
|
1724
1864
|
if (result.values) {
|
|
1725
1865
|
submittedValues = result.values;
|
|
1726
1866
|
}
|
|
@@ -1760,9 +1900,22 @@
|
|
|
1760
1900
|
const handleSubmitImpl = makeSubmissionFactory(false);
|
|
1761
1901
|
const handleSubmit = handleSubmitImpl;
|
|
1762
1902
|
handleSubmit.withControlled = makeSubmissionFactory(true);
|
|
1903
|
+
function removePathState(path) {
|
|
1904
|
+
const idx = pathStates.value.findIndex(s => s.path === path);
|
|
1905
|
+
const pathState = pathStates.value[idx];
|
|
1906
|
+
if (idx === -1 || !pathState) {
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
if (pathState.multiple && pathState.fieldsCount) {
|
|
1910
|
+
pathState.fieldsCount--;
|
|
1911
|
+
}
|
|
1912
|
+
if (!pathState.multiple || pathState.fieldsCount <= 0) {
|
|
1913
|
+
pathStates.value.splice(idx, 1);
|
|
1914
|
+
unsetInitialValue(path);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1763
1917
|
const formCtx = {
|
|
1764
1918
|
formId,
|
|
1765
|
-
fieldsByPath,
|
|
1766
1919
|
values: formValues,
|
|
1767
1920
|
controlledValues,
|
|
1768
1921
|
errorBag,
|
|
@@ -1775,14 +1928,11 @@
|
|
|
1775
1928
|
keepValuesOnUnmount,
|
|
1776
1929
|
validateSchema: vue.unref(schema) ? validateSchema : undefined,
|
|
1777
1930
|
validate,
|
|
1778
|
-
|
|
1779
|
-
unregister: unregisterField,
|
|
1780
|
-
setFieldErrorBag,
|
|
1931
|
+
setFieldError,
|
|
1781
1932
|
validateField,
|
|
1782
1933
|
setFieldValue,
|
|
1783
1934
|
setValues,
|
|
1784
1935
|
setErrors,
|
|
1785
|
-
setFieldError,
|
|
1786
1936
|
setFieldTouched,
|
|
1787
1937
|
setTouched,
|
|
1788
1938
|
resetForm,
|
|
@@ -1792,102 +1942,63 @@
|
|
|
1792
1942
|
unsetInitialValue,
|
|
1793
1943
|
setFieldInitialValue,
|
|
1794
1944
|
useFieldModel,
|
|
1945
|
+
createPathState,
|
|
1946
|
+
getPathState: findPathState,
|
|
1947
|
+
unsetPathValue,
|
|
1948
|
+
removePathState,
|
|
1949
|
+
initialValues: initialValues,
|
|
1950
|
+
getAllPathStates: () => pathStates.value,
|
|
1795
1951
|
};
|
|
1796
|
-
function isFieldGroup(fieldOrGroup) {
|
|
1797
|
-
return Array.isArray(fieldOrGroup);
|
|
1798
|
-
}
|
|
1799
|
-
function applyFieldMutation(fieldOrGroup, mutation) {
|
|
1800
|
-
if (Array.isArray(fieldOrGroup)) {
|
|
1801
|
-
return fieldOrGroup.forEach(mutation);
|
|
1802
|
-
}
|
|
1803
|
-
return mutation(fieldOrGroup);
|
|
1804
|
-
}
|
|
1805
|
-
function mutateAllFields(mutation) {
|
|
1806
|
-
Object.values(fieldsByPath.value).forEach(field => {
|
|
1807
|
-
if (!field) {
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
// avoid resetting the field values, because they should've been reset already.
|
|
1811
|
-
applyFieldMutation(field, mutation);
|
|
1812
|
-
});
|
|
1813
|
-
}
|
|
1814
|
-
/**
|
|
1815
|
-
* Manually sets an error message on a specific field
|
|
1816
|
-
*/
|
|
1817
|
-
function setFieldError(field, message) {
|
|
1818
|
-
setFieldErrorBag(field, message);
|
|
1819
|
-
}
|
|
1820
|
-
/**
|
|
1821
|
-
* Sets errors for the fields specified in the object
|
|
1822
|
-
*/
|
|
1823
|
-
function setErrors(fields) {
|
|
1824
|
-
setErrorBag(fields);
|
|
1825
|
-
}
|
|
1826
1952
|
/**
|
|
1827
1953
|
* Sets a single field value
|
|
1828
1954
|
*/
|
|
1829
|
-
function setFieldValue(field, value
|
|
1830
|
-
var _a;
|
|
1831
|
-
const fieldInstance = fieldsByPath.value[field];
|
|
1955
|
+
function setFieldValue(field, value) {
|
|
1832
1956
|
const clonedValue = klona(value);
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1957
|
+
const path = typeof field === 'string' ? field : field.path;
|
|
1958
|
+
const pathState = findPathState(path);
|
|
1959
|
+
if (!pathState) {
|
|
1960
|
+
createPathState(path);
|
|
1837
1961
|
}
|
|
1838
|
-
|
|
1839
|
-
// Multiple checkboxes, and only one of them got updated
|
|
1840
|
-
const newValue = klona(resolveNextCheckboxValue(getFromPath(formValues, field) || [], value, undefined));
|
|
1841
|
-
setInPath(formValues, field, newValue);
|
|
1842
|
-
return;
|
|
1843
|
-
}
|
|
1844
|
-
let newValue = clonedValue;
|
|
1845
|
-
// Single Checkbox: toggles the field value unless the field is being reset then force it
|
|
1846
|
-
if (!isFieldGroup(fieldInstance) && fieldInstance.type === 'checkbox' && !force && !RESET_LOCK) {
|
|
1847
|
-
newValue = klona(resolveNextCheckboxValue(getFromPath(formValues, field), value, vue.unref(fieldInstance.uncheckedValue)));
|
|
1848
|
-
}
|
|
1849
|
-
setInPath(formValues, field, newValue);
|
|
1962
|
+
setInPath(formValues, path, clonedValue);
|
|
1850
1963
|
}
|
|
1851
1964
|
/**
|
|
1852
1965
|
* Sets multiple fields values
|
|
1853
1966
|
*/
|
|
1854
1967
|
function setValues(fields) {
|
|
1855
|
-
|
|
1856
|
-
keysOf(formValues).forEach(key => {
|
|
1857
|
-
delete formValues[key];
|
|
1858
|
-
});
|
|
1859
|
-
// set up new values
|
|
1860
|
-
keysOf(fields).forEach(path => {
|
|
1861
|
-
setFieldValue(path, fields[path]);
|
|
1862
|
-
});
|
|
1968
|
+
merge(formValues, fields);
|
|
1863
1969
|
// regenerate the arrays when the form values change
|
|
1864
1970
|
fieldArrays.forEach(f => f && f.reset());
|
|
1865
1971
|
}
|
|
1866
1972
|
function createModel(path) {
|
|
1867
|
-
const
|
|
1868
|
-
vue.
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1973
|
+
const pathState = findPathState(vue.unref(path)) || createPathState(path);
|
|
1974
|
+
return vue.computed({
|
|
1975
|
+
get() {
|
|
1976
|
+
return pathState.value;
|
|
1977
|
+
},
|
|
1978
|
+
set(value) {
|
|
1979
|
+
const pathValue = vue.unref(path);
|
|
1980
|
+
setFieldValue(pathValue, value);
|
|
1981
|
+
pathState.validated = true;
|
|
1982
|
+
pathState.pending = true;
|
|
1983
|
+
validateField(pathValue).then(() => {
|
|
1984
|
+
pathState.pending = false;
|
|
1985
|
+
});
|
|
1986
|
+
},
|
|
1874
1987
|
});
|
|
1875
|
-
controlledModelPaths.add(vue.unref(path));
|
|
1876
|
-
return value;
|
|
1877
1988
|
}
|
|
1878
|
-
function useFieldModel(
|
|
1879
|
-
if (!Array.isArray(
|
|
1880
|
-
return createModel(
|
|
1989
|
+
function useFieldModel(pathOrPaths) {
|
|
1990
|
+
if (!Array.isArray(pathOrPaths)) {
|
|
1991
|
+
return createModel(pathOrPaths);
|
|
1881
1992
|
}
|
|
1882
|
-
return
|
|
1993
|
+
return pathOrPaths.map(createModel);
|
|
1883
1994
|
}
|
|
1884
1995
|
/**
|
|
1885
1996
|
* Sets the touched meta state on a field
|
|
1886
1997
|
*/
|
|
1887
1998
|
function setFieldTouched(field, isTouched) {
|
|
1888
|
-
const
|
|
1889
|
-
if (
|
|
1890
|
-
|
|
1999
|
+
const pathState = findPathState(field);
|
|
2000
|
+
if (pathState) {
|
|
2001
|
+
pathState.touched = isTouched;
|
|
1891
2002
|
}
|
|
1892
2003
|
}
|
|
1893
2004
|
/**
|
|
@@ -1899,172 +2010,53 @@
|
|
|
1899
2010
|
});
|
|
1900
2011
|
}
|
|
1901
2012
|
function resetField(field, state) {
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2013
|
+
var _a;
|
|
2014
|
+
const newValue = state && 'value' in state ? state.value : getFromPath(initialValues.value, field);
|
|
2015
|
+
setFieldInitialValue(field, klona(newValue));
|
|
2016
|
+
setFieldValue(field, newValue);
|
|
2017
|
+
setFieldTouched(field, (_a = state === null || state === void 0 ? void 0 : state.touched) !== null && _a !== void 0 ? _a : false);
|
|
2018
|
+
setFieldError(field, (state === null || state === void 0 ? void 0 : state.errors) || []);
|
|
1906
2019
|
}
|
|
1907
2020
|
/**
|
|
1908
2021
|
* Resets all fields
|
|
1909
2022
|
*/
|
|
1910
|
-
function resetForm(
|
|
1911
|
-
|
|
1912
|
-
// Reset all field states first
|
|
1913
|
-
mutateAllFields(f => f.resetField());
|
|
1914
|
-
// reset values
|
|
1915
|
-
const newValues = (state === null || state === void 0 ? void 0 : state.values) ? state.values : originalInitialValues.value;
|
|
2023
|
+
function resetForm(resetState) {
|
|
2024
|
+
const newValues = (resetState === null || resetState === void 0 ? void 0 : resetState.values) ? resetState.values : originalInitialValues.value;
|
|
1916
2025
|
setInitialValues(newValues);
|
|
1917
2026
|
setValues(newValues);
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
RESET_LOCK = false;
|
|
2027
|
+
mutateAllPathState(state => {
|
|
2028
|
+
var _a;
|
|
2029
|
+
state.validated = false;
|
|
2030
|
+
state.touched = ((_a = resetState === null || resetState === void 0 ? void 0 : resetState.touched) === null || _a === void 0 ? void 0 : _a[state.path]) || false;
|
|
2031
|
+
setFieldValue(state.path, getFromPath(newValues, state.path));
|
|
2032
|
+
setFieldError(state.path, undefined);
|
|
1925
2033
|
});
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
const rawField = vue.markRaw(field);
|
|
1929
|
-
const fieldPath = path;
|
|
1930
|
-
// first field at that path
|
|
1931
|
-
if (!fieldsByPath.value[fieldPath]) {
|
|
1932
|
-
fieldsByPath.value[fieldPath] = rawField;
|
|
1933
|
-
return;
|
|
1934
|
-
}
|
|
1935
|
-
const fieldAtPath = fieldsByPath.value[fieldPath];
|
|
1936
|
-
if (fieldAtPath && !Array.isArray(fieldAtPath)) {
|
|
1937
|
-
fieldsByPath.value[fieldPath] = [fieldAtPath];
|
|
1938
|
-
}
|
|
1939
|
-
// add the new array to that path
|
|
1940
|
-
fieldsByPath.value[fieldPath] = [...fieldsByPath.value[fieldPath], rawField];
|
|
1941
|
-
}
|
|
1942
|
-
function removeFieldFromPath(field, path) {
|
|
1943
|
-
const fieldPath = path;
|
|
1944
|
-
const fieldAtPath = fieldsByPath.value[fieldPath];
|
|
1945
|
-
if (!fieldAtPath) {
|
|
1946
|
-
return;
|
|
1947
|
-
}
|
|
1948
|
-
// same field at path
|
|
1949
|
-
if (!isFieldGroup(fieldAtPath) && field.id === fieldAtPath.id) {
|
|
1950
|
-
delete fieldsByPath.value[fieldPath];
|
|
1951
|
-
return;
|
|
1952
|
-
}
|
|
1953
|
-
if (isFieldGroup(fieldAtPath)) {
|
|
1954
|
-
const idx = fieldAtPath.findIndex(f => f.id === field.id);
|
|
1955
|
-
if (idx === -1) {
|
|
1956
|
-
return;
|
|
1957
|
-
}
|
|
1958
|
-
fieldAtPath.splice(idx, 1);
|
|
1959
|
-
if (!fieldAtPath.length) {
|
|
1960
|
-
delete fieldsByPath.value[fieldPath];
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
function registerField(field) {
|
|
1965
|
-
const fieldPath = vue.unref(field.name);
|
|
1966
|
-
insertFieldAtPath(field, fieldPath);
|
|
1967
|
-
if (vue.isRef(field.name)) {
|
|
1968
|
-
// ensures when a field's name was already taken that it preserves its same value
|
|
1969
|
-
// necessary for fields generated by loops
|
|
1970
|
-
vue.watch(field.name, async (newPath, oldPath) => {
|
|
1971
|
-
// cache the value
|
|
1972
|
-
await vue.nextTick();
|
|
1973
|
-
removeFieldFromPath(field, oldPath);
|
|
1974
|
-
insertFieldAtPath(field, newPath);
|
|
1975
|
-
// re-validate if either path had errors before
|
|
1976
|
-
if (errors.value[oldPath] || errors.value[newPath]) {
|
|
1977
|
-
// clear up both paths errors
|
|
1978
|
-
setFieldError(oldPath, undefined);
|
|
1979
|
-
validateField(newPath);
|
|
1980
|
-
}
|
|
1981
|
-
// clean up the old path if no other field is sharing that name
|
|
1982
|
-
// #3325
|
|
1983
|
-
await vue.nextTick();
|
|
1984
|
-
if (!fieldExists(oldPath)) {
|
|
1985
|
-
unsetPath(formValues, oldPath);
|
|
1986
|
-
}
|
|
1987
|
-
});
|
|
1988
|
-
}
|
|
1989
|
-
// if field already had errors (initial errors) that's not user-set, validate it again to ensure state is correct
|
|
1990
|
-
// the difference being that `initialErrors` will contain the error message while other errors (pre-validated schema) won't have them as initial errors
|
|
1991
|
-
// #3342
|
|
1992
|
-
const initialErrorMessage = vue.unref(field.errorMessage);
|
|
1993
|
-
if (initialErrorMessage && (initialErrors === null || initialErrors === void 0 ? void 0 : initialErrors[fieldPath]) !== initialErrorMessage) {
|
|
1994
|
-
validateField(fieldPath);
|
|
1995
|
-
}
|
|
1996
|
-
// marks the initial error as "consumed" so it won't be matched later with same non-initial error
|
|
1997
|
-
delete initialErrors[fieldPath];
|
|
1998
|
-
}
|
|
1999
|
-
function unregisterField(field) {
|
|
2000
|
-
const fieldName = vue.unref(field.name);
|
|
2001
|
-
const fieldInstance = fieldsByPath.value[fieldName];
|
|
2002
|
-
const isGroup = !!fieldInstance && isFieldGroup(fieldInstance);
|
|
2003
|
-
removeFieldFromPath(field, fieldName);
|
|
2004
|
-
// clears a field error on unmounted
|
|
2005
|
-
// we wait till next tick to make sure if the field is completely removed and doesn't have any siblings like checkboxes
|
|
2034
|
+
setErrors((resetState === null || resetState === void 0 ? void 0 : resetState.errors) || {});
|
|
2035
|
+
submitCount.value = (resetState === null || resetState === void 0 ? void 0 : resetState.submitCount) || 0;
|
|
2006
2036
|
vue.nextTick(() => {
|
|
2007
|
-
|
|
2008
|
-
const shouldKeepValue = (_a = vue.unref(field.keepValueOnUnmount)) !== null && _a !== void 0 ? _a : vue.unref(keepValuesOnUnmount);
|
|
2009
|
-
const currentGroupValue = getFromPath(formValues, fieldName);
|
|
2010
|
-
// The boolean here is we check if the field still belongs to the same control group with that name
|
|
2011
|
-
// if another group claimed the name, we should avoid handling it since it is no longer the same group
|
|
2012
|
-
// this happens with `v-for` over some checkboxes and field arrays.
|
|
2013
|
-
// also if the group no longer exist we can assume this group was the last one that controlled it
|
|
2014
|
-
const isSameGroup = isGroup && (fieldInstance === fieldsByPath.value[fieldName] || !fieldsByPath.value[fieldName]);
|
|
2015
|
-
// group field that still has a dangling value, the field may exist or not after it was removed.
|
|
2016
|
-
// This used to be handled in the useField composable but the form has better context on when it should/not happen.
|
|
2017
|
-
// if it does belong to it that means the group still exists
|
|
2018
|
-
// #3844
|
|
2019
|
-
if (isSameGroup && !shouldKeepValue) {
|
|
2020
|
-
if (Array.isArray(currentGroupValue)) {
|
|
2021
|
-
const valueIdx = currentGroupValue.findIndex(i => isEqual(i, vue.unref(field.checkedValue)));
|
|
2022
|
-
if (valueIdx > -1) {
|
|
2023
|
-
const newVal = [...currentGroupValue];
|
|
2024
|
-
newVal.splice(valueIdx, 1);
|
|
2025
|
-
setFieldValue(fieldName, newVal, { force: true });
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
else if (currentGroupValue === vue.unref(field.checkedValue)) {
|
|
2029
|
-
// Remove field if it is a group but does not have an array value, like for radio inputs #3963
|
|
2030
|
-
unsetPath(formValues, fieldName);
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
// Field was removed entirely, we should unset its path
|
|
2034
|
-
// #3384
|
|
2035
|
-
if (!fieldExists(fieldName)) {
|
|
2036
|
-
setFieldError(fieldName, undefined);
|
|
2037
|
-
// Checks if the field was configured to be unset during unmount or not
|
|
2038
|
-
// Checks both the form-level config and field-level one
|
|
2039
|
-
// Field has the priority if it is set, otherwise it goes to the form settings
|
|
2040
|
-
if (shouldKeepValue) {
|
|
2041
|
-
return;
|
|
2042
|
-
}
|
|
2043
|
-
// Don't apply emptyContainer check unless the current group value is an array
|
|
2044
|
-
if (isGroup && Array.isArray(currentGroupValue) && !isEmptyContainer(currentGroupValue)) {
|
|
2045
|
-
return;
|
|
2046
|
-
}
|
|
2047
|
-
unsetPath(formValues, fieldName);
|
|
2048
|
-
}
|
|
2037
|
+
validate({ mode: 'silent' });
|
|
2049
2038
|
});
|
|
2050
2039
|
}
|
|
2051
2040
|
async function validate(opts) {
|
|
2052
2041
|
const mode = (opts === null || opts === void 0 ? void 0 : opts.mode) || 'force';
|
|
2053
2042
|
if (mode === 'force') {
|
|
2054
|
-
|
|
2043
|
+
mutateAllPathState(f => (f.validated = true));
|
|
2055
2044
|
}
|
|
2056
2045
|
if (formCtx.validateSchema) {
|
|
2057
2046
|
return formCtx.validateSchema(mode);
|
|
2058
2047
|
}
|
|
2059
2048
|
// No schema, each field is responsible to validate itself
|
|
2060
|
-
const validations = await Promise.all(
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2049
|
+
const validations = await Promise.all(pathStates.value.map(state => {
|
|
2050
|
+
if (!state.validate) {
|
|
2051
|
+
return Promise.resolve({
|
|
2052
|
+
key: state.path,
|
|
2053
|
+
valid: true,
|
|
2054
|
+
errors: [],
|
|
2055
|
+
});
|
|
2064
2056
|
}
|
|
2065
|
-
return
|
|
2057
|
+
return state.validate(opts).then((result) => {
|
|
2066
2058
|
return {
|
|
2067
|
-
key:
|
|
2059
|
+
key: state.path,
|
|
2068
2060
|
valid: result.valid,
|
|
2069
2061
|
errors: result.errors,
|
|
2070
2062
|
};
|
|
@@ -2087,16 +2079,22 @@
|
|
|
2087
2079
|
errors,
|
|
2088
2080
|
};
|
|
2089
2081
|
}
|
|
2090
|
-
async function validateField(
|
|
2091
|
-
const
|
|
2092
|
-
if (
|
|
2093
|
-
|
|
2094
|
-
|
|
2082
|
+
async function validateField(path) {
|
|
2083
|
+
const state = findPathState(path);
|
|
2084
|
+
if (state) {
|
|
2085
|
+
state.validated = true;
|
|
2086
|
+
}
|
|
2087
|
+
if (schema) {
|
|
2088
|
+
const { results } = await validateSchema('validated-only');
|
|
2089
|
+
return results[path] || { errors: [], valid: true };
|
|
2095
2090
|
}
|
|
2096
|
-
if (
|
|
2097
|
-
return
|
|
2091
|
+
if (state === null || state === void 0 ? void 0 : state.validate) {
|
|
2092
|
+
return state.validate();
|
|
2098
2093
|
}
|
|
2099
|
-
|
|
2094
|
+
if (!state) {
|
|
2095
|
+
vue.warn(`field with path ${path} was not found`);
|
|
2096
|
+
}
|
|
2097
|
+
return Promise.resolve({ errors: [], valid: true });
|
|
2100
2098
|
}
|
|
2101
2099
|
function unsetInitialValue(path) {
|
|
2102
2100
|
unsetPath(initialValues.value, path);
|
|
@@ -2105,8 +2103,8 @@
|
|
|
2105
2103
|
* Sneaky function to set initial field values
|
|
2106
2104
|
*/
|
|
2107
2105
|
function stageInitialValue(path, value, updateOriginal = false) {
|
|
2108
|
-
setInPath(formValues, path, value);
|
|
2109
2106
|
setFieldInitialValue(path, value);
|
|
2107
|
+
setInPath(formValues, path, value);
|
|
2110
2108
|
if (updateOriginal && !(opts === null || opts === void 0 ? void 0 : opts.initialValues)) {
|
|
2111
2109
|
setInPath(originalInitialValues.value, path, klona(value));
|
|
2112
2110
|
}
|
|
@@ -2159,12 +2157,95 @@
|
|
|
2159
2157
|
}
|
|
2160
2158
|
// Provide injections
|
|
2161
2159
|
vue.provide(FormContextKey, formCtx);
|
|
2162
|
-
|
|
2160
|
+
function defineComponentBinds(path, config) {
|
|
2161
|
+
const pathState = findPathState(unravel(path)) || createPathState(path);
|
|
2162
|
+
const evalConfig = () => (isCallable(config) ? config(omit(pathState, PRIVATE_PATH_STATE_KEYS)) : config || {});
|
|
2163
|
+
function onBlur() {
|
|
2164
|
+
var _a;
|
|
2165
|
+
pathState.touched = true;
|
|
2166
|
+
const validateOnBlur = (_a = evalConfig().validateOnBlur) !== null && _a !== void 0 ? _a : getConfig().validateOnBlur;
|
|
2167
|
+
if (validateOnBlur) {
|
|
2168
|
+
validateField(pathState.path);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
function onUpdateModelValue(value) {
|
|
2172
|
+
var _a;
|
|
2173
|
+
setFieldValue(pathState.path, value);
|
|
2174
|
+
const validateOnModelUpdate = (_a = evalConfig().validateOnModelUpdate) !== null && _a !== void 0 ? _a : getConfig().validateOnModelUpdate;
|
|
2175
|
+
if (validateOnModelUpdate) {
|
|
2176
|
+
validateField(pathState.path);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
const props = vue.computed(() => {
|
|
2180
|
+
const base = {
|
|
2181
|
+
modelValue: pathState.value,
|
|
2182
|
+
'onUpdate:modelValue': onUpdateModelValue,
|
|
2183
|
+
onBlur,
|
|
2184
|
+
};
|
|
2185
|
+
if (isCallable(config)) {
|
|
2186
|
+
return Object.assign(Object.assign({}, base), (config(pathState).props || {}));
|
|
2187
|
+
}
|
|
2188
|
+
if (config === null || config === void 0 ? void 0 : config.mapProps) {
|
|
2189
|
+
return Object.assign(Object.assign({}, base), config.mapProps(omit(pathState, PRIVATE_PATH_STATE_KEYS)));
|
|
2190
|
+
}
|
|
2191
|
+
return base;
|
|
2192
|
+
});
|
|
2193
|
+
return props;
|
|
2194
|
+
}
|
|
2195
|
+
function defineInputBinds(path, config) {
|
|
2196
|
+
const pathState = (findPathState(unravel(path)) || createPathState(path));
|
|
2197
|
+
const evalConfig = () => (isCallable(config) ? config(omit(pathState, PRIVATE_PATH_STATE_KEYS)) : config || {});
|
|
2198
|
+
function onBlur() {
|
|
2199
|
+
var _a;
|
|
2200
|
+
pathState.touched = true;
|
|
2201
|
+
const validateOnBlur = (_a = evalConfig().validateOnBlur) !== null && _a !== void 0 ? _a : getConfig().validateOnBlur;
|
|
2202
|
+
if (validateOnBlur) {
|
|
2203
|
+
validateField(pathState.path);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
function onInput(e) {
|
|
2207
|
+
var _a;
|
|
2208
|
+
const value = normalizeEventValue(e);
|
|
2209
|
+
setFieldValue(pathState.path, value);
|
|
2210
|
+
const validateOnInput = (_a = evalConfig().validateOnInput) !== null && _a !== void 0 ? _a : getConfig().validateOnInput;
|
|
2211
|
+
if (validateOnInput) {
|
|
2212
|
+
validateField(pathState.path);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
function onChange(e) {
|
|
2216
|
+
var _a;
|
|
2217
|
+
const value = normalizeEventValue(e);
|
|
2218
|
+
setFieldValue(pathState.path, value);
|
|
2219
|
+
const validateOnChange = (_a = evalConfig().validateOnChange) !== null && _a !== void 0 ? _a : getConfig().validateOnChange;
|
|
2220
|
+
if (validateOnChange) {
|
|
2221
|
+
validateField(pathState.path);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
const props = vue.computed(() => {
|
|
2225
|
+
const base = {
|
|
2226
|
+
value: pathState.value,
|
|
2227
|
+
onChange,
|
|
2228
|
+
onInput,
|
|
2229
|
+
onBlur,
|
|
2230
|
+
};
|
|
2231
|
+
if (isCallable(config)) {
|
|
2232
|
+
return Object.assign(Object.assign({}, base), (config(omit(pathState, PRIVATE_PATH_STATE_KEYS)).attrs || {}));
|
|
2233
|
+
}
|
|
2234
|
+
if (config === null || config === void 0 ? void 0 : config.mapAttrs) {
|
|
2235
|
+
return Object.assign(Object.assign({}, base), config.mapAttrs(omit(pathState, PRIVATE_PATH_STATE_KEYS)));
|
|
2236
|
+
}
|
|
2237
|
+
return base;
|
|
2238
|
+
});
|
|
2239
|
+
return props;
|
|
2240
|
+
}
|
|
2241
|
+
return Object.assign(Object.assign({}, formCtx), { handleReset: () => resetForm(), submitForm,
|
|
2242
|
+
defineComponentBinds,
|
|
2243
|
+
defineInputBinds });
|
|
2163
2244
|
}
|
|
2164
2245
|
/**
|
|
2165
2246
|
* Manages form meta aggregation
|
|
2166
2247
|
*/
|
|
2167
|
-
function useFormMeta(
|
|
2248
|
+
function useFormMeta(pathsState, currentValues, initialValues, errors) {
|
|
2168
2249
|
const MERGE_STRATEGIES = {
|
|
2169
2250
|
touched: 'some',
|
|
2170
2251
|
pending: 'some',
|
|
@@ -2174,10 +2255,10 @@
|
|
|
2174
2255
|
return !isEqual(currentValues, vue.unref(initialValues));
|
|
2175
2256
|
});
|
|
2176
2257
|
function calculateFlags() {
|
|
2177
|
-
const
|
|
2258
|
+
const states = pathsState.value;
|
|
2178
2259
|
return keysOf(MERGE_STRATEGIES).reduce((acc, flag) => {
|
|
2179
2260
|
const mergeMethod = MERGE_STRATEGIES[flag];
|
|
2180
|
-
acc[flag] =
|
|
2261
|
+
acc[flag] = states[mergeMethod](s => s[flag]);
|
|
2181
2262
|
return acc;
|
|
2182
2263
|
}, {});
|
|
2183
2264
|
}
|
|
@@ -2195,7 +2276,7 @@
|
|
|
2195
2276
|
/**
|
|
2196
2277
|
* Manages the initial values prop
|
|
2197
2278
|
*/
|
|
2198
|
-
function useFormInitialValues(
|
|
2279
|
+
function useFormInitialValues(pathsState, formValues, opts) {
|
|
2199
2280
|
const values = resolveInitialValues(opts);
|
|
2200
2281
|
const providedValues = opts === null || opts === void 0 ? void 0 : opts.initialValues;
|
|
2201
2282
|
// these are the mutable initial values as the fields are mounted/unmounted
|
|
@@ -2216,14 +2297,13 @@
|
|
|
2216
2297
|
// those are excluded because it's unlikely you want to change the form values using initial values
|
|
2217
2298
|
// we mostly watch them for API population or newly inserted fields
|
|
2218
2299
|
// if the user API is taking too much time before user interaction they should consider disabling or hiding their inputs until the values are ready
|
|
2219
|
-
|
|
2220
|
-
const
|
|
2221
|
-
|
|
2222
|
-
if (!field || wasTouched) {
|
|
2300
|
+
pathsState.value.forEach(state => {
|
|
2301
|
+
const wasTouched = state.touched;
|
|
2302
|
+
if (wasTouched) {
|
|
2223
2303
|
return;
|
|
2224
2304
|
}
|
|
2225
|
-
const newValue = getFromPath(initialValues.value,
|
|
2226
|
-
setInPath(formValues,
|
|
2305
|
+
const newValue = getFromPath(initialValues.value, state.path);
|
|
2306
|
+
setInPath(formValues, state.path, klona(newValue));
|
|
2227
2307
|
});
|
|
2228
2308
|
}
|
|
2229
2309
|
if (vue.isRef(providedValues)) {
|
|
@@ -2239,42 +2319,6 @@
|
|
|
2239
2319
|
setInitialValues,
|
|
2240
2320
|
};
|
|
2241
2321
|
}
|
|
2242
|
-
function useErrorBag(initialErrors) {
|
|
2243
|
-
const errorBag = vue.ref({});
|
|
2244
|
-
function normalizeErrorItem(message) {
|
|
2245
|
-
return Array.isArray(message) ? message : message ? [message] : [];
|
|
2246
|
-
}
|
|
2247
|
-
/**
|
|
2248
|
-
* Manually sets an error message on a specific field
|
|
2249
|
-
*/
|
|
2250
|
-
function setFieldErrorBag(field, message) {
|
|
2251
|
-
if (!message) {
|
|
2252
|
-
delete errorBag.value[field];
|
|
2253
|
-
return;
|
|
2254
|
-
}
|
|
2255
|
-
errorBag.value[field] = normalizeErrorItem(message);
|
|
2256
|
-
}
|
|
2257
|
-
/**
|
|
2258
|
-
* Sets errors for the fields specified in the object
|
|
2259
|
-
*/
|
|
2260
|
-
function setErrorBag(fields) {
|
|
2261
|
-
errorBag.value = keysOf(fields).reduce((acc, key) => {
|
|
2262
|
-
const message = fields[key];
|
|
2263
|
-
if (message) {
|
|
2264
|
-
acc[key] = normalizeErrorItem(message);
|
|
2265
|
-
}
|
|
2266
|
-
return acc;
|
|
2267
|
-
}, {});
|
|
2268
|
-
}
|
|
2269
|
-
if (initialErrors) {
|
|
2270
|
-
setErrorBag(initialErrors);
|
|
2271
|
-
}
|
|
2272
|
-
return {
|
|
2273
|
-
errorBag,
|
|
2274
|
-
setErrorBag,
|
|
2275
|
-
setFieldErrorBag,
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
2322
|
|
|
2279
2323
|
const FormImpl = vue.defineComponent({
|
|
2280
2324
|
name: 'Form',
|
|
@@ -2455,7 +2499,10 @@
|
|
|
2455
2499
|
}
|
|
2456
2500
|
function initFields() {
|
|
2457
2501
|
const currentValues = getCurrentValues();
|
|
2458
|
-
|
|
2502
|
+
if (!Array.isArray(currentValues)) {
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
fields.value = currentValues.map((v, idx) => createEntry(v, idx, fields.value));
|
|
2459
2506
|
updateEntryFlags();
|
|
2460
2507
|
}
|
|
2461
2508
|
initFields();
|
|
@@ -2467,7 +2514,13 @@
|
|
|
2467
2514
|
entry.isLast = i === fieldsLength - 1;
|
|
2468
2515
|
}
|
|
2469
2516
|
}
|
|
2470
|
-
function createEntry(value) {
|
|
2517
|
+
function createEntry(value, idx, currentFields) {
|
|
2518
|
+
// Skips the work by returning the current entry if it already exists
|
|
2519
|
+
// This should make the `key` prop stable and doesn't cause more re-renders than needed
|
|
2520
|
+
// The value is computed and should update anyways
|
|
2521
|
+
if (currentFields && !isNullOrUndefined(idx) && currentFields[idx]) {
|
|
2522
|
+
return currentFields[idx];
|
|
2523
|
+
}
|
|
2471
2524
|
const key = entryCounter++;
|
|
2472
2525
|
const entry = {
|
|
2473
2526
|
key,
|
|
@@ -2504,8 +2557,9 @@
|
|
|
2504
2557
|
}
|
|
2505
2558
|
const newValue = [...pathValue];
|
|
2506
2559
|
newValue.splice(idx, 1);
|
|
2507
|
-
|
|
2508
|
-
form
|
|
2560
|
+
const fieldPath = pathName + `[${idx}]`;
|
|
2561
|
+
form.unsetInitialValue(fieldPath);
|
|
2562
|
+
setInPath(form.values, pathName, newValue);
|
|
2509
2563
|
fields.value.splice(idx, 1);
|
|
2510
2564
|
afterMutation();
|
|
2511
2565
|
}
|
|
@@ -2518,8 +2572,8 @@
|
|
|
2518
2572
|
}
|
|
2519
2573
|
const newValue = [...normalizedPathValue];
|
|
2520
2574
|
newValue.push(value);
|
|
2521
|
-
form
|
|
2522
|
-
form
|
|
2575
|
+
form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2576
|
+
setInPath(form.values, pathName, newValue);
|
|
2523
2577
|
fields.value.push(createEntry(value));
|
|
2524
2578
|
afterMutation();
|
|
2525
2579
|
}
|
|
@@ -2538,7 +2592,7 @@
|
|
|
2538
2592
|
const tempEntry = newFields[indexA];
|
|
2539
2593
|
newFields[indexA] = newFields[indexB];
|
|
2540
2594
|
newFields[indexB] = tempEntry;
|
|
2541
|
-
form
|
|
2595
|
+
setInPath(form.values, pathName, newValue);
|
|
2542
2596
|
fields.value = newFields;
|
|
2543
2597
|
updateEntryFlags();
|
|
2544
2598
|
}
|
|
@@ -2552,13 +2606,14 @@
|
|
|
2552
2606
|
const newFields = [...fields.value];
|
|
2553
2607
|
newValue.splice(idx, 0, value);
|
|
2554
2608
|
newFields.splice(idx, 0, createEntry(value));
|
|
2555
|
-
form
|
|
2609
|
+
setInPath(form.values, pathName, newValue);
|
|
2556
2610
|
fields.value = newFields;
|
|
2557
2611
|
afterMutation();
|
|
2558
2612
|
}
|
|
2559
2613
|
function replace(arr) {
|
|
2560
2614
|
const pathName = vue.unref(arrayPath);
|
|
2561
|
-
form
|
|
2615
|
+
form.stageInitialValue(pathName, arr);
|
|
2616
|
+
setInPath(form.values, pathName, arr);
|
|
2562
2617
|
initFields();
|
|
2563
2618
|
afterMutation();
|
|
2564
2619
|
}
|
|
@@ -2568,7 +2623,7 @@
|
|
|
2568
2623
|
if (!Array.isArray(pathValue) || pathValue.length - 1 < idx) {
|
|
2569
2624
|
return;
|
|
2570
2625
|
}
|
|
2571
|
-
form
|
|
2626
|
+
setInPath(form.values, `${pathName}[${idx}]`, value);
|
|
2572
2627
|
form === null || form === void 0 ? void 0 : form.validate({ mode: 'validated-only' });
|
|
2573
2628
|
}
|
|
2574
2629
|
function prepend(value) {
|
|
@@ -2579,8 +2634,8 @@
|
|
|
2579
2634
|
return;
|
|
2580
2635
|
}
|
|
2581
2636
|
const newValue = [value, ...normalizedPathValue];
|
|
2582
|
-
form
|
|
2583
|
-
form
|
|
2637
|
+
form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2638
|
+
setInPath(form.values, pathName, newValue);
|
|
2584
2639
|
fields.value.unshift(createEntry(value));
|
|
2585
2640
|
afterMutation();
|
|
2586
2641
|
}
|
|
@@ -2598,7 +2653,7 @@
|
|
|
2598
2653
|
const movedValue = newValue[oldIdx];
|
|
2599
2654
|
newValue.splice(oldIdx, 1);
|
|
2600
2655
|
newValue.splice(newIdx, 0, movedValue);
|
|
2601
|
-
form
|
|
2656
|
+
setInPath(form.values, pathName, newValue);
|
|
2602
2657
|
fields.value = newFields;
|
|
2603
2658
|
afterMutation();
|
|
2604
2659
|
}
|
|
@@ -2737,17 +2792,13 @@
|
|
|
2737
2792
|
* If a field is dirty or not
|
|
2738
2793
|
*/
|
|
2739
2794
|
function useIsFieldDirty(path) {
|
|
2740
|
-
const
|
|
2741
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2795
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2742
2796
|
return vue.computed(() => {
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
}
|
|
2746
|
-
if (!field) {
|
|
2747
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2797
|
+
var _a, _b;
|
|
2798
|
+
if (!fieldOrPath) {
|
|
2748
2799
|
return false;
|
|
2749
2800
|
}
|
|
2750
|
-
return
|
|
2801
|
+
return (_b = ('meta' in fieldOrPath ? fieldOrPath.meta.dirty : (_a = fieldOrPath === null || fieldOrPath === void 0 ? void 0 : fieldOrPath.value) === null || _a === void 0 ? void 0 : _a.dirty)) !== null && _b !== void 0 ? _b : false;
|
|
2751
2802
|
});
|
|
2752
2803
|
}
|
|
2753
2804
|
|
|
@@ -2755,17 +2806,13 @@
|
|
|
2755
2806
|
* If a field is touched or not
|
|
2756
2807
|
*/
|
|
2757
2808
|
function useIsFieldTouched(path) {
|
|
2758
|
-
const
|
|
2759
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2809
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2760
2810
|
return vue.computed(() => {
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
}
|
|
2764
|
-
if (!field) {
|
|
2765
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2811
|
+
var _a, _b;
|
|
2812
|
+
if (!fieldOrPath) {
|
|
2766
2813
|
return false;
|
|
2767
2814
|
}
|
|
2768
|
-
return
|
|
2815
|
+
return (_b = ('meta' in fieldOrPath ? fieldOrPath.meta.touched : (_a = fieldOrPath === null || fieldOrPath === void 0 ? void 0 : fieldOrPath.value) === null || _a === void 0 ? void 0 : _a.touched)) !== null && _b !== void 0 ? _b : false;
|
|
2769
2816
|
});
|
|
2770
2817
|
}
|
|
2771
2818
|
|
|
@@ -2773,17 +2820,13 @@
|
|
|
2773
2820
|
* If a field is validated and is valid
|
|
2774
2821
|
*/
|
|
2775
2822
|
function useIsFieldValid(path) {
|
|
2776
|
-
const
|
|
2777
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2823
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2778
2824
|
return vue.computed(() => {
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
}
|
|
2782
|
-
if (!field) {
|
|
2783
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2825
|
+
var _a, _b;
|
|
2826
|
+
if (!fieldOrPath) {
|
|
2784
2827
|
return false;
|
|
2785
2828
|
}
|
|
2786
|
-
return
|
|
2829
|
+
return (_b = ('meta' in fieldOrPath ? fieldOrPath.meta.valid : (_a = fieldOrPath === null || fieldOrPath === void 0 ? void 0 : fieldOrPath.value) === null || _a === void 0 ? void 0 : _a.valid)) !== null && _b !== void 0 ? _b : false;
|
|
2787
2830
|
});
|
|
2788
2831
|
}
|
|
2789
2832
|
|
|
@@ -2806,19 +2849,19 @@
|
|
|
2806
2849
|
*/
|
|
2807
2850
|
function useValidateField(path) {
|
|
2808
2851
|
const form = injectWithSelf(FormContextKey);
|
|
2809
|
-
|
|
2852
|
+
const field = path ? undefined : vue.inject(FieldContextKey);
|
|
2810
2853
|
return function validateField() {
|
|
2811
|
-
if (
|
|
2812
|
-
field
|
|
2854
|
+
if (field) {
|
|
2855
|
+
return field.validate();
|
|
2813
2856
|
}
|
|
2814
|
-
if (
|
|
2815
|
-
|
|
2816
|
-
return Promise.resolve({
|
|
2817
|
-
errors: [],
|
|
2818
|
-
valid: true,
|
|
2819
|
-
});
|
|
2857
|
+
if (form && path) {
|
|
2858
|
+
return form === null || form === void 0 ? void 0 : form.validateField(vue.unref(path));
|
|
2820
2859
|
}
|
|
2821
|
-
|
|
2860
|
+
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2861
|
+
return Promise.resolve({
|
|
2862
|
+
errors: [],
|
|
2863
|
+
valid: true,
|
|
2864
|
+
});
|
|
2822
2865
|
};
|
|
2823
2866
|
}
|
|
2824
2867
|
|