@samline/forms 2.6.0 → 2.7.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 +6 -4
- package/dist/browser/global.d.ts +19 -3
- package/dist/browser/global.global.js +176 -30
- package/dist/browser/global.global.js.map +1 -1
- package/dist/browser/index.cjs +176 -30
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.d.cts +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/{chunk-L4GRKSQ5.js → chunk-MMHX34WB.js} +181 -31
- package/dist/chunk-MMHX34WB.js.map +1 -0
- package/dist/index.cjs +180 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{registry-BpqJetAt.d.cts → registry-GzopYPCR.d.cts} +20 -4
- package/dist/{registry-BpqJetAt.d.ts → registry-GzopYPCR.d.ts} +20 -4
- package/docs/api/add-cleanup.md +52 -0
- package/docs/api/destroy.md +16 -1
- package/docs/api/form.md +4 -2
- package/docs/api/format.md +3 -3
- package/docs/api/get-state.md +17 -1
- package/docs/api/index.md +1 -0
- package/docs/api/on-submit.md +7 -3
- package/docs/api/reset.md +3 -2
- package/docs/api/revalidate.md +3 -1
- package/docs/api/subscribe.md +16 -0
- package/docs/api/validate-field-value.md +39 -3
- package/docs/api/validate-values.md +4 -1
- package/docs/api/validate.md +5 -3
- package/docs/browser.md +5 -5
- package/docs/css-styling.md +5 -1
- package/docs/getting-started.md +13 -8
- package/docs/options.md +69 -2
- package/docs/recipes.md +65 -11
- package/docs/typescript.md +47 -8
- package/package.json +1 -1
- package/dist/chunk-L4GRKSQ5.js.map +0 -1
package/dist/browser/index.cjs
CHANGED
|
@@ -58,6 +58,22 @@ var createAppend = (state2, helpers) => ({ tag, content, class: className, atSta
|
|
|
58
58
|
return node;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
// src/api/add-cleanup.ts
|
|
62
|
+
var createAddCleanup = (state2, _helpers) => (cleanup) => {
|
|
63
|
+
if (state2.isDestroyed) {
|
|
64
|
+
cleanup();
|
|
65
|
+
return () => void 0;
|
|
66
|
+
}
|
|
67
|
+
const registration = () => cleanup();
|
|
68
|
+
state2.cleanups.add(registration);
|
|
69
|
+
let active = true;
|
|
70
|
+
return () => {
|
|
71
|
+
if (!active) return;
|
|
72
|
+
active = false;
|
|
73
|
+
state2.cleanups.delete(registration);
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
61
77
|
// src/api/auto-submit.ts
|
|
62
78
|
var createAutoSubmit = (state2, helpers) => (next = true) => {
|
|
63
79
|
state2.autoSubmitEnabled = next !== false;
|
|
@@ -279,6 +295,10 @@ var buildAutoInterpretedOptions = (formatOptions) => ({
|
|
|
279
295
|
...formatOptions ?? {},
|
|
280
296
|
interpretInputAs: "auto"
|
|
281
297
|
});
|
|
298
|
+
var buildDisplayInterpretedOptions = (formatOptions) => ({
|
|
299
|
+
...formatOptions ?? {},
|
|
300
|
+
interpretInputAs: "display"
|
|
301
|
+
});
|
|
282
302
|
var shouldForceAutoInterpretation = (formatOptions) => formatOptions?.interpretInputAs === void 0;
|
|
283
303
|
var buildHandler = (visible, mirror, formatFn, formatType, formatOptions) => {
|
|
284
304
|
const handler = (event) => {
|
|
@@ -288,7 +308,7 @@ var buildHandler = (visible, mirror, formatFn, formatType, formatOptions) => {
|
|
|
288
308
|
if (!isVisible && !isMirror) return;
|
|
289
309
|
const rawInput = isMirror ? mirror.value : visible.value;
|
|
290
310
|
const inputType = readInputType(event);
|
|
291
|
-
const sourceOptions =
|
|
311
|
+
const sourceOptions = shouldForceAutoInterpretation(formatOptions) ? isMirror ? buildAutoInterpretedOptions(formatOptions) : buildDisplayInterpretedOptions(formatOptions) : formatOptions;
|
|
292
312
|
const { formatted, raw } = formatFn(rawInput, formatType, sourceOptions);
|
|
293
313
|
if (!formatted && !raw) {
|
|
294
314
|
visible.value = "";
|
|
@@ -370,7 +390,8 @@ var applyFormat = async (state2, helpers, config) => {
|
|
|
370
390
|
if (entry.handler !== UNBOUND) {
|
|
371
391
|
const current = entry.visible.value;
|
|
372
392
|
if (current !== "") {
|
|
373
|
-
const
|
|
393
|
+
const rebindOptions = shouldForceAutoInterpretation(formatOptions) ? buildDisplayInterpretedOptions(formatOptions) : formatOptions;
|
|
394
|
+
const { formatted, raw } = formatter.format(current, formatType, rebindOptions);
|
|
374
395
|
applyFormattedValue(entry.visible, entry.mirror, formatted, raw);
|
|
375
396
|
}
|
|
376
397
|
continue;
|
|
@@ -485,12 +506,24 @@ var createDestroy = (state2, _helpers) => () => {
|
|
|
485
506
|
}
|
|
486
507
|
state2.mutationObserver?.disconnect();
|
|
487
508
|
state2.mutationObserver = null;
|
|
509
|
+
const cleanups = Array.from(state2.cleanups).reverse();
|
|
510
|
+
state2.cleanups.clear();
|
|
511
|
+
for (const cleanup of cleanups) {
|
|
512
|
+
try {
|
|
513
|
+
cleanup();
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error("[forms] cleanup failed", error);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
488
518
|
state2.watchedFields.clear();
|
|
489
519
|
state2.subscribers.clear();
|
|
490
520
|
state2.submitHandlers.clear();
|
|
491
521
|
state2.fieldCache.clear();
|
|
492
522
|
state2.manualErrors = {};
|
|
493
523
|
state2.validationErrors = {};
|
|
524
|
+
state2.validationGroupErrors = {};
|
|
525
|
+
state2.validationElementErrors.clear();
|
|
526
|
+
state2.pendingSubmitCount = 0;
|
|
494
527
|
cleanupFormatRegistry(state2);
|
|
495
528
|
};
|
|
496
529
|
|
|
@@ -557,6 +590,7 @@ var createEmptyFormState = () => ({
|
|
|
557
590
|
isValid: true,
|
|
558
591
|
isValidated: false,
|
|
559
592
|
autoSubmit: false,
|
|
593
|
+
isSubmitting: false,
|
|
560
594
|
submitCount: 0
|
|
561
595
|
});
|
|
562
596
|
var cloneErrors = (errors) => Object.fromEntries(
|
|
@@ -588,6 +622,7 @@ var createGetState = (state2, helpers) => () => {
|
|
|
588
622
|
isValid: Object.keys(errors).length === 0,
|
|
589
623
|
isValidated: state2.isValidated,
|
|
590
624
|
autoSubmit: state2.autoSubmitEnabled,
|
|
625
|
+
isSubmitting: state2.pendingSubmitCount > 0,
|
|
591
626
|
submitCount: state2.submitCount
|
|
592
627
|
};
|
|
593
628
|
};
|
|
@@ -785,12 +820,14 @@ var createReset = (state2, helpers) => () => {
|
|
|
785
820
|
resetFormattedFields(state2);
|
|
786
821
|
state2.manualErrors = {};
|
|
787
822
|
state2.validationErrors = {};
|
|
823
|
+
state2.validationGroupErrors = {};
|
|
824
|
+
state2.validationElementErrors.clear();
|
|
788
825
|
clearAttributes(state2.element, [
|
|
789
826
|
state2.attributes.error,
|
|
790
827
|
state2.attributes.filled,
|
|
791
828
|
"aria-invalid"
|
|
792
829
|
]);
|
|
793
|
-
|
|
830
|
+
helpers.syncVisualState();
|
|
794
831
|
helpers.notifySubscribers();
|
|
795
832
|
return state2.api;
|
|
796
833
|
};
|
|
@@ -901,14 +938,29 @@ var valuesAreEqual = (left, right) => {
|
|
|
901
938
|
}
|
|
902
939
|
return left === right;
|
|
903
940
|
};
|
|
904
|
-
var
|
|
941
|
+
var DECIMAL_PATTERN = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
942
|
+
var parseStrictNumber = (value) => {
|
|
943
|
+
if (typeof value !== "string") return void 0;
|
|
944
|
+
const candidate = value.trim();
|
|
945
|
+
if (!DECIMAL_PATTERN.test(candidate)) return void 0;
|
|
946
|
+
const number = Number(candidate);
|
|
947
|
+
return Number.isFinite(number) ? number : void 0;
|
|
948
|
+
};
|
|
949
|
+
var validateValue = (field, value, rules, values, contextOverrides = {}) => {
|
|
905
950
|
const errors = [];
|
|
906
|
-
const context = {
|
|
951
|
+
const context = {
|
|
952
|
+
field,
|
|
953
|
+
value,
|
|
954
|
+
values,
|
|
955
|
+
...contextOverrides
|
|
956
|
+
};
|
|
907
957
|
const required = resolveRule(rules.required);
|
|
908
958
|
const minLength = resolveRule(rules.minLength);
|
|
909
959
|
const maxLength = resolveRule(rules.maxLength);
|
|
910
960
|
const pattern = resolveRule(rules.pattern);
|
|
911
|
-
const
|
|
961
|
+
const numeric = resolveRule(rules.numeric);
|
|
962
|
+
const min = resolveRule(rules.min);
|
|
963
|
+
const max = resolveRule(rules.max);
|
|
912
964
|
if (required.value && !hasValue(value)) {
|
|
913
965
|
errors.push(required.message ?? "This field is required.");
|
|
914
966
|
}
|
|
@@ -926,10 +978,17 @@ var validateFieldValue = (field, value, rules, values) => {
|
|
|
926
978
|
errors.push(pattern.message ?? "Value does not match the required pattern.");
|
|
927
979
|
}
|
|
928
980
|
}
|
|
929
|
-
if (
|
|
930
|
-
const
|
|
931
|
-
if (
|
|
932
|
-
errors.push(
|
|
981
|
+
if (hasValue(value) && (numeric.value || min.value !== void 0 || max.value !== void 0)) {
|
|
982
|
+
const number = parseStrictNumber(value);
|
|
983
|
+
if (number === void 0) {
|
|
984
|
+
errors.push(numeric.message ?? "Value must be a number.");
|
|
985
|
+
} else {
|
|
986
|
+
if (min.value !== void 0 && number < min.value) {
|
|
987
|
+
errors.push(min.message ?? `Minimum value is ${min.value}.`);
|
|
988
|
+
}
|
|
989
|
+
if (max.value !== void 0 && number > max.value) {
|
|
990
|
+
errors.push(max.message ?? `Maximum value is ${max.value}.`);
|
|
991
|
+
}
|
|
933
992
|
}
|
|
934
993
|
}
|
|
935
994
|
const custom = rules.validate ? Array.isArray(rules.validate) ? rules.validate : [rules.validate] : [];
|
|
@@ -940,6 +999,37 @@ var validateFieldValue = (field, value, rules, values) => {
|
|
|
940
999
|
}
|
|
941
1000
|
return errors;
|
|
942
1001
|
};
|
|
1002
|
+
var validateFieldValueDetailed = (field, value, rules, values, items) => {
|
|
1003
|
+
const groupErrors = validateValue(field, value, rules, values);
|
|
1004
|
+
const sameAs = resolveRule(rules.sameAs);
|
|
1005
|
+
if (sameAs.value !== void 0) {
|
|
1006
|
+
const otherValue = values[sameAs.value];
|
|
1007
|
+
if (hasValue(value) && hasValue(otherValue) && !valuesAreEqual(value, otherValue)) {
|
|
1008
|
+
groupErrors.push(sameAs.message ?? `Value must match ${sameAs.value}.`);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
const itemErrors = [];
|
|
1012
|
+
if (rules.each) {
|
|
1013
|
+
const sourceItems = items ?? (Array.isArray(value) ? value.map((entry) => ({
|
|
1014
|
+
value: typeof entry === "string" ? entry : [entry]
|
|
1015
|
+
})) : [{ value }]);
|
|
1016
|
+
sourceItems.forEach((item, index) => {
|
|
1017
|
+
const overrides = {
|
|
1018
|
+
index
|
|
1019
|
+
};
|
|
1020
|
+
if (item.element) overrides.element = item.element;
|
|
1021
|
+
const messages = validateValue(field, item.value, rules.each, values, overrides);
|
|
1022
|
+
if (messages.length === 0) return;
|
|
1023
|
+
const error = {
|
|
1024
|
+
index,
|
|
1025
|
+
messages
|
|
1026
|
+
};
|
|
1027
|
+
if (item.element) error.element = item.element;
|
|
1028
|
+
itemErrors.push(error);
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
return { groupErrors, itemErrors };
|
|
1032
|
+
};
|
|
943
1033
|
|
|
944
1034
|
// src/core/controller.ts
|
|
945
1035
|
var DEFAULT_ATTRIBUTES = {
|
|
@@ -970,25 +1060,35 @@ var createFormController = (target, options = {}) => {
|
|
|
970
1060
|
fieldCache: /* @__PURE__ */ new Map(),
|
|
971
1061
|
manualErrors: {},
|
|
972
1062
|
validationErrors: {},
|
|
1063
|
+
validationGroupErrors: {},
|
|
1064
|
+
validationElementErrors: /* @__PURE__ */ new Map(),
|
|
973
1065
|
isValidated: Boolean(normalizedOptions.autoValidate),
|
|
974
1066
|
autoSubmitEnabled: false,
|
|
975
1067
|
autoSubmitDebounce: 0,
|
|
976
1068
|
submitCount: 0,
|
|
1069
|
+
pendingSubmitCount: 0,
|
|
977
1070
|
autoSubmitTimer: null,
|
|
978
1071
|
isDestroyed: false,
|
|
979
1072
|
listeners: [],
|
|
980
1073
|
mutationObserver: null,
|
|
1074
|
+
cleanups: /* @__PURE__ */ new Set(),
|
|
981
1075
|
formattedFields: /* @__PURE__ */ new Map(),
|
|
982
1076
|
api: null
|
|
983
1077
|
};
|
|
984
1078
|
const validationDependents = /* @__PURE__ */ new Map();
|
|
985
1079
|
for (const [field, rules] of Object.entries(state2.validators)) {
|
|
1080
|
+
const sources = /* @__PURE__ */ new Set();
|
|
986
1081
|
const sameAs = rules.sameAs;
|
|
987
|
-
if (sameAs
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1082
|
+
if (sameAs !== void 0) {
|
|
1083
|
+
sources.add(typeof sameAs === "string" ? sameAs : sameAs.value);
|
|
1084
|
+
}
|
|
1085
|
+
if (typeof rules.dependsOn === "string") sources.add(rules.dependsOn);
|
|
1086
|
+
else rules.dependsOn?.forEach((source) => sources.add(source));
|
|
1087
|
+
for (const source of sources) {
|
|
1088
|
+
const dependents = validationDependents.get(source) ?? /* @__PURE__ */ new Set();
|
|
1089
|
+
dependents.add(field);
|
|
1090
|
+
validationDependents.set(source, dependents);
|
|
1091
|
+
}
|
|
992
1092
|
}
|
|
993
1093
|
const notifySubscribers = () => {
|
|
994
1094
|
if (!state2.api) return;
|
|
@@ -1037,18 +1137,21 @@ var createFormController = (target, options = {}) => {
|
|
|
1037
1137
|
const syncVisualState = (names) => {
|
|
1038
1138
|
if (!state2.element) return;
|
|
1039
1139
|
const sourceNames = names ?? getTrackedFieldNames();
|
|
1040
|
-
const errors = getMergedErrors();
|
|
1041
1140
|
for (const name of sourceNames) {
|
|
1042
1141
|
const displayName = resolveDisplayNameForName(state2, name);
|
|
1043
1142
|
const canonical = resolveCanonicalForName(state2, name) ?? name;
|
|
1044
1143
|
const fields = getFieldsByName(displayName);
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1144
|
+
const hasGroupError = Boolean(
|
|
1145
|
+
state2.validationGroupErrors[canonical]?.length || state2.manualErrors[canonical]?.length
|
|
1146
|
+
);
|
|
1147
|
+
const elementErrors = state2.validationElementErrors.get(canonical);
|
|
1148
|
+
fields.forEach((field) => {
|
|
1149
|
+
const hasError = hasGroupError || Boolean(elementErrors?.get(field)?.length);
|
|
1047
1150
|
applyBooleanAttribute(field, attributes.filled, isFieldFilled(field));
|
|
1048
1151
|
applyBooleanAttribute(field, attributes.error, hasError);
|
|
1049
1152
|
if (hasError) field.setAttribute("aria-invalid", "true");
|
|
1050
1153
|
else field.removeAttribute("aria-invalid");
|
|
1051
|
-
}
|
|
1154
|
+
});
|
|
1052
1155
|
}
|
|
1053
1156
|
};
|
|
1054
1157
|
void readFieldValue;
|
|
@@ -1057,17 +1160,38 @@ var createFormController = (target, options = {}) => {
|
|
|
1057
1160
|
const targetNames = names ?? Object.keys(state2.validators);
|
|
1058
1161
|
const values = getValues();
|
|
1059
1162
|
const nextValidationErrors = names ? cloneErrors(state2.validationErrors) : {};
|
|
1163
|
+
const nextGroupErrors = names ? cloneErrors(state2.validationGroupErrors) : {};
|
|
1164
|
+
const nextElementErrors = names ? new Map(state2.validationElementErrors) : /* @__PURE__ */ new Map();
|
|
1060
1165
|
for (const name of targetNames) {
|
|
1061
1166
|
const rules = state2.validators[name];
|
|
1062
1167
|
if (!rules) {
|
|
1063
1168
|
delete nextValidationErrors[name];
|
|
1169
|
+
delete nextGroupErrors[name];
|
|
1170
|
+
nextElementErrors.delete(name);
|
|
1064
1171
|
continue;
|
|
1065
1172
|
}
|
|
1066
|
-
const
|
|
1173
|
+
const fields = getFieldsByName(name);
|
|
1174
|
+
const displayFields = getFieldsByName(resolveDisplayNameForName(state2, name));
|
|
1175
|
+
const items = fields.map((field, index) => ({
|
|
1176
|
+
value: readFieldValue([field]),
|
|
1177
|
+
element: displayFields[index] ?? field
|
|
1178
|
+
}));
|
|
1179
|
+
const result = validateFieldValueDetailed(name, values[name], rules, values, items);
|
|
1180
|
+
const messages = [...result.groupErrors, ...result.itemErrors.flatMap((item) => item.messages)];
|
|
1067
1181
|
if (messages.length > 0) nextValidationErrors[name] = messages;
|
|
1068
1182
|
else delete nextValidationErrors[name];
|
|
1183
|
+
if (result.groupErrors.length > 0) nextGroupErrors[name] = result.groupErrors;
|
|
1184
|
+
else delete nextGroupErrors[name];
|
|
1185
|
+
const perElement = /* @__PURE__ */ new Map();
|
|
1186
|
+
result.itemErrors.forEach((item) => {
|
|
1187
|
+
if (item.element) perElement.set(item.element, item.messages);
|
|
1188
|
+
});
|
|
1189
|
+
if (perElement.size > 0) nextElementErrors.set(name, perElement);
|
|
1190
|
+
else nextElementErrors.delete(name);
|
|
1069
1191
|
}
|
|
1070
1192
|
state2.validationErrors = nextValidationErrors;
|
|
1193
|
+
state2.validationGroupErrors = nextGroupErrors;
|
|
1194
|
+
state2.validationElementErrors = nextElementErrors;
|
|
1071
1195
|
syncVisualState(names);
|
|
1072
1196
|
return {
|
|
1073
1197
|
isValid: Object.keys(getMergedErrors()).length === 0,
|
|
@@ -1161,7 +1285,13 @@ var createFormController = (target, options = {}) => {
|
|
|
1161
1285
|
if (!validation.isValid) {
|
|
1162
1286
|
for (const name of Object.keys(validation.errors)) {
|
|
1163
1287
|
const displayName = resolveDisplayNameForName(state2, name);
|
|
1164
|
-
const
|
|
1288
|
+
const fields = getFieldsByName(displayName);
|
|
1289
|
+
const elementErrors = state2.validationElementErrors.get(name);
|
|
1290
|
+
const field = fields.find((candidate2) => {
|
|
1291
|
+
if (!candidate2.isConnected || candidate2.disabled || candidate2.hidden) return false;
|
|
1292
|
+
if (candidate2 instanceof HTMLInputElement && candidate2.type === "hidden") return false;
|
|
1293
|
+
return elementErrors?.has(candidate2);
|
|
1294
|
+
}) ?? fields.find((candidate2) => {
|
|
1165
1295
|
if (!candidate2.isConnected || candidate2.disabled || candidate2.hidden) return false;
|
|
1166
1296
|
return !(candidate2 instanceof HTMLInputElement && candidate2.type === "hidden");
|
|
1167
1297
|
});
|
|
@@ -1176,18 +1306,35 @@ var createFormController = (target, options = {}) => {
|
|
|
1176
1306
|
const submitter = candidate.submitter instanceof HTMLElement ? candidate.submitter : null;
|
|
1177
1307
|
const { data, formData } = parseFormData(state2.element, submitter);
|
|
1178
1308
|
const snapshot = state2.api.getState();
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1309
|
+
const pending = [];
|
|
1310
|
+
let synchronousError;
|
|
1311
|
+
let hasSynchronousError = false;
|
|
1312
|
+
try {
|
|
1313
|
+
for (const handler of handlers) {
|
|
1314
|
+
const result = handler.callback(state2.element, data, formData, snapshot);
|
|
1315
|
+
if (result && typeof result.then === "function") pending.push(Promise.resolve(result));
|
|
1316
|
+
}
|
|
1317
|
+
} catch (error) {
|
|
1318
|
+
synchronousError = error;
|
|
1319
|
+
hasSynchronousError = true;
|
|
1320
|
+
}
|
|
1321
|
+
if (pending.length > 0) {
|
|
1322
|
+
state2.pendingSubmitCount += 1;
|
|
1323
|
+
notifySubscribers();
|
|
1324
|
+
void Promise.allSettled(pending).then(() => {
|
|
1325
|
+
state2.pendingSubmitCount = Math.max(0, state2.pendingSubmitCount - 1);
|
|
1326
|
+
if (!state2.isDestroyed) notifySubscribers();
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
if (hasSynchronousError) throw synchronousError;
|
|
1182
1330
|
};
|
|
1183
1331
|
const startMutationObserver = () => {
|
|
1184
1332
|
if (!state2.element || typeof MutationObserver === "undefined") return;
|
|
1185
1333
|
state2.mutationObserver = new MutationObserver(() => {
|
|
1186
1334
|
clearFieldCache();
|
|
1187
1335
|
if (state2.isValidated) {
|
|
1188
|
-
syncVisualState();
|
|
1189
1336
|
validateNames();
|
|
1190
|
-
}
|
|
1337
|
+
} else syncVisualState();
|
|
1191
1338
|
notifySubscribers();
|
|
1192
1339
|
});
|
|
1193
1340
|
state2.mutationObserver.observe(state2.element, {
|
|
@@ -1208,6 +1355,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1208
1355
|
return state2.options;
|
|
1209
1356
|
},
|
|
1210
1357
|
onSubmit: createOnSubmit(state2, helpers),
|
|
1358
|
+
addCleanup: createAddCleanup(state2, helpers),
|
|
1211
1359
|
watch: createWatch(state2, helpers),
|
|
1212
1360
|
observe: createObserve(state2, helpers),
|
|
1213
1361
|
unwatch: createUnwatch(state2, helpers),
|
|
@@ -1245,10 +1393,8 @@ var createFormController = (target, options = {}) => {
|
|
|
1245
1393
|
api.format(config);
|
|
1246
1394
|
}
|
|
1247
1395
|
}
|
|
1248
|
-
if (state2.isValidated)
|
|
1249
|
-
|
|
1250
|
-
validateNames();
|
|
1251
|
-
}
|
|
1396
|
+
if (state2.isValidated) validateNames();
|
|
1397
|
+
else syncVisualState();
|
|
1252
1398
|
return api;
|
|
1253
1399
|
};
|
|
1254
1400
|
|