@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/index.cjs
CHANGED
|
@@ -59,6 +59,22 @@ var createAppend = (state2, helpers) => ({ tag, content, class: className, atSta
|
|
|
59
59
|
return node;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
// src/api/add-cleanup.ts
|
|
63
|
+
var createAddCleanup = (state2, _helpers) => (cleanup) => {
|
|
64
|
+
if (state2.isDestroyed) {
|
|
65
|
+
cleanup();
|
|
66
|
+
return () => void 0;
|
|
67
|
+
}
|
|
68
|
+
const registration = () => cleanup();
|
|
69
|
+
state2.cleanups.add(registration);
|
|
70
|
+
let active = true;
|
|
71
|
+
return () => {
|
|
72
|
+
if (!active) return;
|
|
73
|
+
active = false;
|
|
74
|
+
state2.cleanups.delete(registration);
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
62
78
|
// src/api/auto-submit.ts
|
|
63
79
|
var createAutoSubmit = (state2, helpers) => (next = true) => {
|
|
64
80
|
state2.autoSubmitEnabled = next !== false;
|
|
@@ -280,6 +296,10 @@ var buildAutoInterpretedOptions = (formatOptions) => ({
|
|
|
280
296
|
...formatOptions ?? {},
|
|
281
297
|
interpretInputAs: "auto"
|
|
282
298
|
});
|
|
299
|
+
var buildDisplayInterpretedOptions = (formatOptions) => ({
|
|
300
|
+
...formatOptions ?? {},
|
|
301
|
+
interpretInputAs: "display"
|
|
302
|
+
});
|
|
283
303
|
var shouldForceAutoInterpretation = (formatOptions) => formatOptions?.interpretInputAs === void 0;
|
|
284
304
|
var buildHandler = (visible, mirror, formatFn, formatType, formatOptions) => {
|
|
285
305
|
const handler = (event) => {
|
|
@@ -289,7 +309,7 @@ var buildHandler = (visible, mirror, formatFn, formatType, formatOptions) => {
|
|
|
289
309
|
if (!isVisible && !isMirror) return;
|
|
290
310
|
const rawInput = isMirror ? mirror.value : visible.value;
|
|
291
311
|
const inputType = readInputType(event);
|
|
292
|
-
const sourceOptions =
|
|
312
|
+
const sourceOptions = shouldForceAutoInterpretation(formatOptions) ? isMirror ? buildAutoInterpretedOptions(formatOptions) : buildDisplayInterpretedOptions(formatOptions) : formatOptions;
|
|
293
313
|
const { formatted, raw } = formatFn(rawInput, formatType, sourceOptions);
|
|
294
314
|
if (!formatted && !raw) {
|
|
295
315
|
visible.value = "";
|
|
@@ -371,7 +391,8 @@ var applyFormat = async (state2, helpers, config) => {
|
|
|
371
391
|
if (entry.handler !== UNBOUND) {
|
|
372
392
|
const current = entry.visible.value;
|
|
373
393
|
if (current !== "") {
|
|
374
|
-
const
|
|
394
|
+
const rebindOptions = shouldForceAutoInterpretation(formatOptions) ? buildDisplayInterpretedOptions(formatOptions) : formatOptions;
|
|
395
|
+
const { formatted, raw } = formatter.format(current, formatType, rebindOptions);
|
|
375
396
|
applyFormattedValue(entry.visible, entry.mirror, formatted, raw);
|
|
376
397
|
}
|
|
377
398
|
continue;
|
|
@@ -486,12 +507,24 @@ var createDestroy = (state2, _helpers) => () => {
|
|
|
486
507
|
}
|
|
487
508
|
state2.mutationObserver?.disconnect();
|
|
488
509
|
state2.mutationObserver = null;
|
|
510
|
+
const cleanups = Array.from(state2.cleanups).reverse();
|
|
511
|
+
state2.cleanups.clear();
|
|
512
|
+
for (const cleanup of cleanups) {
|
|
513
|
+
try {
|
|
514
|
+
cleanup();
|
|
515
|
+
} catch (error) {
|
|
516
|
+
console.error("[forms] cleanup failed", error);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
489
519
|
state2.watchedFields.clear();
|
|
490
520
|
state2.subscribers.clear();
|
|
491
521
|
state2.submitHandlers.clear();
|
|
492
522
|
state2.fieldCache.clear();
|
|
493
523
|
state2.manualErrors = {};
|
|
494
524
|
state2.validationErrors = {};
|
|
525
|
+
state2.validationGroupErrors = {};
|
|
526
|
+
state2.validationElementErrors.clear();
|
|
527
|
+
state2.pendingSubmitCount = 0;
|
|
495
528
|
cleanupFormatRegistry(state2);
|
|
496
529
|
};
|
|
497
530
|
|
|
@@ -558,6 +591,7 @@ var createEmptyFormState = () => ({
|
|
|
558
591
|
isValid: true,
|
|
559
592
|
isValidated: false,
|
|
560
593
|
autoSubmit: false,
|
|
594
|
+
isSubmitting: false,
|
|
561
595
|
submitCount: 0
|
|
562
596
|
});
|
|
563
597
|
var cloneErrors = (errors) => Object.fromEntries(
|
|
@@ -589,6 +623,7 @@ var createGetState = (state2, helpers) => () => {
|
|
|
589
623
|
isValid: Object.keys(errors).length === 0,
|
|
590
624
|
isValidated: state2.isValidated,
|
|
591
625
|
autoSubmit: state2.autoSubmitEnabled,
|
|
626
|
+
isSubmitting: state2.pendingSubmitCount > 0,
|
|
592
627
|
submitCount: state2.submitCount
|
|
593
628
|
};
|
|
594
629
|
};
|
|
@@ -786,12 +821,14 @@ var createReset = (state2, helpers) => () => {
|
|
|
786
821
|
resetFormattedFields(state2);
|
|
787
822
|
state2.manualErrors = {};
|
|
788
823
|
state2.validationErrors = {};
|
|
824
|
+
state2.validationGroupErrors = {};
|
|
825
|
+
state2.validationElementErrors.clear();
|
|
789
826
|
clearAttributes(state2.element, [
|
|
790
827
|
state2.attributes.error,
|
|
791
828
|
state2.attributes.filled,
|
|
792
829
|
"aria-invalid"
|
|
793
830
|
]);
|
|
794
|
-
|
|
831
|
+
helpers.syncVisualState();
|
|
795
832
|
helpers.notifySubscribers();
|
|
796
833
|
return state2.api;
|
|
797
834
|
};
|
|
@@ -902,14 +939,29 @@ var valuesAreEqual = (left, right) => {
|
|
|
902
939
|
}
|
|
903
940
|
return left === right;
|
|
904
941
|
};
|
|
905
|
-
var
|
|
942
|
+
var DECIMAL_PATTERN = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
943
|
+
var parseStrictNumber = (value) => {
|
|
944
|
+
if (typeof value !== "string") return void 0;
|
|
945
|
+
const candidate = value.trim();
|
|
946
|
+
if (!DECIMAL_PATTERN.test(candidate)) return void 0;
|
|
947
|
+
const number = Number(candidate);
|
|
948
|
+
return Number.isFinite(number) ? number : void 0;
|
|
949
|
+
};
|
|
950
|
+
var validateValue = (field, value, rules, values, contextOverrides = {}) => {
|
|
906
951
|
const errors = [];
|
|
907
|
-
const context = {
|
|
952
|
+
const context = {
|
|
953
|
+
field,
|
|
954
|
+
value,
|
|
955
|
+
values,
|
|
956
|
+
...contextOverrides
|
|
957
|
+
};
|
|
908
958
|
const required = resolveRule(rules.required);
|
|
909
959
|
const minLength = resolveRule(rules.minLength);
|
|
910
960
|
const maxLength = resolveRule(rules.maxLength);
|
|
911
961
|
const pattern = resolveRule(rules.pattern);
|
|
912
|
-
const
|
|
962
|
+
const numeric = resolveRule(rules.numeric);
|
|
963
|
+
const min = resolveRule(rules.min);
|
|
964
|
+
const max = resolveRule(rules.max);
|
|
913
965
|
if (required.value && !hasValue(value)) {
|
|
914
966
|
errors.push(required.message ?? "This field is required.");
|
|
915
967
|
}
|
|
@@ -927,10 +979,17 @@ var validateFieldValue = (field, value, rules, values) => {
|
|
|
927
979
|
errors.push(pattern.message ?? "Value does not match the required pattern.");
|
|
928
980
|
}
|
|
929
981
|
}
|
|
930
|
-
if (
|
|
931
|
-
const
|
|
932
|
-
if (
|
|
933
|
-
errors.push(
|
|
982
|
+
if (hasValue(value) && (numeric.value || min.value !== void 0 || max.value !== void 0)) {
|
|
983
|
+
const number = parseStrictNumber(value);
|
|
984
|
+
if (number === void 0) {
|
|
985
|
+
errors.push(numeric.message ?? "Value must be a number.");
|
|
986
|
+
} else {
|
|
987
|
+
if (min.value !== void 0 && number < min.value) {
|
|
988
|
+
errors.push(min.message ?? `Minimum value is ${min.value}.`);
|
|
989
|
+
}
|
|
990
|
+
if (max.value !== void 0 && number > max.value) {
|
|
991
|
+
errors.push(max.message ?? `Maximum value is ${max.value}.`);
|
|
992
|
+
}
|
|
934
993
|
}
|
|
935
994
|
}
|
|
936
995
|
const custom = rules.validate ? Array.isArray(rules.validate) ? rules.validate : [rules.validate] : [];
|
|
@@ -941,6 +1000,41 @@ var validateFieldValue = (field, value, rules, values) => {
|
|
|
941
1000
|
}
|
|
942
1001
|
return errors;
|
|
943
1002
|
};
|
|
1003
|
+
var validateFieldValueDetailed = (field, value, rules, values, items) => {
|
|
1004
|
+
const groupErrors = validateValue(field, value, rules, values);
|
|
1005
|
+
const sameAs = resolveRule(rules.sameAs);
|
|
1006
|
+
if (sameAs.value !== void 0) {
|
|
1007
|
+
const otherValue = values[sameAs.value];
|
|
1008
|
+
if (hasValue(value) && hasValue(otherValue) && !valuesAreEqual(value, otherValue)) {
|
|
1009
|
+
groupErrors.push(sameAs.message ?? `Value must match ${sameAs.value}.`);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const itemErrors = [];
|
|
1013
|
+
if (rules.each) {
|
|
1014
|
+
const sourceItems = items ?? (Array.isArray(value) ? value.map((entry) => ({
|
|
1015
|
+
value: typeof entry === "string" ? entry : [entry]
|
|
1016
|
+
})) : [{ value }]);
|
|
1017
|
+
sourceItems.forEach((item, index) => {
|
|
1018
|
+
const overrides = {
|
|
1019
|
+
index
|
|
1020
|
+
};
|
|
1021
|
+
if (item.element) overrides.element = item.element;
|
|
1022
|
+
const messages = validateValue(field, item.value, rules.each, values, overrides);
|
|
1023
|
+
if (messages.length === 0) return;
|
|
1024
|
+
const error = {
|
|
1025
|
+
index,
|
|
1026
|
+
messages
|
|
1027
|
+
};
|
|
1028
|
+
if (item.element) error.element = item.element;
|
|
1029
|
+
itemErrors.push(error);
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
return { groupErrors, itemErrors };
|
|
1033
|
+
};
|
|
1034
|
+
var validateFieldValue = (field, value, rules, values) => {
|
|
1035
|
+
const result = validateFieldValueDetailed(field, value, rules, values);
|
|
1036
|
+
return [...result.groupErrors, ...result.itemErrors.flatMap((item) => item.messages)];
|
|
1037
|
+
};
|
|
944
1038
|
var validateValues = (values, schema) => {
|
|
945
1039
|
const errors = {};
|
|
946
1040
|
for (const [field, rules] of Object.entries(schema)) {
|
|
@@ -982,25 +1076,35 @@ var createFormController = (target, options = {}) => {
|
|
|
982
1076
|
fieldCache: /* @__PURE__ */ new Map(),
|
|
983
1077
|
manualErrors: {},
|
|
984
1078
|
validationErrors: {},
|
|
1079
|
+
validationGroupErrors: {},
|
|
1080
|
+
validationElementErrors: /* @__PURE__ */ new Map(),
|
|
985
1081
|
isValidated: Boolean(normalizedOptions.autoValidate),
|
|
986
1082
|
autoSubmitEnabled: false,
|
|
987
1083
|
autoSubmitDebounce: 0,
|
|
988
1084
|
submitCount: 0,
|
|
1085
|
+
pendingSubmitCount: 0,
|
|
989
1086
|
autoSubmitTimer: null,
|
|
990
1087
|
isDestroyed: false,
|
|
991
1088
|
listeners: [],
|
|
992
1089
|
mutationObserver: null,
|
|
1090
|
+
cleanups: /* @__PURE__ */ new Set(),
|
|
993
1091
|
formattedFields: /* @__PURE__ */ new Map(),
|
|
994
1092
|
api: null
|
|
995
1093
|
};
|
|
996
1094
|
const validationDependents = /* @__PURE__ */ new Map();
|
|
997
1095
|
for (const [field, rules] of Object.entries(state2.validators)) {
|
|
1096
|
+
const sources = /* @__PURE__ */ new Set();
|
|
998
1097
|
const sameAs = rules.sameAs;
|
|
999
|
-
if (sameAs
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1098
|
+
if (sameAs !== void 0) {
|
|
1099
|
+
sources.add(typeof sameAs === "string" ? sameAs : sameAs.value);
|
|
1100
|
+
}
|
|
1101
|
+
if (typeof rules.dependsOn === "string") sources.add(rules.dependsOn);
|
|
1102
|
+
else rules.dependsOn?.forEach((source) => sources.add(source));
|
|
1103
|
+
for (const source of sources) {
|
|
1104
|
+
const dependents = validationDependents.get(source) ?? /* @__PURE__ */ new Set();
|
|
1105
|
+
dependents.add(field);
|
|
1106
|
+
validationDependents.set(source, dependents);
|
|
1107
|
+
}
|
|
1004
1108
|
}
|
|
1005
1109
|
const notifySubscribers = () => {
|
|
1006
1110
|
if (!state2.api) return;
|
|
@@ -1049,18 +1153,21 @@ var createFormController = (target, options = {}) => {
|
|
|
1049
1153
|
const syncVisualState = (names) => {
|
|
1050
1154
|
if (!state2.element) return;
|
|
1051
1155
|
const sourceNames = names ?? getTrackedFieldNames();
|
|
1052
|
-
const errors = getMergedErrors();
|
|
1053
1156
|
for (const name of sourceNames) {
|
|
1054
1157
|
const displayName = resolveDisplayNameForName(state2, name);
|
|
1055
1158
|
const canonical = resolveCanonicalForName(state2, name) ?? name;
|
|
1056
1159
|
const fields = getFieldsByName(displayName);
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1160
|
+
const hasGroupError = Boolean(
|
|
1161
|
+
state2.validationGroupErrors[canonical]?.length || state2.manualErrors[canonical]?.length
|
|
1162
|
+
);
|
|
1163
|
+
const elementErrors = state2.validationElementErrors.get(canonical);
|
|
1164
|
+
fields.forEach((field) => {
|
|
1165
|
+
const hasError = hasGroupError || Boolean(elementErrors?.get(field)?.length);
|
|
1059
1166
|
applyBooleanAttribute(field, attributes.filled, isFieldFilled(field));
|
|
1060
1167
|
applyBooleanAttribute(field, attributes.error, hasError);
|
|
1061
1168
|
if (hasError) field.setAttribute("aria-invalid", "true");
|
|
1062
1169
|
else field.removeAttribute("aria-invalid");
|
|
1063
|
-
}
|
|
1170
|
+
});
|
|
1064
1171
|
}
|
|
1065
1172
|
};
|
|
1066
1173
|
void readFieldValue;
|
|
@@ -1069,17 +1176,38 @@ var createFormController = (target, options = {}) => {
|
|
|
1069
1176
|
const targetNames = names ?? Object.keys(state2.validators);
|
|
1070
1177
|
const values = getValues();
|
|
1071
1178
|
const nextValidationErrors = names ? cloneErrors(state2.validationErrors) : {};
|
|
1179
|
+
const nextGroupErrors = names ? cloneErrors(state2.validationGroupErrors) : {};
|
|
1180
|
+
const nextElementErrors = names ? new Map(state2.validationElementErrors) : /* @__PURE__ */ new Map();
|
|
1072
1181
|
for (const name of targetNames) {
|
|
1073
1182
|
const rules = state2.validators[name];
|
|
1074
1183
|
if (!rules) {
|
|
1075
1184
|
delete nextValidationErrors[name];
|
|
1185
|
+
delete nextGroupErrors[name];
|
|
1186
|
+
nextElementErrors.delete(name);
|
|
1076
1187
|
continue;
|
|
1077
1188
|
}
|
|
1078
|
-
const
|
|
1189
|
+
const fields = getFieldsByName(name);
|
|
1190
|
+
const displayFields = getFieldsByName(resolveDisplayNameForName(state2, name));
|
|
1191
|
+
const items = fields.map((field, index) => ({
|
|
1192
|
+
value: readFieldValue([field]),
|
|
1193
|
+
element: displayFields[index] ?? field
|
|
1194
|
+
}));
|
|
1195
|
+
const result = validateFieldValueDetailed(name, values[name], rules, values, items);
|
|
1196
|
+
const messages = [...result.groupErrors, ...result.itemErrors.flatMap((item) => item.messages)];
|
|
1079
1197
|
if (messages.length > 0) nextValidationErrors[name] = messages;
|
|
1080
1198
|
else delete nextValidationErrors[name];
|
|
1199
|
+
if (result.groupErrors.length > 0) nextGroupErrors[name] = result.groupErrors;
|
|
1200
|
+
else delete nextGroupErrors[name];
|
|
1201
|
+
const perElement = /* @__PURE__ */ new Map();
|
|
1202
|
+
result.itemErrors.forEach((item) => {
|
|
1203
|
+
if (item.element) perElement.set(item.element, item.messages);
|
|
1204
|
+
});
|
|
1205
|
+
if (perElement.size > 0) nextElementErrors.set(name, perElement);
|
|
1206
|
+
else nextElementErrors.delete(name);
|
|
1081
1207
|
}
|
|
1082
1208
|
state2.validationErrors = nextValidationErrors;
|
|
1209
|
+
state2.validationGroupErrors = nextGroupErrors;
|
|
1210
|
+
state2.validationElementErrors = nextElementErrors;
|
|
1083
1211
|
syncVisualState(names);
|
|
1084
1212
|
return {
|
|
1085
1213
|
isValid: Object.keys(getMergedErrors()).length === 0,
|
|
@@ -1173,7 +1301,13 @@ var createFormController = (target, options = {}) => {
|
|
|
1173
1301
|
if (!validation.isValid) {
|
|
1174
1302
|
for (const name of Object.keys(validation.errors)) {
|
|
1175
1303
|
const displayName = resolveDisplayNameForName(state2, name);
|
|
1176
|
-
const
|
|
1304
|
+
const fields = getFieldsByName(displayName);
|
|
1305
|
+
const elementErrors = state2.validationElementErrors.get(name);
|
|
1306
|
+
const field = fields.find((candidate2) => {
|
|
1307
|
+
if (!candidate2.isConnected || candidate2.disabled || candidate2.hidden) return false;
|
|
1308
|
+
if (candidate2 instanceof HTMLInputElement && candidate2.type === "hidden") return false;
|
|
1309
|
+
return elementErrors?.has(candidate2);
|
|
1310
|
+
}) ?? fields.find((candidate2) => {
|
|
1177
1311
|
if (!candidate2.isConnected || candidate2.disabled || candidate2.hidden) return false;
|
|
1178
1312
|
return !(candidate2 instanceof HTMLInputElement && candidate2.type === "hidden");
|
|
1179
1313
|
});
|
|
@@ -1188,18 +1322,35 @@ var createFormController = (target, options = {}) => {
|
|
|
1188
1322
|
const submitter = candidate.submitter instanceof HTMLElement ? candidate.submitter : null;
|
|
1189
1323
|
const { data, formData } = parseFormData(state2.element, submitter);
|
|
1190
1324
|
const snapshot = state2.api.getState();
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1325
|
+
const pending = [];
|
|
1326
|
+
let synchronousError;
|
|
1327
|
+
let hasSynchronousError = false;
|
|
1328
|
+
try {
|
|
1329
|
+
for (const handler of handlers) {
|
|
1330
|
+
const result = handler.callback(state2.element, data, formData, snapshot);
|
|
1331
|
+
if (result && typeof result.then === "function") pending.push(Promise.resolve(result));
|
|
1332
|
+
}
|
|
1333
|
+
} catch (error) {
|
|
1334
|
+
synchronousError = error;
|
|
1335
|
+
hasSynchronousError = true;
|
|
1336
|
+
}
|
|
1337
|
+
if (pending.length > 0) {
|
|
1338
|
+
state2.pendingSubmitCount += 1;
|
|
1339
|
+
notifySubscribers();
|
|
1340
|
+
void Promise.allSettled(pending).then(() => {
|
|
1341
|
+
state2.pendingSubmitCount = Math.max(0, state2.pendingSubmitCount - 1);
|
|
1342
|
+
if (!state2.isDestroyed) notifySubscribers();
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
if (hasSynchronousError) throw synchronousError;
|
|
1194
1346
|
};
|
|
1195
1347
|
const startMutationObserver = () => {
|
|
1196
1348
|
if (!state2.element || typeof MutationObserver === "undefined") return;
|
|
1197
1349
|
state2.mutationObserver = new MutationObserver(() => {
|
|
1198
1350
|
clearFieldCache();
|
|
1199
1351
|
if (state2.isValidated) {
|
|
1200
|
-
syncVisualState();
|
|
1201
1352
|
validateNames();
|
|
1202
|
-
}
|
|
1353
|
+
} else syncVisualState();
|
|
1203
1354
|
notifySubscribers();
|
|
1204
1355
|
});
|
|
1205
1356
|
state2.mutationObserver.observe(state2.element, {
|
|
@@ -1220,6 +1371,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1220
1371
|
return state2.options;
|
|
1221
1372
|
},
|
|
1222
1373
|
onSubmit: createOnSubmit(state2, helpers),
|
|
1374
|
+
addCleanup: createAddCleanup(state2, helpers),
|
|
1223
1375
|
watch: createWatch(state2, helpers),
|
|
1224
1376
|
observe: createObserve(state2, helpers),
|
|
1225
1377
|
unwatch: createUnwatch(state2, helpers),
|
|
@@ -1257,10 +1409,8 @@ var createFormController = (target, options = {}) => {
|
|
|
1257
1409
|
api.format(config);
|
|
1258
1410
|
}
|
|
1259
1411
|
}
|
|
1260
|
-
if (state2.isValidated)
|
|
1261
|
-
|
|
1262
|
-
validateNames();
|
|
1263
|
-
}
|
|
1412
|
+
if (state2.isValidated) validateNames();
|
|
1413
|
+
else syncVisualState();
|
|
1264
1414
|
return api;
|
|
1265
1415
|
};
|
|
1266
1416
|
|