vee-validate 4.8.6 → 4.9.1
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 +266 -73
- package/dist/vee-validate.esm.js +672 -581
- package/dist/vee-validate.js +556 -495
- package/dist/vee-validate.min.js +2 -2
- package/package.json +3 -2
package/dist/vee-validate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vee-validate v4.
|
|
2
|
+
* vee-validate v4.9.1
|
|
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();
|
|
@@ -1490,9 +1548,27 @@
|
|
|
1490
1548
|
};
|
|
1491
1549
|
const fieldProps = vue.computed(() => {
|
|
1492
1550
|
const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(props);
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1551
|
+
function baseOnBlur(e) {
|
|
1552
|
+
handleBlur(e);
|
|
1553
|
+
if (isCallable(ctx.attrs.onBlur)) {
|
|
1554
|
+
ctx.attrs.onBlur(e);
|
|
1555
|
+
}
|
|
1556
|
+
if (validateOnBlur) {
|
|
1557
|
+
validateField();
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
function baseOnInput(e) {
|
|
1561
|
+
onChangeHandler(e, validateOnInput);
|
|
1562
|
+
if (isCallable(ctx.attrs.onInput)) {
|
|
1563
|
+
ctx.attrs.onInput(e);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function baseOnChange(e) {
|
|
1567
|
+
onChangeHandler(e, validateOnChange);
|
|
1568
|
+
if (isCallable(ctx.attrs.onChange)) {
|
|
1569
|
+
ctx.attrs.onChange(e);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1496
1572
|
const attrs = {
|
|
1497
1573
|
name: props.name,
|
|
1498
1574
|
onBlur: baseOnBlur,
|
|
@@ -1571,6 +1647,7 @@
|
|
|
1571
1647
|
const Field = FieldImpl;
|
|
1572
1648
|
|
|
1573
1649
|
let FORM_COUNTER = 0;
|
|
1650
|
+
const PRIVATE_PATH_STATE_KEYS = ['bails', 'fieldsCount', 'id', 'multiple', 'type', 'validate'];
|
|
1574
1651
|
function resolveInitialValues(opts) {
|
|
1575
1652
|
const providedValues = vue.unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {};
|
|
1576
1653
|
const schema = vue.unref(opts === null || opts === void 0 ? void 0 : opts.validationSchema);
|
|
@@ -1582,12 +1659,8 @@
|
|
|
1582
1659
|
function useForm(opts) {
|
|
1583
1660
|
var _a;
|
|
1584
1661
|
const formId = FORM_COUNTER++;
|
|
1585
|
-
const controlledModelPaths = new Set();
|
|
1586
1662
|
// 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({});
|
|
1663
|
+
let FIELD_ID_COUNTER = 0;
|
|
1591
1664
|
// If the form is currently submitting
|
|
1592
1665
|
const isSubmitting = vue.ref(false);
|
|
1593
1666
|
// The number of times the user tried to submit the form
|
|
@@ -1596,44 +1669,62 @@
|
|
|
1596
1669
|
const fieldArrays = [];
|
|
1597
1670
|
// a private ref for all form values
|
|
1598
1671
|
const formValues = vue.reactive(resolveInitialValues(opts));
|
|
1599
|
-
|
|
1600
|
-
const
|
|
1672
|
+
const pathStates = vue.ref([]);
|
|
1673
|
+
const extraErrorsBag = vue.ref({});
|
|
1674
|
+
/**
|
|
1675
|
+
* Manually sets an error message on a specific field
|
|
1676
|
+
*/
|
|
1677
|
+
function setFieldError(field, message) {
|
|
1678
|
+
const state = findPathState(field);
|
|
1679
|
+
if (!state) {
|
|
1680
|
+
extraErrorsBag.value[field] = normalizeErrorItem(message);
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
state.errors = normalizeErrorItem(message);
|
|
1684
|
+
}
|
|
1685
|
+
/**
|
|
1686
|
+
* Sets errors for the fields specified in the object
|
|
1687
|
+
*/
|
|
1688
|
+
function setErrors(paths) {
|
|
1689
|
+
keysOf(paths).forEach(path => {
|
|
1690
|
+
setFieldError(path, paths[path]);
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
if (opts === null || opts === void 0 ? void 0 : opts.initialErrors) {
|
|
1694
|
+
setErrors(opts.initialErrors);
|
|
1695
|
+
}
|
|
1696
|
+
const errorBag = vue.computed(() => {
|
|
1697
|
+
const pathErrors = pathStates.value.reduce((acc, state) => {
|
|
1698
|
+
if (state.errors.length) {
|
|
1699
|
+
acc[state.path] = state.errors;
|
|
1700
|
+
}
|
|
1701
|
+
return acc;
|
|
1702
|
+
}, {});
|
|
1703
|
+
return Object.assign(Object.assign({}, extraErrorsBag.value), pathErrors);
|
|
1704
|
+
});
|
|
1601
1705
|
// Gets the first error of each field
|
|
1602
1706
|
const errors = vue.computed(() => {
|
|
1603
1707
|
return keysOf(errorBag.value).reduce((acc, key) => {
|
|
1604
|
-
const
|
|
1605
|
-
if (
|
|
1606
|
-
acc[key] =
|
|
1708
|
+
const errors = errorBag.value[key];
|
|
1709
|
+
if (errors === null || errors === void 0 ? void 0 : errors.length) {
|
|
1710
|
+
acc[key] = errors[0];
|
|
1607
1711
|
}
|
|
1608
1712
|
return acc;
|
|
1609
1713
|
}, {});
|
|
1610
1714
|
});
|
|
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
1715
|
/**
|
|
1619
1716
|
* Holds a computed reference to all fields names and labels
|
|
1620
1717
|
*/
|
|
1621
1718
|
const fieldNames = vue.computed(() => {
|
|
1622
|
-
return
|
|
1623
|
-
|
|
1624
|
-
if (field) {
|
|
1625
|
-
names[path] = { name: vue.unref(field.name) || '', label: vue.unref(field.label) || '' };
|
|
1626
|
-
}
|
|
1719
|
+
return pathStates.value.reduce((names, state) => {
|
|
1720
|
+
names[state.path] = { name: state.path || '', label: state.label || '' };
|
|
1627
1721
|
return names;
|
|
1628
1722
|
}, {});
|
|
1629
1723
|
});
|
|
1630
1724
|
const fieldBailsMap = vue.computed(() => {
|
|
1631
|
-
return
|
|
1725
|
+
return pathStates.value.reduce((map, state) => {
|
|
1632
1726
|
var _a;
|
|
1633
|
-
|
|
1634
|
-
if (field) {
|
|
1635
|
-
map[path] = (_a = field.bails) !== null && _a !== void 0 ? _a : true;
|
|
1636
|
-
}
|
|
1727
|
+
map[state.path] = (_a = state.bails) !== null && _a !== void 0 ? _a : true;
|
|
1637
1728
|
return map;
|
|
1638
1729
|
}, {});
|
|
1639
1730
|
});
|
|
@@ -1642,17 +1733,74 @@
|
|
|
1642
1733
|
const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
|
|
1643
1734
|
const keepValuesOnUnmount = (_a = opts === null || opts === void 0 ? void 0 : opts.keepValuesOnUnmount) !== null && _a !== void 0 ? _a : false;
|
|
1644
1735
|
// initial form values
|
|
1645
|
-
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(
|
|
1736
|
+
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(pathStates, formValues, opts);
|
|
1646
1737
|
// form meta aggregations
|
|
1647
|
-
const meta = useFormMeta(
|
|
1738
|
+
const meta = useFormMeta(pathStates, formValues, originalInitialValues, errors);
|
|
1648
1739
|
const controlledValues = vue.computed(() => {
|
|
1649
|
-
return
|
|
1650
|
-
const value = getFromPath(formValues, path);
|
|
1651
|
-
setInPath(acc, path, value);
|
|
1740
|
+
return pathStates.value.reduce((acc, state) => {
|
|
1741
|
+
const value = getFromPath(formValues, state.path);
|
|
1742
|
+
setInPath(acc, state.path, value);
|
|
1652
1743
|
return acc;
|
|
1653
1744
|
}, {});
|
|
1654
1745
|
});
|
|
1655
1746
|
const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
|
|
1747
|
+
function createPathState(path, config) {
|
|
1748
|
+
var _a, _b;
|
|
1749
|
+
const initialValue = vue.computed(() => getFromPath(initialValues.value, unravel(path)));
|
|
1750
|
+
const pathStateExists = pathStates.value.find(state => state.path === vue.unref(path));
|
|
1751
|
+
if (pathStateExists) {
|
|
1752
|
+
if ((config === null || config === void 0 ? void 0 : config.type) === 'checkbox' || (config === null || config === void 0 ? void 0 : config.type) === 'radio') {
|
|
1753
|
+
pathStateExists.multiple = true;
|
|
1754
|
+
}
|
|
1755
|
+
if (Array.isArray(pathStateExists.id)) {
|
|
1756
|
+
pathStateExists.id.push(FIELD_ID_COUNTER++);
|
|
1757
|
+
}
|
|
1758
|
+
else {
|
|
1759
|
+
pathStateExists.id = [pathStateExists.id, FIELD_ID_COUNTER++];
|
|
1760
|
+
}
|
|
1761
|
+
pathStateExists.fieldsCount++;
|
|
1762
|
+
return pathStateExists;
|
|
1763
|
+
}
|
|
1764
|
+
const currentValue = vue.computed(() => getFromPath(formValues, unravel(path)));
|
|
1765
|
+
const pathValue = unravel(path);
|
|
1766
|
+
const state = vue.reactive({
|
|
1767
|
+
id: FIELD_ID_COUNTER++,
|
|
1768
|
+
path,
|
|
1769
|
+
touched: false,
|
|
1770
|
+
pending: false,
|
|
1771
|
+
valid: true,
|
|
1772
|
+
validated: !!((_a = initialErrors[pathValue]) === null || _a === void 0 ? void 0 : _a.length),
|
|
1773
|
+
initialValue,
|
|
1774
|
+
errors: vue.shallowRef([]),
|
|
1775
|
+
bails: (_b = config === null || config === void 0 ? void 0 : config.bails) !== null && _b !== void 0 ? _b : false,
|
|
1776
|
+
label: config === null || config === void 0 ? void 0 : config.label,
|
|
1777
|
+
type: (config === null || config === void 0 ? void 0 : config.type) || 'default',
|
|
1778
|
+
value: currentValue,
|
|
1779
|
+
multiple: false,
|
|
1780
|
+
fieldsCount: 1,
|
|
1781
|
+
validate: config === null || config === void 0 ? void 0 : config.validate,
|
|
1782
|
+
dirty: vue.computed(() => {
|
|
1783
|
+
return !isEqual(vue.unref(currentValue), vue.unref(initialValue));
|
|
1784
|
+
}),
|
|
1785
|
+
});
|
|
1786
|
+
pathStates.value.push(state);
|
|
1787
|
+
// if it has errors before, validate it.
|
|
1788
|
+
if (errors.value[pathValue] && !initialErrors[pathValue]) {
|
|
1789
|
+
vue.nextTick(() => {
|
|
1790
|
+
validateField(pathValue);
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
// Handles when a path changes
|
|
1794
|
+
if (vue.isRef(path)) {
|
|
1795
|
+
vue.watch(path, newPath => {
|
|
1796
|
+
const nextValue = klona(currentValue.value);
|
|
1797
|
+
vue.nextTick(() => {
|
|
1798
|
+
setInPath(formValues, newPath, nextValue);
|
|
1799
|
+
});
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
return state;
|
|
1803
|
+
}
|
|
1656
1804
|
/**
|
|
1657
1805
|
* Batches validation runs in 5ms batches
|
|
1658
1806
|
* Must have two distinct batch queues to make sure they don't override each other settings #3783
|
|
@@ -1663,17 +1811,17 @@
|
|
|
1663
1811
|
return (await mode) === 'silent' ? debouncedSilentValidation() : debouncedValidation();
|
|
1664
1812
|
}, (formResult, [mode]) => {
|
|
1665
1813
|
// fields by id lookup
|
|
1666
|
-
const fieldsById = formCtx.fieldsByPath.value || {};
|
|
1667
1814
|
// errors fields names, we need it to also check if custom errors are updated
|
|
1668
1815
|
const currentErrorsPaths = keysOf(formCtx.errorBag.value);
|
|
1669
1816
|
// collect all the keys from the schema and all fields
|
|
1670
|
-
// this ensures we have a complete
|
|
1817
|
+
// this ensures we have a complete key map of all the fields
|
|
1671
1818
|
const paths = [
|
|
1672
|
-
...new Set([...keysOf(formResult.results), ...
|
|
1819
|
+
...new Set([...keysOf(formResult.results), ...pathStates.value.map(p => p.path), ...currentErrorsPaths]),
|
|
1673
1820
|
];
|
|
1674
1821
|
// aggregates the paths into a single result object while applying the results on the fields
|
|
1675
|
-
return paths.reduce((validation,
|
|
1676
|
-
const
|
|
1822
|
+
return paths.reduce((validation, _path) => {
|
|
1823
|
+
const path = _path;
|
|
1824
|
+
const pathState = findPathState(path);
|
|
1677
1825
|
const messages = (formResult.results[path] || { errors: [] }).errors;
|
|
1678
1826
|
const fieldResult = {
|
|
1679
1827
|
errors: messages,
|
|
@@ -1683,24 +1831,37 @@
|
|
|
1683
1831
|
if (!fieldResult.valid) {
|
|
1684
1832
|
validation.errors[path] = fieldResult.errors[0];
|
|
1685
1833
|
}
|
|
1834
|
+
// clean up extra errors if path state exists
|
|
1835
|
+
if (pathState && extraErrorsBag.value[path]) {
|
|
1836
|
+
delete extraErrorsBag.value[path];
|
|
1837
|
+
}
|
|
1686
1838
|
// field not rendered
|
|
1687
|
-
if (!
|
|
1839
|
+
if (!pathState) {
|
|
1688
1840
|
setFieldError(path, messages);
|
|
1689
1841
|
return validation;
|
|
1690
1842
|
}
|
|
1691
1843
|
// always update the valid flag regardless of the mode
|
|
1692
|
-
|
|
1844
|
+
pathState.valid = fieldResult.valid;
|
|
1693
1845
|
if (mode === 'silent') {
|
|
1694
1846
|
return validation;
|
|
1695
1847
|
}
|
|
1696
|
-
|
|
1697
|
-
if (mode === 'validated-only' && !wasValidated) {
|
|
1848
|
+
if (mode === 'validated-only' && !pathState.validated) {
|
|
1698
1849
|
return validation;
|
|
1699
1850
|
}
|
|
1700
|
-
|
|
1851
|
+
setFieldError(pathState, fieldResult.errors);
|
|
1701
1852
|
return validation;
|
|
1702
1853
|
}, { valid: formResult.valid, results: {}, errors: {} });
|
|
1703
1854
|
});
|
|
1855
|
+
function mutateAllPathState(mutation) {
|
|
1856
|
+
pathStates.value.forEach(mutation);
|
|
1857
|
+
}
|
|
1858
|
+
function findPathState(path) {
|
|
1859
|
+
const pathState = typeof path === 'string' ? pathStates.value.find(state => state.path === path) : path;
|
|
1860
|
+
return pathState;
|
|
1861
|
+
}
|
|
1862
|
+
function unsetPathValue(path) {
|
|
1863
|
+
unsetPath(formValues, path);
|
|
1864
|
+
}
|
|
1704
1865
|
function makeSubmissionFactory(onlyControlled) {
|
|
1705
1866
|
return function submitHandlerFactory(fn, onValidationError) {
|
|
1706
1867
|
return function submissionHandler(e) {
|
|
@@ -1709,10 +1870,7 @@
|
|
|
1709
1870
|
e.stopPropagation();
|
|
1710
1871
|
}
|
|
1711
1872
|
// Touch all fields
|
|
1712
|
-
|
|
1713
|
-
acc[field] = true;
|
|
1714
|
-
return acc;
|
|
1715
|
-
}, {}));
|
|
1873
|
+
mutateAllPathState(s => (s.touched = true));
|
|
1716
1874
|
isSubmitting.value = true;
|
|
1717
1875
|
submitCount.value++;
|
|
1718
1876
|
return validate()
|
|
@@ -1720,7 +1878,7 @@
|
|
|
1720
1878
|
const values = klona(formValues);
|
|
1721
1879
|
if (result.valid && typeof fn === 'function') {
|
|
1722
1880
|
const controlled = klona(controlledValues.value);
|
|
1723
|
-
let submittedValues = onlyControlled ? controlled : values;
|
|
1881
|
+
let submittedValues = (onlyControlled ? controlled : values);
|
|
1724
1882
|
if (result.values) {
|
|
1725
1883
|
submittedValues = result.values;
|
|
1726
1884
|
}
|
|
@@ -1760,9 +1918,22 @@
|
|
|
1760
1918
|
const handleSubmitImpl = makeSubmissionFactory(false);
|
|
1761
1919
|
const handleSubmit = handleSubmitImpl;
|
|
1762
1920
|
handleSubmit.withControlled = makeSubmissionFactory(true);
|
|
1921
|
+
function removePathState(path) {
|
|
1922
|
+
const idx = pathStates.value.findIndex(s => s.path === path);
|
|
1923
|
+
const pathState = pathStates.value[idx];
|
|
1924
|
+
if (idx === -1 || !pathState) {
|
|
1925
|
+
return;
|
|
1926
|
+
}
|
|
1927
|
+
if (pathState.multiple && pathState.fieldsCount) {
|
|
1928
|
+
pathState.fieldsCount--;
|
|
1929
|
+
}
|
|
1930
|
+
if (!pathState.multiple || pathState.fieldsCount <= 0) {
|
|
1931
|
+
pathStates.value.splice(idx, 1);
|
|
1932
|
+
unsetInitialValue(path);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1763
1935
|
const formCtx = {
|
|
1764
1936
|
formId,
|
|
1765
|
-
fieldsByPath,
|
|
1766
1937
|
values: formValues,
|
|
1767
1938
|
controlledValues,
|
|
1768
1939
|
errorBag,
|
|
@@ -1775,14 +1946,11 @@
|
|
|
1775
1946
|
keepValuesOnUnmount,
|
|
1776
1947
|
validateSchema: vue.unref(schema) ? validateSchema : undefined,
|
|
1777
1948
|
validate,
|
|
1778
|
-
|
|
1779
|
-
unregister: unregisterField,
|
|
1780
|
-
setFieldErrorBag,
|
|
1949
|
+
setFieldError,
|
|
1781
1950
|
validateField,
|
|
1782
1951
|
setFieldValue,
|
|
1783
1952
|
setValues,
|
|
1784
1953
|
setErrors,
|
|
1785
|
-
setFieldError,
|
|
1786
1954
|
setFieldTouched,
|
|
1787
1955
|
setTouched,
|
|
1788
1956
|
resetForm,
|
|
@@ -1792,102 +1960,63 @@
|
|
|
1792
1960
|
unsetInitialValue,
|
|
1793
1961
|
setFieldInitialValue,
|
|
1794
1962
|
useFieldModel,
|
|
1963
|
+
createPathState,
|
|
1964
|
+
getPathState: findPathState,
|
|
1965
|
+
unsetPathValue,
|
|
1966
|
+
removePathState,
|
|
1967
|
+
initialValues: initialValues,
|
|
1968
|
+
getAllPathStates: () => pathStates.value,
|
|
1795
1969
|
};
|
|
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
1970
|
/**
|
|
1827
1971
|
* Sets a single field value
|
|
1828
1972
|
*/
|
|
1829
|
-
function setFieldValue(field, value
|
|
1830
|
-
var _a;
|
|
1831
|
-
const fieldInstance = fieldsByPath.value[field];
|
|
1973
|
+
function setFieldValue(field, value) {
|
|
1832
1974
|
const clonedValue = klona(value);
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
}
|
|
1838
|
-
if (isFieldGroup(fieldInstance) && ((_a = fieldInstance[0]) === null || _a === void 0 ? void 0 : _a.type) === 'checkbox' && !Array.isArray(value)) {
|
|
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)));
|
|
1975
|
+
const path = typeof field === 'string' ? field : field.path;
|
|
1976
|
+
const pathState = findPathState(path);
|
|
1977
|
+
if (!pathState) {
|
|
1978
|
+
createPathState(path);
|
|
1848
1979
|
}
|
|
1849
|
-
setInPath(formValues,
|
|
1980
|
+
setInPath(formValues, path, clonedValue);
|
|
1850
1981
|
}
|
|
1851
1982
|
/**
|
|
1852
1983
|
* Sets multiple fields values
|
|
1853
1984
|
*/
|
|
1854
1985
|
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
|
-
});
|
|
1986
|
+
merge(formValues, fields);
|
|
1863
1987
|
// regenerate the arrays when the form values change
|
|
1864
1988
|
fieldArrays.forEach(f => f && f.reset());
|
|
1865
1989
|
}
|
|
1866
1990
|
function createModel(path) {
|
|
1867
|
-
const
|
|
1868
|
-
vue.
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1991
|
+
const pathState = findPathState(vue.unref(path)) || createPathState(path);
|
|
1992
|
+
return vue.computed({
|
|
1993
|
+
get() {
|
|
1994
|
+
return pathState.value;
|
|
1995
|
+
},
|
|
1996
|
+
set(value) {
|
|
1997
|
+
const pathValue = vue.unref(path);
|
|
1998
|
+
setFieldValue(pathValue, value);
|
|
1999
|
+
pathState.validated = true;
|
|
2000
|
+
pathState.pending = true;
|
|
2001
|
+
validateField(pathValue).then(() => {
|
|
2002
|
+
pathState.pending = false;
|
|
2003
|
+
});
|
|
2004
|
+
},
|
|
1874
2005
|
});
|
|
1875
|
-
controlledModelPaths.add(vue.unref(path));
|
|
1876
|
-
return value;
|
|
1877
2006
|
}
|
|
1878
|
-
function useFieldModel(
|
|
1879
|
-
if (!Array.isArray(
|
|
1880
|
-
return createModel(
|
|
2007
|
+
function useFieldModel(pathOrPaths) {
|
|
2008
|
+
if (!Array.isArray(pathOrPaths)) {
|
|
2009
|
+
return createModel(pathOrPaths);
|
|
1881
2010
|
}
|
|
1882
|
-
return
|
|
2011
|
+
return pathOrPaths.map(createModel);
|
|
1883
2012
|
}
|
|
1884
2013
|
/**
|
|
1885
2014
|
* Sets the touched meta state on a field
|
|
1886
2015
|
*/
|
|
1887
2016
|
function setFieldTouched(field, isTouched) {
|
|
1888
|
-
const
|
|
1889
|
-
if (
|
|
1890
|
-
|
|
2017
|
+
const pathState = findPathState(field);
|
|
2018
|
+
if (pathState) {
|
|
2019
|
+
pathState.touched = isTouched;
|
|
1891
2020
|
}
|
|
1892
2021
|
}
|
|
1893
2022
|
/**
|
|
@@ -1899,172 +2028,53 @@
|
|
|
1899
2028
|
});
|
|
1900
2029
|
}
|
|
1901
2030
|
function resetField(field, state) {
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2031
|
+
var _a;
|
|
2032
|
+
const newValue = state && 'value' in state ? state.value : getFromPath(initialValues.value, field);
|
|
2033
|
+
setFieldInitialValue(field, klona(newValue));
|
|
2034
|
+
setFieldValue(field, newValue);
|
|
2035
|
+
setFieldTouched(field, (_a = state === null || state === void 0 ? void 0 : state.touched) !== null && _a !== void 0 ? _a : false);
|
|
2036
|
+
setFieldError(field, (state === null || state === void 0 ? void 0 : state.errors) || []);
|
|
1906
2037
|
}
|
|
1907
2038
|
/**
|
|
1908
2039
|
* Resets all fields
|
|
1909
2040
|
*/
|
|
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;
|
|
2041
|
+
function resetForm(resetState) {
|
|
2042
|
+
const newValues = (resetState === null || resetState === void 0 ? void 0 : resetState.values) ? resetState.values : originalInitialValues.value;
|
|
1916
2043
|
setInitialValues(newValues);
|
|
1917
2044
|
setValues(newValues);
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
RESET_LOCK = false;
|
|
2045
|
+
mutateAllPathState(state => {
|
|
2046
|
+
var _a;
|
|
2047
|
+
state.validated = false;
|
|
2048
|
+
state.touched = ((_a = resetState === null || resetState === void 0 ? void 0 : resetState.touched) === null || _a === void 0 ? void 0 : _a[state.path]) || false;
|
|
2049
|
+
setFieldValue(state.path, getFromPath(newValues, state.path));
|
|
2050
|
+
setFieldError(state.path, undefined);
|
|
1925
2051
|
});
|
|
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
|
|
2052
|
+
setErrors((resetState === null || resetState === void 0 ? void 0 : resetState.errors) || {});
|
|
2053
|
+
submitCount.value = (resetState === null || resetState === void 0 ? void 0 : resetState.submitCount) || 0;
|
|
2006
2054
|
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
|
-
}
|
|
2055
|
+
validate({ mode: 'silent' });
|
|
2049
2056
|
});
|
|
2050
2057
|
}
|
|
2051
2058
|
async function validate(opts) {
|
|
2052
2059
|
const mode = (opts === null || opts === void 0 ? void 0 : opts.mode) || 'force';
|
|
2053
2060
|
if (mode === 'force') {
|
|
2054
|
-
|
|
2061
|
+
mutateAllPathState(f => (f.validated = true));
|
|
2055
2062
|
}
|
|
2056
2063
|
if (formCtx.validateSchema) {
|
|
2057
2064
|
return formCtx.validateSchema(mode);
|
|
2058
2065
|
}
|
|
2059
2066
|
// No schema, each field is responsible to validate itself
|
|
2060
|
-
const validations = await Promise.all(
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2067
|
+
const validations = await Promise.all(pathStates.value.map(state => {
|
|
2068
|
+
if (!state.validate) {
|
|
2069
|
+
return Promise.resolve({
|
|
2070
|
+
key: state.path,
|
|
2071
|
+
valid: true,
|
|
2072
|
+
errors: [],
|
|
2073
|
+
});
|
|
2064
2074
|
}
|
|
2065
|
-
return
|
|
2075
|
+
return state.validate(opts).then((result) => {
|
|
2066
2076
|
return {
|
|
2067
|
-
key:
|
|
2077
|
+
key: state.path,
|
|
2068
2078
|
valid: result.valid,
|
|
2069
2079
|
errors: result.errors,
|
|
2070
2080
|
};
|
|
@@ -2087,16 +2097,22 @@
|
|
|
2087
2097
|
errors,
|
|
2088
2098
|
};
|
|
2089
2099
|
}
|
|
2090
|
-
async function validateField(
|
|
2091
|
-
const
|
|
2092
|
-
if (
|
|
2093
|
-
|
|
2094
|
-
|
|
2100
|
+
async function validateField(path) {
|
|
2101
|
+
const state = findPathState(path);
|
|
2102
|
+
if (state) {
|
|
2103
|
+
state.validated = true;
|
|
2104
|
+
}
|
|
2105
|
+
if (schema) {
|
|
2106
|
+
const { results } = await validateSchema('validated-only');
|
|
2107
|
+
return results[path] || { errors: [], valid: true };
|
|
2108
|
+
}
|
|
2109
|
+
if (state === null || state === void 0 ? void 0 : state.validate) {
|
|
2110
|
+
return state.validate();
|
|
2095
2111
|
}
|
|
2096
|
-
if (
|
|
2097
|
-
|
|
2112
|
+
if (!state) {
|
|
2113
|
+
vue.warn(`field with path ${path} was not found`);
|
|
2098
2114
|
}
|
|
2099
|
-
return
|
|
2115
|
+
return Promise.resolve({ errors: [], valid: true });
|
|
2100
2116
|
}
|
|
2101
2117
|
function unsetInitialValue(path) {
|
|
2102
2118
|
unsetPath(initialValues.value, path);
|
|
@@ -2105,8 +2121,8 @@
|
|
|
2105
2121
|
* Sneaky function to set initial field values
|
|
2106
2122
|
*/
|
|
2107
2123
|
function stageInitialValue(path, value, updateOriginal = false) {
|
|
2108
|
-
setInPath(formValues, path, value);
|
|
2109
2124
|
setFieldInitialValue(path, value);
|
|
2125
|
+
setInPath(formValues, path, value);
|
|
2110
2126
|
if (updateOriginal && !(opts === null || opts === void 0 ? void 0 : opts.initialValues)) {
|
|
2111
2127
|
setInPath(originalInitialValues.value, path, klona(value));
|
|
2112
2128
|
}
|
|
@@ -2159,12 +2175,95 @@
|
|
|
2159
2175
|
}
|
|
2160
2176
|
// Provide injections
|
|
2161
2177
|
vue.provide(FormContextKey, formCtx);
|
|
2162
|
-
|
|
2178
|
+
function defineComponentBinds(path, config) {
|
|
2179
|
+
const pathState = findPathState(unravel(path)) || createPathState(path);
|
|
2180
|
+
const evalConfig = () => (isCallable(config) ? config(omit(pathState, PRIVATE_PATH_STATE_KEYS)) : config || {});
|
|
2181
|
+
function onBlur() {
|
|
2182
|
+
var _a;
|
|
2183
|
+
pathState.touched = true;
|
|
2184
|
+
const validateOnBlur = (_a = evalConfig().validateOnBlur) !== null && _a !== void 0 ? _a : getConfig().validateOnBlur;
|
|
2185
|
+
if (validateOnBlur) {
|
|
2186
|
+
validateField(pathState.path);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function onUpdateModelValue(value) {
|
|
2190
|
+
var _a;
|
|
2191
|
+
setFieldValue(pathState.path, value);
|
|
2192
|
+
const validateOnModelUpdate = (_a = evalConfig().validateOnModelUpdate) !== null && _a !== void 0 ? _a : getConfig().validateOnModelUpdate;
|
|
2193
|
+
if (validateOnModelUpdate) {
|
|
2194
|
+
validateField(pathState.path);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
const props = vue.computed(() => {
|
|
2198
|
+
const base = {
|
|
2199
|
+
modelValue: pathState.value,
|
|
2200
|
+
'onUpdate:modelValue': onUpdateModelValue,
|
|
2201
|
+
onBlur,
|
|
2202
|
+
};
|
|
2203
|
+
if (isCallable(config)) {
|
|
2204
|
+
return Object.assign(Object.assign({}, base), (config(pathState).props || {}));
|
|
2205
|
+
}
|
|
2206
|
+
if (config === null || config === void 0 ? void 0 : config.mapProps) {
|
|
2207
|
+
return Object.assign(Object.assign({}, base), config.mapProps(omit(pathState, PRIVATE_PATH_STATE_KEYS)));
|
|
2208
|
+
}
|
|
2209
|
+
return base;
|
|
2210
|
+
});
|
|
2211
|
+
return props;
|
|
2212
|
+
}
|
|
2213
|
+
function defineInputBinds(path, config) {
|
|
2214
|
+
const pathState = (findPathState(unravel(path)) || createPathState(path));
|
|
2215
|
+
const evalConfig = () => (isCallable(config) ? config(omit(pathState, PRIVATE_PATH_STATE_KEYS)) : config || {});
|
|
2216
|
+
function onBlur() {
|
|
2217
|
+
var _a;
|
|
2218
|
+
pathState.touched = true;
|
|
2219
|
+
const validateOnBlur = (_a = evalConfig().validateOnBlur) !== null && _a !== void 0 ? _a : getConfig().validateOnBlur;
|
|
2220
|
+
if (validateOnBlur) {
|
|
2221
|
+
validateField(pathState.path);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
function onInput(e) {
|
|
2225
|
+
var _a;
|
|
2226
|
+
const value = normalizeEventValue(e);
|
|
2227
|
+
setFieldValue(pathState.path, value);
|
|
2228
|
+
const validateOnInput = (_a = evalConfig().validateOnInput) !== null && _a !== void 0 ? _a : getConfig().validateOnInput;
|
|
2229
|
+
if (validateOnInput) {
|
|
2230
|
+
validateField(pathState.path);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
function onChange(e) {
|
|
2234
|
+
var _a;
|
|
2235
|
+
const value = normalizeEventValue(e);
|
|
2236
|
+
setFieldValue(pathState.path, value);
|
|
2237
|
+
const validateOnChange = (_a = evalConfig().validateOnChange) !== null && _a !== void 0 ? _a : getConfig().validateOnChange;
|
|
2238
|
+
if (validateOnChange) {
|
|
2239
|
+
validateField(pathState.path);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
const props = vue.computed(() => {
|
|
2243
|
+
const base = {
|
|
2244
|
+
value: pathState.value,
|
|
2245
|
+
onChange,
|
|
2246
|
+
onInput,
|
|
2247
|
+
onBlur,
|
|
2248
|
+
};
|
|
2249
|
+
if (isCallable(config)) {
|
|
2250
|
+
return Object.assign(Object.assign({}, base), (config(omit(pathState, PRIVATE_PATH_STATE_KEYS)).attrs || {}));
|
|
2251
|
+
}
|
|
2252
|
+
if (config === null || config === void 0 ? void 0 : config.mapAttrs) {
|
|
2253
|
+
return Object.assign(Object.assign({}, base), config.mapAttrs(omit(pathState, PRIVATE_PATH_STATE_KEYS)));
|
|
2254
|
+
}
|
|
2255
|
+
return base;
|
|
2256
|
+
});
|
|
2257
|
+
return props;
|
|
2258
|
+
}
|
|
2259
|
+
return Object.assign(Object.assign({}, formCtx), { handleReset: () => resetForm(), submitForm,
|
|
2260
|
+
defineComponentBinds,
|
|
2261
|
+
defineInputBinds });
|
|
2163
2262
|
}
|
|
2164
2263
|
/**
|
|
2165
2264
|
* Manages form meta aggregation
|
|
2166
2265
|
*/
|
|
2167
|
-
function useFormMeta(
|
|
2266
|
+
function useFormMeta(pathsState, currentValues, initialValues, errors) {
|
|
2168
2267
|
const MERGE_STRATEGIES = {
|
|
2169
2268
|
touched: 'some',
|
|
2170
2269
|
pending: 'some',
|
|
@@ -2174,10 +2273,10 @@
|
|
|
2174
2273
|
return !isEqual(currentValues, vue.unref(initialValues));
|
|
2175
2274
|
});
|
|
2176
2275
|
function calculateFlags() {
|
|
2177
|
-
const
|
|
2276
|
+
const states = pathsState.value;
|
|
2178
2277
|
return keysOf(MERGE_STRATEGIES).reduce((acc, flag) => {
|
|
2179
2278
|
const mergeMethod = MERGE_STRATEGIES[flag];
|
|
2180
|
-
acc[flag] =
|
|
2279
|
+
acc[flag] = states[mergeMethod](s => s[flag]);
|
|
2181
2280
|
return acc;
|
|
2182
2281
|
}, {});
|
|
2183
2282
|
}
|
|
@@ -2195,7 +2294,7 @@
|
|
|
2195
2294
|
/**
|
|
2196
2295
|
* Manages the initial values prop
|
|
2197
2296
|
*/
|
|
2198
|
-
function useFormInitialValues(
|
|
2297
|
+
function useFormInitialValues(pathsState, formValues, opts) {
|
|
2199
2298
|
const values = resolveInitialValues(opts);
|
|
2200
2299
|
const providedValues = opts === null || opts === void 0 ? void 0 : opts.initialValues;
|
|
2201
2300
|
// these are the mutable initial values as the fields are mounted/unmounted
|
|
@@ -2216,14 +2315,13 @@
|
|
|
2216
2315
|
// those are excluded because it's unlikely you want to change the form values using initial values
|
|
2217
2316
|
// we mostly watch them for API population or newly inserted fields
|
|
2218
2317
|
// 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) {
|
|
2318
|
+
pathsState.value.forEach(state => {
|
|
2319
|
+
const wasTouched = state.touched;
|
|
2320
|
+
if (wasTouched) {
|
|
2223
2321
|
return;
|
|
2224
2322
|
}
|
|
2225
|
-
const newValue = getFromPath(initialValues.value,
|
|
2226
|
-
setInPath(formValues,
|
|
2323
|
+
const newValue = getFromPath(initialValues.value, state.path);
|
|
2324
|
+
setInPath(formValues, state.path, klona(newValue));
|
|
2227
2325
|
});
|
|
2228
2326
|
}
|
|
2229
2327
|
if (vue.isRef(providedValues)) {
|
|
@@ -2239,42 +2337,6 @@
|
|
|
2239
2337
|
setInitialValues,
|
|
2240
2338
|
};
|
|
2241
2339
|
}
|
|
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
2340
|
|
|
2279
2341
|
const FormImpl = vue.defineComponent({
|
|
2280
2342
|
name: 'Form',
|
|
@@ -2455,7 +2517,10 @@
|
|
|
2455
2517
|
}
|
|
2456
2518
|
function initFields() {
|
|
2457
2519
|
const currentValues = getCurrentValues();
|
|
2458
|
-
|
|
2520
|
+
if (!Array.isArray(currentValues)) {
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
fields.value = currentValues.map((v, idx) => createEntry(v, idx, fields.value));
|
|
2459
2524
|
updateEntryFlags();
|
|
2460
2525
|
}
|
|
2461
2526
|
initFields();
|
|
@@ -2467,7 +2532,13 @@
|
|
|
2467
2532
|
entry.isLast = i === fieldsLength - 1;
|
|
2468
2533
|
}
|
|
2469
2534
|
}
|
|
2470
|
-
function createEntry(value) {
|
|
2535
|
+
function createEntry(value, idx, currentFields) {
|
|
2536
|
+
// Skips the work by returning the current entry if it already exists
|
|
2537
|
+
// This should make the `key` prop stable and doesn't cause more re-renders than needed
|
|
2538
|
+
// The value is computed and should update anyways
|
|
2539
|
+
if (currentFields && !isNullOrUndefined(idx) && currentFields[idx]) {
|
|
2540
|
+
return currentFields[idx];
|
|
2541
|
+
}
|
|
2471
2542
|
const key = entryCounter++;
|
|
2472
2543
|
const entry = {
|
|
2473
2544
|
key,
|
|
@@ -2504,8 +2575,9 @@
|
|
|
2504
2575
|
}
|
|
2505
2576
|
const newValue = [...pathValue];
|
|
2506
2577
|
newValue.splice(idx, 1);
|
|
2507
|
-
|
|
2508
|
-
form
|
|
2578
|
+
const fieldPath = pathName + `[${idx}]`;
|
|
2579
|
+
form.unsetInitialValue(fieldPath);
|
|
2580
|
+
setInPath(form.values, pathName, newValue);
|
|
2509
2581
|
fields.value.splice(idx, 1);
|
|
2510
2582
|
afterMutation();
|
|
2511
2583
|
}
|
|
@@ -2518,8 +2590,8 @@
|
|
|
2518
2590
|
}
|
|
2519
2591
|
const newValue = [...normalizedPathValue];
|
|
2520
2592
|
newValue.push(value);
|
|
2521
|
-
form
|
|
2522
|
-
form
|
|
2593
|
+
form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2594
|
+
setInPath(form.values, pathName, newValue);
|
|
2523
2595
|
fields.value.push(createEntry(value));
|
|
2524
2596
|
afterMutation();
|
|
2525
2597
|
}
|
|
@@ -2538,7 +2610,7 @@
|
|
|
2538
2610
|
const tempEntry = newFields[indexA];
|
|
2539
2611
|
newFields[indexA] = newFields[indexB];
|
|
2540
2612
|
newFields[indexB] = tempEntry;
|
|
2541
|
-
form
|
|
2613
|
+
setInPath(form.values, pathName, newValue);
|
|
2542
2614
|
fields.value = newFields;
|
|
2543
2615
|
updateEntryFlags();
|
|
2544
2616
|
}
|
|
@@ -2552,13 +2624,14 @@
|
|
|
2552
2624
|
const newFields = [...fields.value];
|
|
2553
2625
|
newValue.splice(idx, 0, value);
|
|
2554
2626
|
newFields.splice(idx, 0, createEntry(value));
|
|
2555
|
-
form
|
|
2627
|
+
setInPath(form.values, pathName, newValue);
|
|
2556
2628
|
fields.value = newFields;
|
|
2557
2629
|
afterMutation();
|
|
2558
2630
|
}
|
|
2559
2631
|
function replace(arr) {
|
|
2560
2632
|
const pathName = vue.unref(arrayPath);
|
|
2561
|
-
form
|
|
2633
|
+
form.stageInitialValue(pathName, arr);
|
|
2634
|
+
setInPath(form.values, pathName, arr);
|
|
2562
2635
|
initFields();
|
|
2563
2636
|
afterMutation();
|
|
2564
2637
|
}
|
|
@@ -2568,7 +2641,7 @@
|
|
|
2568
2641
|
if (!Array.isArray(pathValue) || pathValue.length - 1 < idx) {
|
|
2569
2642
|
return;
|
|
2570
2643
|
}
|
|
2571
|
-
form
|
|
2644
|
+
setInPath(form.values, `${pathName}[${idx}]`, value);
|
|
2572
2645
|
form === null || form === void 0 ? void 0 : form.validate({ mode: 'validated-only' });
|
|
2573
2646
|
}
|
|
2574
2647
|
function prepend(value) {
|
|
@@ -2579,8 +2652,8 @@
|
|
|
2579
2652
|
return;
|
|
2580
2653
|
}
|
|
2581
2654
|
const newValue = [value, ...normalizedPathValue];
|
|
2582
|
-
form
|
|
2583
|
-
form
|
|
2655
|
+
form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2656
|
+
setInPath(form.values, pathName, newValue);
|
|
2584
2657
|
fields.value.unshift(createEntry(value));
|
|
2585
2658
|
afterMutation();
|
|
2586
2659
|
}
|
|
@@ -2598,7 +2671,7 @@
|
|
|
2598
2671
|
const movedValue = newValue[oldIdx];
|
|
2599
2672
|
newValue.splice(oldIdx, 1);
|
|
2600
2673
|
newValue.splice(newIdx, 0, movedValue);
|
|
2601
|
-
form
|
|
2674
|
+
setInPath(form.values, pathName, newValue);
|
|
2602
2675
|
fields.value = newFields;
|
|
2603
2676
|
afterMutation();
|
|
2604
2677
|
}
|
|
@@ -2737,17 +2810,13 @@
|
|
|
2737
2810
|
* If a field is dirty or not
|
|
2738
2811
|
*/
|
|
2739
2812
|
function useIsFieldDirty(path) {
|
|
2740
|
-
const
|
|
2741
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2813
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2742
2814
|
return vue.computed(() => {
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
}
|
|
2746
|
-
if (!field) {
|
|
2747
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2815
|
+
var _a, _b;
|
|
2816
|
+
if (!fieldOrPath) {
|
|
2748
2817
|
return false;
|
|
2749
2818
|
}
|
|
2750
|
-
return
|
|
2819
|
+
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
2820
|
});
|
|
2752
2821
|
}
|
|
2753
2822
|
|
|
@@ -2755,17 +2824,13 @@
|
|
|
2755
2824
|
* If a field is touched or not
|
|
2756
2825
|
*/
|
|
2757
2826
|
function useIsFieldTouched(path) {
|
|
2758
|
-
const
|
|
2759
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2827
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2760
2828
|
return vue.computed(() => {
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
}
|
|
2764
|
-
if (!field) {
|
|
2765
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2829
|
+
var _a, _b;
|
|
2830
|
+
if (!fieldOrPath) {
|
|
2766
2831
|
return false;
|
|
2767
2832
|
}
|
|
2768
|
-
return
|
|
2833
|
+
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
2834
|
});
|
|
2770
2835
|
}
|
|
2771
2836
|
|
|
@@ -2773,17 +2838,13 @@
|
|
|
2773
2838
|
* If a field is validated and is valid
|
|
2774
2839
|
*/
|
|
2775
2840
|
function useIsFieldValid(path) {
|
|
2776
|
-
const
|
|
2777
|
-
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2841
|
+
const fieldOrPath = resolveFieldOrPathState(path);
|
|
2778
2842
|
return vue.computed(() => {
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
}
|
|
2782
|
-
if (!field) {
|
|
2783
|
-
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2843
|
+
var _a, _b;
|
|
2844
|
+
if (!fieldOrPath) {
|
|
2784
2845
|
return false;
|
|
2785
2846
|
}
|
|
2786
|
-
return
|
|
2847
|
+
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
2848
|
});
|
|
2788
2849
|
}
|
|
2789
2850
|
|
|
@@ -2806,19 +2867,19 @@
|
|
|
2806
2867
|
*/
|
|
2807
2868
|
function useValidateField(path) {
|
|
2808
2869
|
const form = injectWithSelf(FormContextKey);
|
|
2809
|
-
|
|
2870
|
+
const field = path ? undefined : vue.inject(FieldContextKey);
|
|
2810
2871
|
return function validateField() {
|
|
2811
|
-
if (
|
|
2812
|
-
field
|
|
2872
|
+
if (field) {
|
|
2873
|
+
return field.validate();
|
|
2813
2874
|
}
|
|
2814
|
-
if (
|
|
2815
|
-
|
|
2816
|
-
return Promise.resolve({
|
|
2817
|
-
errors: [],
|
|
2818
|
-
valid: true,
|
|
2819
|
-
});
|
|
2875
|
+
if (form && path) {
|
|
2876
|
+
return form === null || form === void 0 ? void 0 : form.validateField(vue.unref(path));
|
|
2820
2877
|
}
|
|
2821
|
-
|
|
2878
|
+
warn(`field with name ${vue.unref(path)} was not found`);
|
|
2879
|
+
return Promise.resolve({
|
|
2880
|
+
errors: [],
|
|
2881
|
+
valid: true,
|
|
2882
|
+
});
|
|
2822
2883
|
};
|
|
2823
2884
|
}
|
|
2824
2885
|
|