vee-validate 4.4.10 → 4.5.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/CHANGELOG.md +292 -731
- package/dist/vee-validate.d.ts +145 -85
- package/dist/vee-validate.esm.js +1032 -350
- package/dist/vee-validate.js +638 -348
- package/dist/vee-validate.min.js +2 -2
- package/package.json +5 -2
package/dist/vee-validate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vee-validate v4.
|
|
2
|
+
* vee-validate v4.5.0
|
|
3
3
|
* (c) 2021 Abdelrahman Awad
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
@@ -50,8 +50,6 @@
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const FormContextKey = Symbol('vee-validate-form');
|
|
53
|
-
const FormErrorsKey = Symbol('vee-validate-form-errors');
|
|
54
|
-
const FormInitialValuesKey = Symbol('vee-validate-form-initial-values');
|
|
55
53
|
const FieldContextKey = Symbol('vee-validate-field-instance');
|
|
56
54
|
const IS_ABSENT = Symbol('Default empty value');
|
|
57
55
|
|
|
@@ -151,17 +149,14 @@
|
|
|
151
149
|
}
|
|
152
150
|
return path;
|
|
153
151
|
}
|
|
154
|
-
|
|
155
|
-
* Gets a nested property value from an object
|
|
156
|
-
*/
|
|
157
|
-
function getFromPath(object, path, fallback = undefined) {
|
|
152
|
+
function getFromPath(object, path, fallback) {
|
|
158
153
|
if (!object) {
|
|
159
154
|
return fallback;
|
|
160
155
|
}
|
|
161
156
|
if (isNotNestedPath(path)) {
|
|
162
157
|
return object[cleanupNonNestedPath(path)];
|
|
163
158
|
}
|
|
164
|
-
const resolvedValue = path
|
|
159
|
+
const resolvedValue = (path || '')
|
|
165
160
|
.split(/\.|\[(\d+)\]/)
|
|
166
161
|
.filter(Boolean)
|
|
167
162
|
.reduce((acc, propKey) => {
|
|
@@ -265,20 +260,6 @@
|
|
|
265
260
|
}
|
|
266
261
|
return field;
|
|
267
262
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Applies a mutation function on a field or field group
|
|
270
|
-
*/
|
|
271
|
-
function applyFieldMutation(field, mutation, onlyFirst = false) {
|
|
272
|
-
if (!Array.isArray(field)) {
|
|
273
|
-
mutation(field);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
if (onlyFirst) {
|
|
277
|
-
mutation(field[0]);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
field.forEach(mutation);
|
|
281
|
-
}
|
|
282
263
|
function resolveNextCheckboxValue(currentValue, checkedValue, uncheckedValue) {
|
|
283
264
|
if (Array.isArray(currentValue)) {
|
|
284
265
|
const newVal = [...currentValue];
|
|
@@ -287,6 +268,24 @@
|
|
|
287
268
|
return newVal;
|
|
288
269
|
}
|
|
289
270
|
return currentValue === checkedValue ? uncheckedValue : checkedValue;
|
|
271
|
+
}
|
|
272
|
+
function debounceAsync(inner, ms = 0) {
|
|
273
|
+
let timer = null;
|
|
274
|
+
let resolves = [];
|
|
275
|
+
return function (...args) {
|
|
276
|
+
// Run the function after a certain amount of time
|
|
277
|
+
if (timer) {
|
|
278
|
+
window.clearTimeout(timer);
|
|
279
|
+
}
|
|
280
|
+
timer = window.setTimeout(() => {
|
|
281
|
+
// Get the result of the inner function, then apply it to the resolve function of
|
|
282
|
+
// each promise that has been created since the last time the inner function was run
|
|
283
|
+
const result = inner(...args);
|
|
284
|
+
resolves.forEach(r => r(result));
|
|
285
|
+
resolves = [];
|
|
286
|
+
}, ms);
|
|
287
|
+
return new Promise(resolve => resolves.push(resolve));
|
|
288
|
+
};
|
|
290
289
|
}
|
|
291
290
|
|
|
292
291
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -777,21 +776,162 @@
|
|
|
777
776
|
};
|
|
778
777
|
|
|
779
778
|
let ID_COUNTER = 0;
|
|
779
|
+
function useFieldState(path, init) {
|
|
780
|
+
const { value, initialValue, setInitialValue } = _useFieldValue(path, init.modelValue, !init.standalone);
|
|
781
|
+
const { errorMessage, errors, setErrors } = _useFieldErrors(path, !init.standalone);
|
|
782
|
+
const meta = _useFieldMeta(value, initialValue, errors);
|
|
783
|
+
const id = ID_COUNTER >= Number.MAX_SAFE_INTEGER ? 0 : ++ID_COUNTER;
|
|
784
|
+
function setState(state) {
|
|
785
|
+
var _a;
|
|
786
|
+
if ('value' in state) {
|
|
787
|
+
value.value = state.value;
|
|
788
|
+
}
|
|
789
|
+
if ('errors' in state) {
|
|
790
|
+
setErrors(state.errors);
|
|
791
|
+
}
|
|
792
|
+
if ('touched' in state) {
|
|
793
|
+
meta.touched = (_a = state.touched) !== null && _a !== void 0 ? _a : meta.touched;
|
|
794
|
+
}
|
|
795
|
+
if ('initialValue' in state) {
|
|
796
|
+
setInitialValue(state.initialValue);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
id,
|
|
801
|
+
path,
|
|
802
|
+
value,
|
|
803
|
+
initialValue,
|
|
804
|
+
meta,
|
|
805
|
+
errors,
|
|
806
|
+
errorMessage,
|
|
807
|
+
setState,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Creates the field value and resolves the initial value
|
|
812
|
+
*/
|
|
813
|
+
function _useFieldValue(path, modelValue, shouldInjectForm) {
|
|
814
|
+
const form = shouldInjectForm ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
815
|
+
const modelRef = vue.ref(vue.unref(modelValue));
|
|
816
|
+
function resolveInitialValue() {
|
|
817
|
+
if (!form) {
|
|
818
|
+
return vue.unref(modelRef);
|
|
819
|
+
}
|
|
820
|
+
return getFromPath(form.meta.value.initialValues, vue.unref(path), vue.unref(modelRef));
|
|
821
|
+
}
|
|
822
|
+
function setInitialValue(value) {
|
|
823
|
+
if (!form) {
|
|
824
|
+
modelRef.value = value;
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
form.setFieldInitialValue(vue.unref(path), value);
|
|
828
|
+
}
|
|
829
|
+
const initialValue = vue.computed(resolveInitialValue);
|
|
830
|
+
// if no form is associated, use a regular ref.
|
|
831
|
+
if (!form) {
|
|
832
|
+
const value = vue.ref(resolveInitialValue());
|
|
833
|
+
return {
|
|
834
|
+
value,
|
|
835
|
+
initialValue,
|
|
836
|
+
setInitialValue,
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
// to set the initial value, first check if there is a current value, if there is then use it.
|
|
840
|
+
// otherwise use the configured initial value if it exists.
|
|
841
|
+
// prioritize model value over form values
|
|
842
|
+
// #3429
|
|
843
|
+
const currentValue = modelValue ? vue.unref(modelValue) : getFromPath(form.values, vue.unref(path), vue.unref(initialValue));
|
|
844
|
+
form.stageInitialValue(vue.unref(path), currentValue);
|
|
845
|
+
// otherwise use a computed setter that triggers the `setFieldValue`
|
|
846
|
+
const value = vue.computed({
|
|
847
|
+
get() {
|
|
848
|
+
return getFromPath(form.values, vue.unref(path));
|
|
849
|
+
},
|
|
850
|
+
set(newVal) {
|
|
851
|
+
form.setFieldValue(vue.unref(path), newVal);
|
|
852
|
+
},
|
|
853
|
+
});
|
|
854
|
+
return {
|
|
855
|
+
value,
|
|
856
|
+
initialValue,
|
|
857
|
+
setInitialValue,
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Creates meta flags state and some associated effects with them
|
|
862
|
+
*/
|
|
863
|
+
function _useFieldMeta(currentValue, initialValue, errors) {
|
|
864
|
+
const meta = vue.reactive({
|
|
865
|
+
touched: false,
|
|
866
|
+
pending: false,
|
|
867
|
+
valid: true,
|
|
868
|
+
validated: !!vue.unref(errors).length,
|
|
869
|
+
initialValue: vue.computed(() => vue.unref(initialValue)),
|
|
870
|
+
dirty: vue.computed(() => {
|
|
871
|
+
return !es6(vue.unref(currentValue), vue.unref(initialValue));
|
|
872
|
+
}),
|
|
873
|
+
});
|
|
874
|
+
vue.watch(errors, value => {
|
|
875
|
+
meta.valid = !value.length;
|
|
876
|
+
}, {
|
|
877
|
+
immediate: true,
|
|
878
|
+
flush: 'sync',
|
|
879
|
+
});
|
|
880
|
+
return meta;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Creates the error message state for the field state
|
|
884
|
+
*/
|
|
885
|
+
function _useFieldErrors(path, shouldInjectForm) {
|
|
886
|
+
const form = shouldInjectForm ? injectWithSelf(FormContextKey, undefined) : undefined;
|
|
887
|
+
function normalizeErrors(messages) {
|
|
888
|
+
if (!messages) {
|
|
889
|
+
return [];
|
|
890
|
+
}
|
|
891
|
+
return Array.isArray(messages) ? messages : [messages];
|
|
892
|
+
}
|
|
893
|
+
if (!form) {
|
|
894
|
+
const errors = vue.ref([]);
|
|
895
|
+
return {
|
|
896
|
+
errors,
|
|
897
|
+
errorMessage: vue.computed(() => errors.value[0]),
|
|
898
|
+
setErrors: (messages) => {
|
|
899
|
+
errors.value = normalizeErrors(messages);
|
|
900
|
+
},
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
const errors = vue.computed(() => form.errorBag.value[vue.unref(path)] || []);
|
|
904
|
+
return {
|
|
905
|
+
errors,
|
|
906
|
+
errorMessage: vue.computed(() => errors.value[0]),
|
|
907
|
+
setErrors: (messages) => {
|
|
908
|
+
form.setFieldErrorBag(vue.unref(path), normalizeErrors(messages));
|
|
909
|
+
},
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
|
|
780
913
|
/**
|
|
781
914
|
* Creates a field composite.
|
|
782
915
|
*/
|
|
783
916
|
function useField(name, rules, opts) {
|
|
784
|
-
|
|
785
|
-
|
|
917
|
+
if (hasCheckedAttr(opts === null || opts === void 0 ? void 0 : opts.type)) {
|
|
918
|
+
return useCheckboxField(name, rules, opts);
|
|
919
|
+
}
|
|
920
|
+
return _useField(name, rules, opts);
|
|
921
|
+
}
|
|
922
|
+
function _useField(name, rules, opts) {
|
|
923
|
+
const { initialValue: modelValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue, standalone, } = normalizeOptions(vue.unref(name), opts);
|
|
786
924
|
const form = !standalone ? injectWithSelf(FormContextKey) : undefined;
|
|
787
|
-
const {
|
|
788
|
-
|
|
789
|
-
initValue: initialValue,
|
|
790
|
-
form,
|
|
791
|
-
type,
|
|
792
|
-
checkedValue,
|
|
925
|
+
const { id, value, initialValue, meta, setState, errors, errorMessage } = useFieldState(name, {
|
|
926
|
+
modelValue,
|
|
793
927
|
standalone,
|
|
794
928
|
});
|
|
929
|
+
/**
|
|
930
|
+
* Handles common onBlur meta update
|
|
931
|
+
*/
|
|
932
|
+
const handleBlur = () => {
|
|
933
|
+
meta.touched = true;
|
|
934
|
+
};
|
|
795
935
|
const normalizedRules = vue.computed(() => {
|
|
796
936
|
let rulesValue = vue.unref(rules);
|
|
797
937
|
const schema = vue.unref(form === null || form === void 0 ? void 0 : form.schema);
|
|
@@ -818,27 +958,30 @@
|
|
|
818
958
|
meta.pending = true;
|
|
819
959
|
meta.validated = true;
|
|
820
960
|
const result = await validateCurrentValue('validated-only');
|
|
961
|
+
setState({ errors: result.errors });
|
|
821
962
|
meta.pending = false;
|
|
822
|
-
return
|
|
963
|
+
return result;
|
|
823
964
|
}
|
|
824
965
|
async function validateValidStateOnly() {
|
|
825
966
|
const result = await validateCurrentValue('silent');
|
|
826
967
|
meta.valid = result.valid;
|
|
968
|
+
return result;
|
|
827
969
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
if (checked && checked.value === ((_b = (_a = e) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.checked)) {
|
|
832
|
-
return;
|
|
970
|
+
function validate$1(opts) {
|
|
971
|
+
if (!(opts === null || opts === void 0 ? void 0 : opts.mode) || (opts === null || opts === void 0 ? void 0 : opts.mode) === 'force') {
|
|
972
|
+
return validateWithStateMutation();
|
|
833
973
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
if (checked && type === 'checkbox' && !form) {
|
|
837
|
-
newValue = resolveNextCheckboxValue(value.value, vue.unref(checkedValue), vue.unref(uncheckedValue));
|
|
974
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.mode) === 'validated-only') {
|
|
975
|
+
return validateWithStateMutation();
|
|
838
976
|
}
|
|
977
|
+
return validateValidStateOnly();
|
|
978
|
+
}
|
|
979
|
+
// Common input/change event handler
|
|
980
|
+
const handleChange = (e, shouldValidate = true) => {
|
|
981
|
+
const newValue = normalizeEventValue(e);
|
|
839
982
|
value.value = newValue;
|
|
840
983
|
if (!validateOnValueUpdate && shouldValidate) {
|
|
841
|
-
|
|
984
|
+
validateWithStateMutation();
|
|
842
985
|
}
|
|
843
986
|
};
|
|
844
987
|
// Runs the initial validation
|
|
@@ -863,17 +1006,31 @@
|
|
|
863
1006
|
}
|
|
864
1007
|
watchValue();
|
|
865
1008
|
function resetField(state) {
|
|
1009
|
+
var _a;
|
|
866
1010
|
unwatchValue === null || unwatchValue === void 0 ? void 0 : unwatchValue();
|
|
867
|
-
|
|
1011
|
+
const newValue = state && 'value' in state ? state.value : initialValue.value;
|
|
1012
|
+
setState({
|
|
1013
|
+
value: klona(newValue),
|
|
1014
|
+
initialValue: klona(newValue),
|
|
1015
|
+
touched: (_a = state === null || state === void 0 ? void 0 : state.touched) !== null && _a !== void 0 ? _a : false,
|
|
1016
|
+
errors: (state === null || state === void 0 ? void 0 : state.errors) || [],
|
|
1017
|
+
});
|
|
1018
|
+
meta.pending = false;
|
|
1019
|
+
meta.validated = false;
|
|
868
1020
|
validateValidStateOnly();
|
|
869
1021
|
// need to watch at next tick to avoid triggering the value watcher
|
|
870
1022
|
vue.nextTick(() => {
|
|
871
1023
|
watchValue();
|
|
872
1024
|
});
|
|
873
1025
|
}
|
|
1026
|
+
function setValue(newValue) {
|
|
1027
|
+
value.value = newValue;
|
|
1028
|
+
}
|
|
1029
|
+
function setErrors(errors) {
|
|
1030
|
+
setState({ errors: Array.isArray(errors) ? errors : [errors] });
|
|
1031
|
+
}
|
|
874
1032
|
const field = {
|
|
875
|
-
|
|
876
|
-
fid,
|
|
1033
|
+
id,
|
|
877
1034
|
name,
|
|
878
1035
|
label,
|
|
879
1036
|
value,
|
|
@@ -883,17 +1040,16 @@
|
|
|
883
1040
|
type,
|
|
884
1041
|
checkedValue,
|
|
885
1042
|
uncheckedValue,
|
|
886
|
-
checked,
|
|
887
1043
|
bails,
|
|
888
1044
|
resetField,
|
|
889
1045
|
handleReset: () => resetField(),
|
|
890
|
-
validate:
|
|
1046
|
+
validate: validate$1,
|
|
891
1047
|
handleChange,
|
|
892
1048
|
handleBlur,
|
|
893
|
-
|
|
894
|
-
setValidationState,
|
|
1049
|
+
setState,
|
|
895
1050
|
setTouched,
|
|
896
1051
|
setErrors,
|
|
1052
|
+
setValue,
|
|
897
1053
|
};
|
|
898
1054
|
vue.provide(FieldContextKey, field);
|
|
899
1055
|
if (vue.isRef(rules) && typeof vue.unref(rules) !== 'function') {
|
|
@@ -901,7 +1057,7 @@
|
|
|
901
1057
|
if (es6(value, oldValue)) {
|
|
902
1058
|
return;
|
|
903
1059
|
}
|
|
904
|
-
|
|
1060
|
+
meta.validated ? validateWithStateMutation() : validateValidStateOnly();
|
|
905
1061
|
}, {
|
|
906
1062
|
deep: true,
|
|
907
1063
|
});
|
|
@@ -944,7 +1100,7 @@
|
|
|
944
1100
|
}
|
|
945
1101
|
const shouldValidate = !es6(deps, oldDeps);
|
|
946
1102
|
if (shouldValidate) {
|
|
947
|
-
meta.
|
|
1103
|
+
meta.validated ? validateWithStateMutation() : validateValidStateOnly();
|
|
948
1104
|
}
|
|
949
1105
|
});
|
|
950
1106
|
return field;
|
|
@@ -969,104 +1125,6 @@
|
|
|
969
1125
|
const checkedValue = 'valueProp' in opts ? opts.valueProp : opts.checkedValue;
|
|
970
1126
|
return Object.assign(Object.assign(Object.assign({}, defaults()), (opts || {})), { checkedValue });
|
|
971
1127
|
}
|
|
972
|
-
/**
|
|
973
|
-
* Manages the validation state of a field.
|
|
974
|
-
*/
|
|
975
|
-
function useValidationState({ name, initValue, form, type, checkedValue, standalone, }) {
|
|
976
|
-
const { errors, errorMessage, setErrors } = useFieldErrors(name, form);
|
|
977
|
-
const formInitialValues = standalone ? undefined : injectWithSelf(FormInitialValuesKey, undefined);
|
|
978
|
-
// clones the ref value to a mutable version
|
|
979
|
-
const initialValueRef = vue.ref(vue.unref(initValue));
|
|
980
|
-
const initialValue = vue.computed(() => {
|
|
981
|
-
return getFromPath(vue.unref(formInitialValues), vue.unref(name), vue.unref(initialValueRef));
|
|
982
|
-
});
|
|
983
|
-
const value = useFieldValue$1(initialValue, name, form);
|
|
984
|
-
const meta = useFieldMeta(initialValue, value, errors);
|
|
985
|
-
const checked = hasCheckedAttr(type)
|
|
986
|
-
? vue.computed(() => {
|
|
987
|
-
if (Array.isArray(value.value)) {
|
|
988
|
-
return value.value.includes(vue.unref(checkedValue));
|
|
989
|
-
}
|
|
990
|
-
return vue.unref(checkedValue) === value.value;
|
|
991
|
-
})
|
|
992
|
-
: undefined;
|
|
993
|
-
/**
|
|
994
|
-
* Handles common onBlur meta update
|
|
995
|
-
*/
|
|
996
|
-
const handleBlur = () => {
|
|
997
|
-
meta.touched = true;
|
|
998
|
-
};
|
|
999
|
-
/**
|
|
1000
|
-
* Handles common on blur events
|
|
1001
|
-
* @deprecated You should use `handleChange` instead
|
|
1002
|
-
*/
|
|
1003
|
-
const handleInput = (e) => {
|
|
1004
|
-
// Checkboxes/Radio will emit a `change` event anyway, custom components will use `update:modelValue`
|
|
1005
|
-
// so this is redundant
|
|
1006
|
-
if (!hasCheckedAttr(type)) {
|
|
1007
|
-
value.value = normalizeEventValue(e);
|
|
1008
|
-
}
|
|
1009
|
-
};
|
|
1010
|
-
// Updates the validation state with the validation result
|
|
1011
|
-
function setValidationState(result) {
|
|
1012
|
-
setErrors(result.errors);
|
|
1013
|
-
return result;
|
|
1014
|
-
}
|
|
1015
|
-
// Resets the validation state
|
|
1016
|
-
function resetValidationState(state) {
|
|
1017
|
-
var _a;
|
|
1018
|
-
const fieldPath = vue.unref(name);
|
|
1019
|
-
const newValue = state && 'value' in state
|
|
1020
|
-
? state.value
|
|
1021
|
-
: getFromPath(vue.unref(formInitialValues), fieldPath, vue.unref(initValue));
|
|
1022
|
-
if (form) {
|
|
1023
|
-
form.setFieldValue(fieldPath, newValue, { force: true });
|
|
1024
|
-
form.setFieldInitialValue(fieldPath, newValue);
|
|
1025
|
-
}
|
|
1026
|
-
else {
|
|
1027
|
-
value.value = klona(newValue);
|
|
1028
|
-
initialValueRef.value = klona(newValue);
|
|
1029
|
-
}
|
|
1030
|
-
setErrors((state === null || state === void 0 ? void 0 : state.errors) || []);
|
|
1031
|
-
meta.touched = (_a = state === null || state === void 0 ? void 0 : state.touched) !== null && _a !== void 0 ? _a : false;
|
|
1032
|
-
meta.pending = false;
|
|
1033
|
-
meta.validated = false;
|
|
1034
|
-
}
|
|
1035
|
-
return {
|
|
1036
|
-
meta,
|
|
1037
|
-
errors,
|
|
1038
|
-
errorMessage,
|
|
1039
|
-
setErrors,
|
|
1040
|
-
setValidationState,
|
|
1041
|
-
resetValidationState,
|
|
1042
|
-
handleBlur,
|
|
1043
|
-
handleInput,
|
|
1044
|
-
value,
|
|
1045
|
-
checked,
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
* Exposes meta flags state and some associated actions with them.
|
|
1050
|
-
*/
|
|
1051
|
-
function useFieldMeta(initialValue, currentValue, errors) {
|
|
1052
|
-
const meta = vue.reactive({
|
|
1053
|
-
touched: false,
|
|
1054
|
-
pending: false,
|
|
1055
|
-
valid: true,
|
|
1056
|
-
validated: !!vue.unref(errors).length,
|
|
1057
|
-
initialValue: vue.computed(() => vue.unref(initialValue)),
|
|
1058
|
-
dirty: vue.computed(() => {
|
|
1059
|
-
return !es6(vue.unref(currentValue), vue.unref(initialValue));
|
|
1060
|
-
}),
|
|
1061
|
-
});
|
|
1062
|
-
vue.watch(errors, value => {
|
|
1063
|
-
meta.valid = !value.length;
|
|
1064
|
-
}, {
|
|
1065
|
-
immediate: true,
|
|
1066
|
-
flush: 'sync',
|
|
1067
|
-
});
|
|
1068
|
-
return meta;
|
|
1069
|
-
}
|
|
1070
1128
|
/**
|
|
1071
1129
|
* Extracts the validation rules from a schema
|
|
1072
1130
|
*/
|
|
@@ -1078,49 +1136,40 @@
|
|
|
1078
1136
|
// there is a key on the schema object for this field
|
|
1079
1137
|
return schema[fieldName];
|
|
1080
1138
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
},
|
|
1114
|
-
};
|
|
1139
|
+
function useCheckboxField(name, rules, opts) {
|
|
1140
|
+
const form = !(opts === null || opts === void 0 ? void 0 : opts.standalone) ? injectWithSelf(FormContextKey) : undefined;
|
|
1141
|
+
const checkedValue = opts === null || opts === void 0 ? void 0 : opts.checkedValue;
|
|
1142
|
+
const uncheckedValue = opts === null || opts === void 0 ? void 0 : opts.uncheckedValue;
|
|
1143
|
+
function patchCheckboxApi(field) {
|
|
1144
|
+
const handleChange = field.handleChange;
|
|
1145
|
+
const checked = vue.computed(() => {
|
|
1146
|
+
const currentValue = vue.unref(field.value);
|
|
1147
|
+
const checkedVal = vue.unref(checkedValue);
|
|
1148
|
+
return Array.isArray(currentValue) ? currentValue.includes(checkedVal) : checkedVal === currentValue;
|
|
1149
|
+
});
|
|
1150
|
+
function handleCheckboxChange(e, shouldValidate = true) {
|
|
1151
|
+
var _a, _b;
|
|
1152
|
+
if (checked.value === ((_b = (_a = e) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.checked)) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
let newValue = normalizeEventValue(e);
|
|
1156
|
+
// Single checkbox field without a form to toggle it's value
|
|
1157
|
+
if (!form) {
|
|
1158
|
+
newValue = resolveNextCheckboxValue(vue.unref(field.value), vue.unref(checkedValue), vue.unref(uncheckedValue));
|
|
1159
|
+
}
|
|
1160
|
+
handleChange(newValue, shouldValidate);
|
|
1161
|
+
}
|
|
1162
|
+
vue.onBeforeUnmount(() => {
|
|
1163
|
+
// toggles the checkbox value if it was checked
|
|
1164
|
+
if (checked.value) {
|
|
1165
|
+
handleCheckboxChange(vue.unref(checkedValue), false);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
return Object.assign(Object.assign({}, field), { checked,
|
|
1169
|
+
checkedValue,
|
|
1170
|
+
uncheckedValue, handleChange: handleCheckboxChange });
|
|
1115
1171
|
}
|
|
1116
|
-
|
|
1117
|
-
return {
|
|
1118
|
-
errors,
|
|
1119
|
-
errorMessage: vue.computed(() => errors.value[0]),
|
|
1120
|
-
setErrors: (messages) => {
|
|
1121
|
-
form.setFieldErrorBag(vue.unref(path), messages);
|
|
1122
|
-
},
|
|
1123
|
-
};
|
|
1172
|
+
return patchCheckboxApi(_useField(name, rules, opts));
|
|
1124
1173
|
}
|
|
1125
1174
|
|
|
1126
1175
|
const Field = vue.defineComponent({
|
|
@@ -1194,7 +1243,7 @@
|
|
|
1194
1243
|
const label = vue.toRef(props, 'label');
|
|
1195
1244
|
const uncheckedValue = vue.toRef(props, 'uncheckedValue');
|
|
1196
1245
|
const hasModelEvents = isPropPresent(props, 'onUpdate:modelValue');
|
|
1197
|
-
const { errors, value, errorMessage, validate: validateField, handleChange, handleBlur,
|
|
1246
|
+
const { errors, value, errorMessage, validate: validateField, handleChange, handleBlur, setTouched, resetField, handleReset, meta, checked, setErrors, } = useField(name, rules, {
|
|
1198
1247
|
validateOnMount: props.validateOnMount,
|
|
1199
1248
|
bails: props.bails,
|
|
1200
1249
|
standalone: props.standalone,
|
|
@@ -1213,8 +1262,13 @@
|
|
|
1213
1262
|
ctx.emit('update:modelValue', value.value);
|
|
1214
1263
|
}
|
|
1215
1264
|
: handleChange;
|
|
1265
|
+
const handleInput = (e) => {
|
|
1266
|
+
if (!hasCheckedAttr(ctx.attrs.type)) {
|
|
1267
|
+
value.value = normalizeEventValue(e);
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1216
1270
|
const onInputHandler = hasModelEvents
|
|
1217
|
-
? function
|
|
1271
|
+
? function handleInputWithModel(e) {
|
|
1218
1272
|
handleInput(e);
|
|
1219
1273
|
ctx.emit('update:modelValue', value.value);
|
|
1220
1274
|
}
|
|
@@ -1273,6 +1327,13 @@
|
|
|
1273
1327
|
setErrors,
|
|
1274
1328
|
};
|
|
1275
1329
|
}
|
|
1330
|
+
ctx.expose({
|
|
1331
|
+
setErrors,
|
|
1332
|
+
setTouched,
|
|
1333
|
+
reset: resetField,
|
|
1334
|
+
validate: validateField,
|
|
1335
|
+
handleChange,
|
|
1336
|
+
});
|
|
1276
1337
|
return () => {
|
|
1277
1338
|
const tag = vue.resolveDynamicComponent(resolveTag(props, ctx));
|
|
1278
1339
|
const children = normalizeChildren(tag, ctx, slotProps);
|
|
@@ -1315,40 +1376,19 @@
|
|
|
1315
1376
|
return isPropPresent(props, 'modelValue') ? props.modelValue : undefined;
|
|
1316
1377
|
}
|
|
1317
1378
|
|
|
1379
|
+
let FORM_COUNTER = 0;
|
|
1318
1380
|
function useForm(opts) {
|
|
1319
|
-
|
|
1320
|
-
|
|
1381
|
+
const formId = FORM_COUNTER++;
|
|
1382
|
+
// A lookup containing fields or field groups
|
|
1383
|
+
const fieldsByPath = vue.ref({});
|
|
1321
1384
|
// If the form is currently submitting
|
|
1322
1385
|
const isSubmitting = vue.ref(false);
|
|
1323
|
-
// a field map object useful for faster access of fields
|
|
1324
|
-
const fieldsById = vue.computed(() => {
|
|
1325
|
-
return fields.value.reduce((acc, field) => {
|
|
1326
|
-
const fieldPath = vue.unref(field.name);
|
|
1327
|
-
// if the field was not added before
|
|
1328
|
-
if (!acc[fieldPath]) {
|
|
1329
|
-
acc[fieldPath] = field;
|
|
1330
|
-
field.idx = -1;
|
|
1331
|
-
return acc;
|
|
1332
|
-
}
|
|
1333
|
-
// if the same name is detected
|
|
1334
|
-
const existingField = acc[fieldPath];
|
|
1335
|
-
if (!Array.isArray(existingField)) {
|
|
1336
|
-
existingField.idx = 0;
|
|
1337
|
-
acc[fieldPath] = [existingField];
|
|
1338
|
-
}
|
|
1339
|
-
const fieldGroup = acc[fieldPath];
|
|
1340
|
-
field.idx = fieldGroup.length;
|
|
1341
|
-
fieldGroup.push(field);
|
|
1342
|
-
return acc;
|
|
1343
|
-
}, {});
|
|
1344
|
-
});
|
|
1345
1386
|
// The number of times the user tried to submit the form
|
|
1346
1387
|
const submitCount = vue.ref(0);
|
|
1388
|
+
// dictionary for field arrays to receive various signals like reset
|
|
1389
|
+
const fieldArraysLookup = {};
|
|
1347
1390
|
// a private ref for all form values
|
|
1348
1391
|
const formValues = vue.reactive(klona(vue.unref(opts === null || opts === void 0 ? void 0 : opts.initialValues) || {}));
|
|
1349
|
-
// a lookup to keep track of values by their field ids
|
|
1350
|
-
// this is important because later we need it if fields swap names
|
|
1351
|
-
const valuesByFid = {};
|
|
1352
1392
|
// the source of errors for the form fields
|
|
1353
1393
|
const { errorBag, setErrorBag, setFieldErrorBag } = useErrorBag(opts === null || opts === void 0 ? void 0 : opts.initialErrors);
|
|
1354
1394
|
// Gets the first error of each field
|
|
@@ -1361,12 +1401,19 @@
|
|
|
1361
1401
|
return acc;
|
|
1362
1402
|
}, {});
|
|
1363
1403
|
});
|
|
1404
|
+
function getFirstFieldAtPath(path) {
|
|
1405
|
+
const fieldOrGroup = fieldsByPath.value[path];
|
|
1406
|
+
return Array.isArray(fieldOrGroup) ? fieldOrGroup[0] : fieldOrGroup;
|
|
1407
|
+
}
|
|
1408
|
+
function fieldExists(path) {
|
|
1409
|
+
return !!fieldsByPath.value[path];
|
|
1410
|
+
}
|
|
1364
1411
|
/**
|
|
1365
1412
|
* Holds a computed reference to all fields names and labels
|
|
1366
1413
|
*/
|
|
1367
1414
|
const fieldNames = vue.computed(() => {
|
|
1368
|
-
return keysOf(
|
|
1369
|
-
const field =
|
|
1415
|
+
return keysOf(fieldsByPath.value).reduce((names, path) => {
|
|
1416
|
+
const field = getFirstFieldAtPath(path);
|
|
1370
1417
|
if (field) {
|
|
1371
1418
|
names[path] = vue.unref(field.label || field.name) || '';
|
|
1372
1419
|
}
|
|
@@ -1374,9 +1421,9 @@
|
|
|
1374
1421
|
}, {});
|
|
1375
1422
|
});
|
|
1376
1423
|
const fieldBailsMap = vue.computed(() => {
|
|
1377
|
-
return keysOf(
|
|
1424
|
+
return keysOf(fieldsByPath.value).reduce((map, path) => {
|
|
1378
1425
|
var _a;
|
|
1379
|
-
const field =
|
|
1426
|
+
const field = getFirstFieldAtPath(path);
|
|
1380
1427
|
if (field) {
|
|
1381
1428
|
map[path] = (_a = field.bails) !== null && _a !== void 0 ? _a : true;
|
|
1382
1429
|
}
|
|
@@ -1387,18 +1434,21 @@
|
|
|
1387
1434
|
// we need this to process initial errors then unset them
|
|
1388
1435
|
const initialErrors = Object.assign({}, ((opts === null || opts === void 0 ? void 0 : opts.initialErrors) || {}));
|
|
1389
1436
|
// initial form values
|
|
1390
|
-
const {
|
|
1437
|
+
const { initialValues, originalInitialValues, setInitialValues } = useFormInitialValues(fieldsByPath, formValues, opts === null || opts === void 0 ? void 0 : opts.initialValues);
|
|
1391
1438
|
// form meta aggregations
|
|
1392
|
-
const meta = useFormMeta(
|
|
1439
|
+
const meta = useFormMeta(fieldsByPath, formValues, initialValues, errors);
|
|
1393
1440
|
const schema = opts === null || opts === void 0 ? void 0 : opts.validationSchema;
|
|
1394
1441
|
const formCtx = {
|
|
1395
|
-
|
|
1442
|
+
formId,
|
|
1443
|
+
fieldsByPath,
|
|
1396
1444
|
values: formValues,
|
|
1397
1445
|
errorBag,
|
|
1446
|
+
errors,
|
|
1398
1447
|
schema,
|
|
1399
1448
|
submitCount,
|
|
1400
1449
|
meta,
|
|
1401
1450
|
isSubmitting,
|
|
1451
|
+
fieldArraysLookup,
|
|
1402
1452
|
validateSchema: vue.unref(schema) ? validateSchema : undefined,
|
|
1403
1453
|
validate,
|
|
1404
1454
|
register: registerField,
|
|
@@ -1414,8 +1464,18 @@
|
|
|
1414
1464
|
resetForm,
|
|
1415
1465
|
handleSubmit,
|
|
1416
1466
|
stageInitialValue,
|
|
1467
|
+
unsetInitialValue,
|
|
1417
1468
|
setFieldInitialValue,
|
|
1418
1469
|
};
|
|
1470
|
+
function isFieldGroup(fieldOrGroup) {
|
|
1471
|
+
return Array.isArray(fieldOrGroup);
|
|
1472
|
+
}
|
|
1473
|
+
function applyFieldMutation(fieldOrGroup, mutation) {
|
|
1474
|
+
if (Array.isArray(fieldOrGroup)) {
|
|
1475
|
+
return fieldOrGroup.forEach(mutation);
|
|
1476
|
+
}
|
|
1477
|
+
return mutation(fieldOrGroup);
|
|
1478
|
+
}
|
|
1419
1479
|
/**
|
|
1420
1480
|
* Manually sets an error message on a specific field
|
|
1421
1481
|
*/
|
|
@@ -1433,7 +1493,7 @@
|
|
|
1433
1493
|
*/
|
|
1434
1494
|
function setFieldValue(field, value, { force } = { force: false }) {
|
|
1435
1495
|
var _a;
|
|
1436
|
-
const fieldInstance =
|
|
1496
|
+
const fieldInstance = fieldsByPath.value[field];
|
|
1437
1497
|
const clonedValue = klona(value);
|
|
1438
1498
|
// field wasn't found, create a virtual field as a placeholder
|
|
1439
1499
|
if (!fieldInstance) {
|
|
@@ -1441,28 +1501,17 @@
|
|
|
1441
1501
|
return;
|
|
1442
1502
|
}
|
|
1443
1503
|
// Multiple checkboxes, and only one of them got updated
|
|
1444
|
-
if (
|
|
1445
|
-
const
|
|
1446
|
-
setInPath(formValues, field,
|
|
1447
|
-
fieldInstance.forEach(fieldItem => {
|
|
1448
|
-
valuesByFid[fieldItem.fid] = newVal;
|
|
1449
|
-
});
|
|
1504
|
+
if (isFieldGroup(fieldInstance) && ((_a = fieldInstance[0]) === null || _a === void 0 ? void 0 : _a.type) === 'checkbox' && !Array.isArray(value)) {
|
|
1505
|
+
const newValue = klona(resolveNextCheckboxValue(getFromPath(formValues, field) || [], value, undefined));
|
|
1506
|
+
setInPath(formValues, field, newValue);
|
|
1450
1507
|
return;
|
|
1451
1508
|
}
|
|
1452
1509
|
let newValue = value;
|
|
1453
1510
|
// Single Checkbox: toggles the field value unless the field is being reset then force it
|
|
1454
|
-
if (!
|
|
1511
|
+
if (!isFieldGroup(fieldInstance) && fieldInstance.type === 'checkbox' && !force) {
|
|
1455
1512
|
newValue = klona(resolveNextCheckboxValue(getFromPath(formValues, field), value, vue.unref(fieldInstance.uncheckedValue)));
|
|
1456
1513
|
}
|
|
1457
1514
|
setInPath(formValues, field, newValue);
|
|
1458
|
-
// multiple radio fields
|
|
1459
|
-
if (fieldInstance && Array.isArray(fieldInstance)) {
|
|
1460
|
-
fieldInstance.forEach(fieldItem => {
|
|
1461
|
-
valuesByFid[fieldItem.fid] = newValue;
|
|
1462
|
-
});
|
|
1463
|
-
return;
|
|
1464
|
-
}
|
|
1465
|
-
valuesByFid[fieldInstance.fid] = newValue;
|
|
1466
1515
|
}
|
|
1467
1516
|
/**
|
|
1468
1517
|
* Sets multiple fields values
|
|
@@ -1476,16 +1525,17 @@
|
|
|
1476
1525
|
keysOf(fields).forEach(path => {
|
|
1477
1526
|
setFieldValue(path, fields[path]);
|
|
1478
1527
|
});
|
|
1528
|
+
// regenerate the arrays when the form values change
|
|
1529
|
+
Object.values(fieldArraysLookup).forEach(f => f && f.reset());
|
|
1479
1530
|
}
|
|
1480
1531
|
/**
|
|
1481
1532
|
* Sets the touched meta state on a field
|
|
1482
1533
|
*/
|
|
1483
1534
|
function setFieldTouched(field, isTouched) {
|
|
1484
|
-
const fieldInstance =
|
|
1485
|
-
if (
|
|
1486
|
-
|
|
1535
|
+
const fieldInstance = fieldsByPath.value[field];
|
|
1536
|
+
if (fieldInstance) {
|
|
1537
|
+
applyFieldMutation(fieldInstance, f => f.setTouched(isTouched));
|
|
1487
1538
|
}
|
|
1488
|
-
applyFieldMutation(fieldInstance, f => f.setTouched(isTouched));
|
|
1489
1539
|
}
|
|
1490
1540
|
/**
|
|
1491
1541
|
* Sets the touched meta state on multiple fields
|
|
@@ -1505,108 +1555,123 @@
|
|
|
1505
1555
|
setValues(state === null || state === void 0 ? void 0 : state.values);
|
|
1506
1556
|
}
|
|
1507
1557
|
else {
|
|
1558
|
+
// clean up the initial values back to the original
|
|
1559
|
+
setInitialValues(originalInitialValues.value);
|
|
1508
1560
|
// otherwise clean the current values
|
|
1509
|
-
setValues(
|
|
1561
|
+
setValues(originalInitialValues.value);
|
|
1510
1562
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1563
|
+
Object.values(fieldsByPath.value).forEach(field => {
|
|
1564
|
+
if (!field) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
applyFieldMutation(field, f => f.resetField());
|
|
1568
|
+
});
|
|
1513
1569
|
if (state === null || state === void 0 ? void 0 : state.touched) {
|
|
1514
1570
|
setTouched(state.touched);
|
|
1515
1571
|
}
|
|
1516
1572
|
setErrors((state === null || state === void 0 ? void 0 : state.errors) || {});
|
|
1517
1573
|
submitCount.value = (state === null || state === void 0 ? void 0 : state.submitCount) || 0;
|
|
1518
1574
|
}
|
|
1575
|
+
function insertFieldAtPath(field, path) {
|
|
1576
|
+
const rawField = vue.markRaw(field);
|
|
1577
|
+
const fieldPath = path;
|
|
1578
|
+
// first field at that path
|
|
1579
|
+
if (!fieldsByPath.value[fieldPath]) {
|
|
1580
|
+
fieldsByPath.value[fieldPath] = rawField;
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
const fieldAtPath = fieldsByPath.value[fieldPath];
|
|
1584
|
+
if (fieldAtPath && !Array.isArray(fieldAtPath)) {
|
|
1585
|
+
fieldsByPath.value[fieldPath] = [fieldAtPath];
|
|
1586
|
+
}
|
|
1587
|
+
// add the new array to that path
|
|
1588
|
+
fieldsByPath.value[fieldPath] = [...fieldsByPath.value[fieldPath], rawField];
|
|
1589
|
+
}
|
|
1590
|
+
function removeFieldFromPath(field, path) {
|
|
1591
|
+
const fieldPath = path;
|
|
1592
|
+
const fieldAtPath = fieldsByPath.value[fieldPath];
|
|
1593
|
+
if (!fieldAtPath) {
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
// same field at path
|
|
1597
|
+
if (!isFieldGroup(fieldAtPath) && field.id === fieldAtPath.id) {
|
|
1598
|
+
delete fieldsByPath.value[fieldPath];
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
if (isFieldGroup(fieldAtPath)) {
|
|
1602
|
+
const idx = fieldAtPath.findIndex(f => f.id === field.id);
|
|
1603
|
+
if (idx === -1) {
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
fieldAtPath.splice(idx, 1);
|
|
1607
|
+
if (fieldAtPath.length === 1) {
|
|
1608
|
+
fieldsByPath.value[fieldPath] = fieldAtPath[0];
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
if (!fieldAtPath.length) {
|
|
1612
|
+
delete fieldsByPath.value[fieldPath];
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1519
1616
|
function registerField(field) {
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
// eslint-disable-next-line no-unused-expressions
|
|
1523
|
-
fieldsById.value; // force computation of the fields ids to properly set their idx
|
|
1617
|
+
const fieldPath = vue.unref(field.name);
|
|
1618
|
+
insertFieldAtPath(field, fieldPath);
|
|
1524
1619
|
if (vue.isRef(field.name)) {
|
|
1525
|
-
valuesByFid[field.fid] = field.value.value;
|
|
1526
1620
|
// ensures when a field's name was already taken that it preserves its same value
|
|
1527
1621
|
// necessary for fields generated by loops
|
|
1528
|
-
vue.watch(field.name, (newPath, oldPath) => {
|
|
1529
|
-
|
|
1530
|
-
|
|
1622
|
+
vue.watch(field.name, async (newPath, oldPath) => {
|
|
1623
|
+
// cache the value
|
|
1624
|
+
await vue.nextTick();
|
|
1625
|
+
removeFieldFromPath(field, oldPath);
|
|
1626
|
+
insertFieldAtPath(field, newPath);
|
|
1627
|
+
// re-validate if either path had errors before
|
|
1628
|
+
if (errors.value[oldPath] || errors.value[newPath]) {
|
|
1629
|
+
validateField(newPath);
|
|
1630
|
+
}
|
|
1531
1631
|
// clean up the old path if no other field is sharing that name
|
|
1532
1632
|
// #3325
|
|
1533
|
-
|
|
1633
|
+
await vue.nextTick();
|
|
1634
|
+
if (!fieldExists(oldPath)) {
|
|
1534
1635
|
unsetPath(formValues, oldPath);
|
|
1535
|
-
unsetPath(initialValues.value, oldPath);
|
|
1536
1636
|
}
|
|
1537
|
-
}, {
|
|
1538
|
-
flush: 'post',
|
|
1539
1637
|
});
|
|
1540
1638
|
}
|
|
1541
1639
|
// if field already had errors (initial errors) that's not user-set, validate it again to ensure state is correct
|
|
1542
1640
|
// the difference being that `initialErrors` will contain the error message while other errors (pre-validated schema) won't have them as initial errors
|
|
1543
1641
|
// #3342
|
|
1544
|
-
const path = vue.unref(field.name);
|
|
1545
1642
|
const initialErrorMessage = vue.unref(field.errorMessage);
|
|
1546
|
-
if (initialErrorMessage && (initialErrors === null || initialErrors === void 0 ? void 0 : initialErrors[
|
|
1547
|
-
validateField(
|
|
1643
|
+
if (initialErrorMessage && (initialErrors === null || initialErrors === void 0 ? void 0 : initialErrors[fieldPath]) !== initialErrorMessage) {
|
|
1644
|
+
validateField(fieldPath);
|
|
1548
1645
|
}
|
|
1549
1646
|
// marks the initial error as "consumed" so it won't be matched later with same non-initial error
|
|
1550
|
-
delete initialErrors[
|
|
1647
|
+
delete initialErrors[fieldPath];
|
|
1551
1648
|
}
|
|
1552
1649
|
function unregisterField(field) {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
if (idx === -1) {
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
|
-
fields.value.splice(idx, 1);
|
|
1559
|
-
const fid = field.fid;
|
|
1560
|
-
// cleans up the field value from fid lookup
|
|
1650
|
+
const fieldName = vue.unref(field.name);
|
|
1651
|
+
removeFieldFromPath(field, fieldName);
|
|
1561
1652
|
vue.nextTick(() => {
|
|
1562
|
-
delete valuesByFid[fid];
|
|
1563
1653
|
// clears a field error on unmounted
|
|
1564
1654
|
// we wait till next tick to make sure if the field is completely removed and doesn't have any siblings like checkboxes
|
|
1565
1655
|
// #3384
|
|
1566
|
-
if (!
|
|
1656
|
+
if (!fieldExists(fieldName)) {
|
|
1567
1657
|
setFieldError(fieldName, undefined);
|
|
1658
|
+
unsetPath(formValues, fieldName);
|
|
1568
1659
|
}
|
|
1569
1660
|
});
|
|
1570
|
-
const fieldName = vue.unref(field.name);
|
|
1571
|
-
// in this case, this is a single field not a group (checkbox or radio)
|
|
1572
|
-
// so remove the field value key immediately
|
|
1573
|
-
if (field.idx === -1) {
|
|
1574
|
-
// avoid un-setting the value if the field was switched with another that shares the same name
|
|
1575
|
-
// they will be unset once the new field takes over the new name, look at `#registerField()`
|
|
1576
|
-
// #3166
|
|
1577
|
-
const isSharingName = fields.value.find(f => vue.unref(f.name) === fieldName);
|
|
1578
|
-
if (isSharingName) {
|
|
1579
|
-
return;
|
|
1580
|
-
}
|
|
1581
|
-
unsetPath(formValues, fieldName);
|
|
1582
|
-
unsetPath(initialValues.value, fieldName);
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
|
-
// otherwise find the actual value in the current array of values and remove it
|
|
1586
|
-
const valueIdx = (_b = (_a = getFromPath(formValues, fieldName)) === null || _a === void 0 ? void 0 : _a.indexOf) === null || _b === void 0 ? void 0 : _b.call(_a, vue.unref(field.checkedValue));
|
|
1587
|
-
if (valueIdx === undefined) {
|
|
1588
|
-
unsetPath(formValues, fieldName);
|
|
1589
|
-
return;
|
|
1590
|
-
}
|
|
1591
|
-
if (valueIdx === -1) {
|
|
1592
|
-
return;
|
|
1593
|
-
}
|
|
1594
|
-
if (Array.isArray(formValues[fieldName])) {
|
|
1595
|
-
unsetPath(formValues, `${fieldName}.${valueIdx}`);
|
|
1596
|
-
return;
|
|
1597
|
-
}
|
|
1598
|
-
unsetPath(formValues, fieldName);
|
|
1599
|
-
unsetPath(initialValues.value, fieldName);
|
|
1600
1661
|
}
|
|
1601
|
-
async function validate() {
|
|
1662
|
+
async function validate(opts) {
|
|
1602
1663
|
if (formCtx.validateSchema) {
|
|
1603
|
-
return formCtx.validateSchema('force');
|
|
1664
|
+
return formCtx.validateSchema((opts === null || opts === void 0 ? void 0 : opts.mode) || 'force');
|
|
1604
1665
|
}
|
|
1605
1666
|
// No schema, each field is responsible to validate itself
|
|
1606
|
-
const validations = await Promise.all(
|
|
1607
|
-
|
|
1667
|
+
const validations = await Promise.all(Object.values(fieldsByPath.value).map(field => {
|
|
1668
|
+
const fieldInstance = Array.isArray(field) ? field[0] : field;
|
|
1669
|
+
if (!fieldInstance) {
|
|
1670
|
+
return Promise.resolve({ key: '', valid: true, errors: [] });
|
|
1671
|
+
}
|
|
1672
|
+
return fieldInstance.validate(opts).then((result) => {
|
|
1608
1673
|
return {
|
|
1609
|
-
key: vue.unref(
|
|
1674
|
+
key: vue.unref(fieldInstance.name),
|
|
1610
1675
|
valid: result.valid,
|
|
1611
1676
|
errors: result.errors,
|
|
1612
1677
|
};
|
|
@@ -1629,8 +1694,8 @@
|
|
|
1629
1694
|
errors,
|
|
1630
1695
|
};
|
|
1631
1696
|
}
|
|
1632
|
-
function validateField(field) {
|
|
1633
|
-
const fieldInstance =
|
|
1697
|
+
async function validateField(field) {
|
|
1698
|
+
const fieldInstance = fieldsByPath.value[field];
|
|
1634
1699
|
if (!fieldInstance) {
|
|
1635
1700
|
vue.warn(`field with name ${field} was not found`);
|
|
1636
1701
|
return Promise.resolve({ errors: [], valid: true });
|
|
@@ -1640,14 +1705,14 @@
|
|
|
1640
1705
|
}
|
|
1641
1706
|
return fieldInstance.validate();
|
|
1642
1707
|
}
|
|
1643
|
-
function handleSubmit(fn) {
|
|
1708
|
+
function handleSubmit(fn, onValidationError) {
|
|
1644
1709
|
return function submissionHandler(e) {
|
|
1645
1710
|
if (e instanceof Event) {
|
|
1646
1711
|
e.preventDefault();
|
|
1647
1712
|
e.stopPropagation();
|
|
1648
1713
|
}
|
|
1649
1714
|
// Touch all fields
|
|
1650
|
-
setTouched(keysOf(
|
|
1715
|
+
setTouched(keysOf(fieldsByPath.value).reduce((acc, field) => {
|
|
1651
1716
|
acc[field] = true;
|
|
1652
1717
|
return acc;
|
|
1653
1718
|
}, {}));
|
|
@@ -1667,9 +1732,18 @@
|
|
|
1667
1732
|
resetForm,
|
|
1668
1733
|
});
|
|
1669
1734
|
}
|
|
1735
|
+
if (!result.valid && typeof onValidationError === 'function') {
|
|
1736
|
+
onValidationError({
|
|
1737
|
+
values: klona(formValues),
|
|
1738
|
+
evt: e,
|
|
1739
|
+
errors: result.errors,
|
|
1740
|
+
results: result.results,
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1670
1743
|
})
|
|
1671
|
-
.then(
|
|
1744
|
+
.then(returnVal => {
|
|
1672
1745
|
isSubmitting.value = false;
|
|
1746
|
+
return returnVal;
|
|
1673
1747
|
}, err => {
|
|
1674
1748
|
isSubmitting.value = false;
|
|
1675
1749
|
// re-throw the err so it doesn't go silent
|
|
@@ -1680,6 +1754,9 @@
|
|
|
1680
1754
|
function setFieldInitialValue(path, value) {
|
|
1681
1755
|
setInPath(initialValues.value, path, klona(value));
|
|
1682
1756
|
}
|
|
1757
|
+
function unsetInitialValue(path) {
|
|
1758
|
+
unsetPath(initialValues.value, path);
|
|
1759
|
+
}
|
|
1683
1760
|
/**
|
|
1684
1761
|
* Sneaky function to set initial field values
|
|
1685
1762
|
*/
|
|
@@ -1687,7 +1764,7 @@
|
|
|
1687
1764
|
setInPath(formValues, path, value);
|
|
1688
1765
|
setFieldInitialValue(path, value);
|
|
1689
1766
|
}
|
|
1690
|
-
async function
|
|
1767
|
+
async function _validateSchema() {
|
|
1691
1768
|
const schemaValue = vue.unref(schema);
|
|
1692
1769
|
if (!schemaValue) {
|
|
1693
1770
|
return { valid: true, results: {}, errors: {} };
|
|
@@ -1698,8 +1775,16 @@
|
|
|
1698
1775
|
names: fieldNames.value,
|
|
1699
1776
|
bailsMap: fieldBailsMap.value,
|
|
1700
1777
|
});
|
|
1778
|
+
return formResult;
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* Batches validation runs in 5ms batches
|
|
1782
|
+
*/
|
|
1783
|
+
const debouncedSchemaValidation = debounceAsync(_validateSchema, 5);
|
|
1784
|
+
async function validateSchema(mode) {
|
|
1785
|
+
const formResult = await debouncedSchemaValidation();
|
|
1701
1786
|
// fields by id lookup
|
|
1702
|
-
const fieldsById = formCtx.
|
|
1787
|
+
const fieldsById = formCtx.fieldsByPath.value || {};
|
|
1703
1788
|
// errors fields names, we need it to also check if custom errors are updated
|
|
1704
1789
|
const currentErrorsPaths = keysOf(formCtx.errorBag.value);
|
|
1705
1790
|
// collect all the keys from the schema and all fields
|
|
@@ -1733,7 +1818,7 @@
|
|
|
1733
1818
|
if (mode === 'validated-only' && !wasValidated) {
|
|
1734
1819
|
return validation;
|
|
1735
1820
|
}
|
|
1736
|
-
applyFieldMutation(field, f => f.
|
|
1821
|
+
applyFieldMutation(field, f => f.setState({ errors: fieldResult.errors }));
|
|
1737
1822
|
return validation;
|
|
1738
1823
|
}, { valid: formResult.valid, results: {}, errors: {} });
|
|
1739
1824
|
}
|
|
@@ -1769,7 +1854,6 @@
|
|
|
1769
1854
|
}
|
|
1770
1855
|
// Provide injections
|
|
1771
1856
|
vue.provide(FormContextKey, formCtx);
|
|
1772
|
-
vue.provide(FormErrorsKey, errors);
|
|
1773
1857
|
return {
|
|
1774
1858
|
errors,
|
|
1775
1859
|
meta,
|
|
@@ -1793,7 +1877,7 @@
|
|
|
1793
1877
|
/**
|
|
1794
1878
|
* Manages form meta aggregation
|
|
1795
1879
|
*/
|
|
1796
|
-
function useFormMeta(
|
|
1880
|
+
function useFormMeta(fieldsByPath, currentValues, initialValues, errors) {
|
|
1797
1881
|
const MERGE_STRATEGIES = {
|
|
1798
1882
|
touched: 'some',
|
|
1799
1883
|
pending: 'some',
|
|
@@ -1803,9 +1887,10 @@
|
|
|
1803
1887
|
return !es6(currentValues, vue.unref(initialValues));
|
|
1804
1888
|
});
|
|
1805
1889
|
const flags = vue.computed(() => {
|
|
1890
|
+
const fields = Object.values(fieldsByPath.value).flat(1).filter(Boolean);
|
|
1806
1891
|
return keysOf(MERGE_STRATEGIES).reduce((acc, flag) => {
|
|
1807
1892
|
const mergeMethod = MERGE_STRATEGIES[flag];
|
|
1808
|
-
acc[flag] = fields
|
|
1893
|
+
acc[flag] = fields[mergeMethod](field => field.meta[flag]);
|
|
1809
1894
|
return acc;
|
|
1810
1895
|
}, {});
|
|
1811
1896
|
});
|
|
@@ -1817,13 +1902,17 @@
|
|
|
1817
1902
|
* Manages the initial values prop
|
|
1818
1903
|
*/
|
|
1819
1904
|
function useFormInitialValues(fields, formValues, providedValues) {
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1905
|
+
// these are the mutable initial values as the fields are mounted/unmounted
|
|
1906
|
+
const initialValues = vue.ref(klona(vue.unref(providedValues)) || {});
|
|
1907
|
+
// these are the original initial value as provided by the user initially, they don't keep track of conditional fields
|
|
1908
|
+
// this is important because some conditional fields will overwrite the initial values for other fields who had the same name
|
|
1909
|
+
// like array fields, any push/insert operation will overwrite the initial values because they "create new fields"
|
|
1910
|
+
// so these are the values that the reset function should use
|
|
1911
|
+
// these only change when the user explicitly chanegs the initial values or when the user resets them with new values.
|
|
1912
|
+
const originalInitialValues = vue.ref(klona(vue.unref(providedValues)) || {});
|
|
1825
1913
|
function setInitialValues(values, updateFields = false) {
|
|
1826
1914
|
initialValues.value = klona(values);
|
|
1915
|
+
originalInitialValues.value = klona(values);
|
|
1827
1916
|
if (!updateFields) {
|
|
1828
1917
|
return;
|
|
1829
1918
|
}
|
|
@@ -1831,15 +1920,14 @@
|
|
|
1831
1920
|
// those are excluded because it's unlikely you want to change the form values using initial values
|
|
1832
1921
|
// we mostly watch them for API population or newly inserted fields
|
|
1833
1922
|
// 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
|
|
1834
|
-
const hadInteraction = (f) => f.meta.touched;
|
|
1835
1923
|
keysOf(fields.value).forEach(fieldPath => {
|
|
1836
1924
|
const field = fields.value[fieldPath];
|
|
1837
|
-
const
|
|
1838
|
-
if (
|
|
1925
|
+
const wasTouched = Array.isArray(field) ? field.some(f => f.meta.touched) : field === null || field === void 0 ? void 0 : field.meta.touched;
|
|
1926
|
+
if (!field || wasTouched) {
|
|
1839
1927
|
return;
|
|
1840
1928
|
}
|
|
1841
1929
|
const newValue = getFromPath(initialValues.value, fieldPath);
|
|
1842
|
-
setInPath(formValues, fieldPath, newValue);
|
|
1930
|
+
setInPath(formValues, fieldPath, klona(newValue));
|
|
1843
1931
|
});
|
|
1844
1932
|
}
|
|
1845
1933
|
if (vue.isRef(providedValues)) {
|
|
@@ -1849,10 +1937,9 @@
|
|
|
1849
1937
|
deep: true,
|
|
1850
1938
|
});
|
|
1851
1939
|
}
|
|
1852
|
-
vue.provide(FormInitialValuesKey, computedInitials);
|
|
1853
1940
|
return {
|
|
1854
|
-
readonlyInitialValues: computedInitials,
|
|
1855
1941
|
initialValues,
|
|
1942
|
+
originalInitialValues,
|
|
1856
1943
|
setInitialValues,
|
|
1857
1944
|
};
|
|
1858
1945
|
}
|
|
@@ -1925,6 +2012,10 @@
|
|
|
1925
2012
|
type: Function,
|
|
1926
2013
|
default: undefined,
|
|
1927
2014
|
},
|
|
2015
|
+
onInvalidSubmit: {
|
|
2016
|
+
type: Function,
|
|
2017
|
+
default: undefined,
|
|
2018
|
+
},
|
|
1928
2019
|
},
|
|
1929
2020
|
setup(props, ctx) {
|
|
1930
2021
|
const initialValues = vue.toRef(props, 'initialValues');
|
|
@@ -1936,7 +2027,7 @@
|
|
|
1936
2027
|
initialTouched: props.initialTouched,
|
|
1937
2028
|
validateOnMount: props.validateOnMount,
|
|
1938
2029
|
});
|
|
1939
|
-
const onSubmit = props.onSubmit ? handleSubmit(props.onSubmit) : submitForm;
|
|
2030
|
+
const onSubmit = props.onSubmit ? handleSubmit(props.onSubmit, props.onInvalidSubmit) : submitForm;
|
|
1940
2031
|
function handleFormReset(e) {
|
|
1941
2032
|
if (isEvent(e)) {
|
|
1942
2033
|
// Prevent default form reset behavior
|
|
@@ -1949,7 +2040,7 @@
|
|
|
1949
2040
|
}
|
|
1950
2041
|
function handleScopedSlotSubmit(evt, onSubmit) {
|
|
1951
2042
|
const onSuccess = typeof evt === 'function' && !onSubmit ? evt : onSubmit;
|
|
1952
|
-
return handleSubmit(onSuccess)(evt);
|
|
2043
|
+
return handleSubmit(onSuccess, props.onInvalidSubmit)(evt);
|
|
1953
2044
|
}
|
|
1954
2045
|
function slotProps() {
|
|
1955
2046
|
return {
|
|
@@ -2003,6 +2094,203 @@
|
|
|
2003
2094
|
},
|
|
2004
2095
|
});
|
|
2005
2096
|
|
|
2097
|
+
let FIELD_ARRAY_COUNTER = 0;
|
|
2098
|
+
function useFieldArray(arrayPath) {
|
|
2099
|
+
const id = FIELD_ARRAY_COUNTER++;
|
|
2100
|
+
const form = injectWithSelf(FormContextKey, undefined);
|
|
2101
|
+
const fields = vue.ref([]);
|
|
2102
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
2103
|
+
const noOp = () => { };
|
|
2104
|
+
const noOpApi = {
|
|
2105
|
+
fields: vue.readonly(fields),
|
|
2106
|
+
remove: noOp,
|
|
2107
|
+
push: noOp,
|
|
2108
|
+
swap: noOp,
|
|
2109
|
+
insert: noOp,
|
|
2110
|
+
update: noOp,
|
|
2111
|
+
replace: noOp,
|
|
2112
|
+
prepend: noOp,
|
|
2113
|
+
};
|
|
2114
|
+
if (!form) {
|
|
2115
|
+
warn('FieldArray requires being a child of `<Form/>` or `useForm` being called before it. Array fields may not work correctly');
|
|
2116
|
+
return noOpApi;
|
|
2117
|
+
}
|
|
2118
|
+
if (!vue.unref(arrayPath)) {
|
|
2119
|
+
warn('FieldArray requires a field path to be provided, did you forget to pass the `name` prop?');
|
|
2120
|
+
return noOpApi;
|
|
2121
|
+
}
|
|
2122
|
+
let entryCounter = 0;
|
|
2123
|
+
function initFields() {
|
|
2124
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []);
|
|
2125
|
+
fields.value = currentValues.map(createEntry);
|
|
2126
|
+
updateEntryFlags();
|
|
2127
|
+
}
|
|
2128
|
+
initFields();
|
|
2129
|
+
function updateEntryFlags() {
|
|
2130
|
+
const fieldsLength = fields.value.length;
|
|
2131
|
+
for (let i = 0; i < fieldsLength; i++) {
|
|
2132
|
+
const entry = fields.value[i];
|
|
2133
|
+
entry.isFirst = i === 0;
|
|
2134
|
+
entry.isLast = i === fieldsLength - 1;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
function createEntry(value) {
|
|
2138
|
+
const key = entryCounter++;
|
|
2139
|
+
const entry = {
|
|
2140
|
+
key,
|
|
2141
|
+
value: vue.computed(() => {
|
|
2142
|
+
const currentValues = getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(arrayPath), []);
|
|
2143
|
+
const idx = fields.value.findIndex(e => e.key === key);
|
|
2144
|
+
return idx === -1 ? value : currentValues[idx];
|
|
2145
|
+
}),
|
|
2146
|
+
isFirst: false,
|
|
2147
|
+
isLast: false,
|
|
2148
|
+
};
|
|
2149
|
+
return entry;
|
|
2150
|
+
}
|
|
2151
|
+
function remove(idx) {
|
|
2152
|
+
const pathName = vue.unref(arrayPath);
|
|
2153
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2154
|
+
if (!pathValue || !Array.isArray(pathValue)) {
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
const newValue = [...pathValue];
|
|
2158
|
+
newValue.splice(idx, 1);
|
|
2159
|
+
form === null || form === void 0 ? void 0 : form.unsetInitialValue(pathName + `[${idx}]`);
|
|
2160
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2161
|
+
fields.value.splice(idx, 1);
|
|
2162
|
+
updateEntryFlags();
|
|
2163
|
+
}
|
|
2164
|
+
function push(value) {
|
|
2165
|
+
const pathName = vue.unref(arrayPath);
|
|
2166
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2167
|
+
const normalizedPathValue = isNullOrUndefined(pathValue) ? [] : pathValue;
|
|
2168
|
+
if (!Array.isArray(normalizedPathValue)) {
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
const newValue = [...normalizedPathValue];
|
|
2172
|
+
newValue.push(value);
|
|
2173
|
+
form === null || form === void 0 ? void 0 : form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2174
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2175
|
+
fields.value.push(createEntry(value));
|
|
2176
|
+
updateEntryFlags();
|
|
2177
|
+
}
|
|
2178
|
+
function swap(indexA, indexB) {
|
|
2179
|
+
const pathName = vue.unref(arrayPath);
|
|
2180
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2181
|
+
if (!Array.isArray(pathValue) || !pathValue[indexA] || !pathValue[indexB]) {
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
const newValue = [...pathValue];
|
|
2185
|
+
const newFields = [...fields.value];
|
|
2186
|
+
// the old switcheroo
|
|
2187
|
+
const temp = newValue[indexA];
|
|
2188
|
+
newValue[indexA] = newValue[indexB];
|
|
2189
|
+
newValue[indexB] = temp;
|
|
2190
|
+
const tempEntry = newFields[indexA];
|
|
2191
|
+
newFields[indexA] = newFields[indexB];
|
|
2192
|
+
newFields[indexB] = tempEntry;
|
|
2193
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2194
|
+
fields.value = newFields;
|
|
2195
|
+
updateEntryFlags();
|
|
2196
|
+
}
|
|
2197
|
+
function insert(idx, value) {
|
|
2198
|
+
const pathName = vue.unref(arrayPath);
|
|
2199
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2200
|
+
if (!Array.isArray(pathValue) || pathValue.length < idx) {
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
const newValue = [...pathValue];
|
|
2204
|
+
const newFields = [...fields.value];
|
|
2205
|
+
newValue.splice(idx, 0, value);
|
|
2206
|
+
newFields.splice(idx, 0, createEntry(value));
|
|
2207
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2208
|
+
fields.value = newFields;
|
|
2209
|
+
updateEntryFlags();
|
|
2210
|
+
}
|
|
2211
|
+
function replace(arr) {
|
|
2212
|
+
const pathName = vue.unref(arrayPath);
|
|
2213
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, arr);
|
|
2214
|
+
initFields();
|
|
2215
|
+
}
|
|
2216
|
+
function update(idx, value) {
|
|
2217
|
+
const pathName = vue.unref(arrayPath);
|
|
2218
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2219
|
+
if (!Array.isArray(pathValue) || pathValue.length - 1 < idx) {
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(`${pathName}[${idx}]`, value);
|
|
2223
|
+
}
|
|
2224
|
+
function prepend(value) {
|
|
2225
|
+
const pathName = vue.unref(arrayPath);
|
|
2226
|
+
const pathValue = getFromPath(form === null || form === void 0 ? void 0 : form.values, pathName);
|
|
2227
|
+
const normalizedPathValue = isNullOrUndefined(pathValue) ? [] : pathValue;
|
|
2228
|
+
if (!Array.isArray(normalizedPathValue)) {
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
const newValue = [value, ...normalizedPathValue];
|
|
2232
|
+
form === null || form === void 0 ? void 0 : form.stageInitialValue(pathName + `[${newValue.length - 1}]`, value);
|
|
2233
|
+
form === null || form === void 0 ? void 0 : form.setFieldValue(pathName, newValue);
|
|
2234
|
+
fields.value.unshift(createEntry(value));
|
|
2235
|
+
updateEntryFlags();
|
|
2236
|
+
}
|
|
2237
|
+
form.fieldArraysLookup[id] = {
|
|
2238
|
+
reset: initFields,
|
|
2239
|
+
};
|
|
2240
|
+
vue.onBeforeUnmount(() => {
|
|
2241
|
+
delete form.fieldArraysLookup[id];
|
|
2242
|
+
});
|
|
2243
|
+
return {
|
|
2244
|
+
fields: vue.readonly(fields),
|
|
2245
|
+
remove,
|
|
2246
|
+
push,
|
|
2247
|
+
swap,
|
|
2248
|
+
insert,
|
|
2249
|
+
update,
|
|
2250
|
+
replace,
|
|
2251
|
+
prepend,
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
const FieldArray = vue.defineComponent({
|
|
2256
|
+
name: 'FieldArray',
|
|
2257
|
+
inheritAttrs: false,
|
|
2258
|
+
props: {
|
|
2259
|
+
name: {
|
|
2260
|
+
type: String,
|
|
2261
|
+
required: true,
|
|
2262
|
+
},
|
|
2263
|
+
},
|
|
2264
|
+
setup(props, ctx) {
|
|
2265
|
+
const { push, remove, swap, insert, replace, update, prepend, fields } = useFieldArray(vue.toRef(props, 'name'));
|
|
2266
|
+
function slotProps() {
|
|
2267
|
+
return {
|
|
2268
|
+
fields: fields.value,
|
|
2269
|
+
push,
|
|
2270
|
+
remove,
|
|
2271
|
+
swap,
|
|
2272
|
+
insert,
|
|
2273
|
+
update,
|
|
2274
|
+
replace,
|
|
2275
|
+
prepend,
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
ctx.expose({
|
|
2279
|
+
push,
|
|
2280
|
+
remove,
|
|
2281
|
+
swap,
|
|
2282
|
+
insert,
|
|
2283
|
+
update,
|
|
2284
|
+
replace,
|
|
2285
|
+
prepend,
|
|
2286
|
+
});
|
|
2287
|
+
return () => {
|
|
2288
|
+
const children = normalizeChildren(undefined, ctx, slotProps);
|
|
2289
|
+
return children;
|
|
2290
|
+
};
|
|
2291
|
+
},
|
|
2292
|
+
});
|
|
2293
|
+
|
|
2006
2294
|
const ErrorMessage = vue.defineComponent({
|
|
2007
2295
|
name: 'ErrorMessage',
|
|
2008
2296
|
props: {
|
|
@@ -2016,9 +2304,9 @@
|
|
|
2016
2304
|
},
|
|
2017
2305
|
},
|
|
2018
2306
|
setup(props, ctx) {
|
|
2019
|
-
const
|
|
2307
|
+
const form = vue.inject(FormContextKey, undefined);
|
|
2020
2308
|
const message = vue.computed(() => {
|
|
2021
|
-
return
|
|
2309
|
+
return form === null || form === void 0 ? void 0 : form.errors.value[props.name];
|
|
2022
2310
|
});
|
|
2023
2311
|
function slotProps() {
|
|
2024
2312
|
return {
|
|
@@ -2069,7 +2357,7 @@
|
|
|
2069
2357
|
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2070
2358
|
return vue.computed(() => {
|
|
2071
2359
|
if (path) {
|
|
2072
|
-
field = normalizeField(form === null || form === void 0 ? void 0 : form.
|
|
2360
|
+
field = normalizeField(form === null || form === void 0 ? void 0 : form.fieldsByPath.value[vue.unref(path)]);
|
|
2073
2361
|
}
|
|
2074
2362
|
if (!field) {
|
|
2075
2363
|
warn(`field with name ${vue.unref(path)} was not found`);
|
|
@@ -2087,7 +2375,7 @@
|
|
|
2087
2375
|
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2088
2376
|
return vue.computed(() => {
|
|
2089
2377
|
if (path) {
|
|
2090
|
-
field = normalizeField(form === null || form === void 0 ? void 0 : form.
|
|
2378
|
+
field = normalizeField(form === null || form === void 0 ? void 0 : form.fieldsByPath.value[vue.unref(path)]);
|
|
2091
2379
|
}
|
|
2092
2380
|
if (!field) {
|
|
2093
2381
|
warn(`field with name ${vue.unref(path)} was not found`);
|
|
@@ -2105,7 +2393,7 @@
|
|
|
2105
2393
|
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2106
2394
|
return vue.computed(() => {
|
|
2107
2395
|
if (path) {
|
|
2108
|
-
field = normalizeField(form === null || form === void 0 ? void 0 : form.
|
|
2396
|
+
field = normalizeField(form === null || form === void 0 ? void 0 : form.fieldsByPath.value[vue.unref(path)]);
|
|
2109
2397
|
}
|
|
2110
2398
|
if (!field) {
|
|
2111
2399
|
warn(`field with name ${vue.unref(path)} was not found`);
|
|
@@ -2137,7 +2425,7 @@
|
|
|
2137
2425
|
let field = path ? undefined : vue.inject(FieldContextKey);
|
|
2138
2426
|
return function validateField() {
|
|
2139
2427
|
if (path) {
|
|
2140
|
-
field = normalizeField(form === null || form === void 0 ? void 0 : form.
|
|
2428
|
+
field = normalizeField(form === null || form === void 0 ? void 0 : form.fieldsByPath.value[vue.unref(path)]);
|
|
2141
2429
|
}
|
|
2142
2430
|
if (!field) {
|
|
2143
2431
|
warn(`field with name ${vue.unref(path)} was not found`);
|
|
@@ -2230,11 +2518,10 @@
|
|
|
2230
2518
|
// We don't want to use self injected context as it doesn't make sense
|
|
2231
2519
|
const field = path ? undefined : vue.inject(FieldContextKey);
|
|
2232
2520
|
return vue.computed(() => {
|
|
2233
|
-
var _a;
|
|
2234
2521
|
if (path) {
|
|
2235
2522
|
return getFromPath(form === null || form === void 0 ? void 0 : form.values, vue.unref(path));
|
|
2236
2523
|
}
|
|
2237
|
-
return (
|
|
2524
|
+
return vue.unref(field === null || field === void 0 ? void 0 : field.value);
|
|
2238
2525
|
});
|
|
2239
2526
|
}
|
|
2240
2527
|
|
|
@@ -2255,24 +2542,25 @@
|
|
|
2255
2542
|
* Gives access to all form errors
|
|
2256
2543
|
*/
|
|
2257
2544
|
function useFormErrors() {
|
|
2258
|
-
const
|
|
2259
|
-
if (!
|
|
2545
|
+
const form = injectWithSelf(FormContextKey);
|
|
2546
|
+
if (!form) {
|
|
2260
2547
|
warn('No vee-validate <Form /> or `useForm` was detected in the component tree');
|
|
2261
2548
|
}
|
|
2262
|
-
return
|
|
2549
|
+
return vue.computed(() => {
|
|
2550
|
+
return ((form === null || form === void 0 ? void 0 : form.errors.value) || {});
|
|
2551
|
+
});
|
|
2263
2552
|
}
|
|
2264
2553
|
|
|
2265
2554
|
/**
|
|
2266
2555
|
* Gives access to a single field error
|
|
2267
2556
|
*/
|
|
2268
2557
|
function useFieldError(path) {
|
|
2269
|
-
const
|
|
2558
|
+
const form = injectWithSelf(FormContextKey);
|
|
2270
2559
|
// We don't want to use self injected context as it doesn't make sense
|
|
2271
2560
|
const field = path ? undefined : vue.inject(FieldContextKey);
|
|
2272
2561
|
return vue.computed(() => {
|
|
2273
|
-
var _a;
|
|
2274
2562
|
if (path) {
|
|
2275
|
-
return
|
|
2563
|
+
return form === null || form === void 0 ? void 0 : form.errors.value[vue.unref(path)];
|
|
2276
2564
|
}
|
|
2277
2565
|
return field === null || field === void 0 ? void 0 : field.errorMessage.value;
|
|
2278
2566
|
});
|
|
@@ -2294,12 +2582,14 @@
|
|
|
2294
2582
|
|
|
2295
2583
|
exports.ErrorMessage = ErrorMessage;
|
|
2296
2584
|
exports.Field = Field;
|
|
2585
|
+
exports.FieldArray = FieldArray;
|
|
2297
2586
|
exports.FieldContextKey = FieldContextKey;
|
|
2298
2587
|
exports.Form = Form;
|
|
2299
2588
|
exports.FormContextKey = FormContextKey;
|
|
2300
2589
|
exports.configure = configure;
|
|
2301
2590
|
exports.defineRule = defineRule;
|
|
2302
2591
|
exports.useField = useField;
|
|
2592
|
+
exports.useFieldArray = useFieldArray;
|
|
2303
2593
|
exports.useFieldError = useFieldError;
|
|
2304
2594
|
exports.useFieldValue = useFieldValue;
|
|
2305
2595
|
exports.useForm = useForm;
|