@samline/forms 2.8.0 → 2.10.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 +29 -1
- package/README.md +43 -31
- package/dist/browser/global.d.ts +49 -3
- package/dist/browser/global.global.js +20 -12
- package/dist/browser/global.global.js.map +1 -1
- package/dist/browser/index.cjs +253 -37
- 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-23VZAYA3.js → chunk-JAEFD56I.js} +254 -38
- package/dist/chunk-JAEFD56I.js.map +1 -0
- package/dist/index.cjs +253 -37
- 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-GzopYPCR.d.cts → registry-CPe_lf8-.d.cts} +50 -4
- package/dist/{registry-GzopYPCR.d.ts → registry-CPe_lf8-.d.ts} +50 -4
- package/package.json +11 -8
- package/dist/chunk-23VZAYA3.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -241,12 +241,37 @@ var restoreCursor = (field, position) => {
|
|
|
241
241
|
var state = null;
|
|
242
242
|
var MISSING_MESSAGE = "[samline/forms] The `format()` and `formatAll()` methods require the @samline/formatter package. Install it with: npm i @samline/formatter (or pnpm/bun/yarn equivalent).";
|
|
243
243
|
var warned = false;
|
|
244
|
+
var phonePromise = null;
|
|
245
|
+
var PHONE_MESSAGE = "[samline/forms] Phone formatting needs `@samline/formatter/phone` (@samline/formatter >= 3.0.0 makes phones opt-in) and it could not be loaded.";
|
|
244
246
|
var warnOnce = () => {
|
|
245
247
|
if (warned) return;
|
|
246
248
|
warned = true;
|
|
247
249
|
console.error(MISSING_MESSAGE);
|
|
248
250
|
};
|
|
249
|
-
var
|
|
251
|
+
var ensurePhone = (formatter) => {
|
|
252
|
+
if (typeof formatter.isPhoneRegistered !== "function") return Promise.resolve(true);
|
|
253
|
+
if (formatter.isPhoneRegistered()) return Promise.resolve(true);
|
|
254
|
+
if (!phonePromise) {
|
|
255
|
+
phonePromise = (async () => {
|
|
256
|
+
try {
|
|
257
|
+
const mod = await import("@samline/formatter/phone");
|
|
258
|
+
mod.registerPhone();
|
|
259
|
+
return true;
|
|
260
|
+
} catch {
|
|
261
|
+
console.error(PHONE_MESSAGE);
|
|
262
|
+
phonePromise = null;
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
})();
|
|
266
|
+
}
|
|
267
|
+
return phonePromise;
|
|
268
|
+
};
|
|
269
|
+
var loadFormatter = async (options = {}) => {
|
|
270
|
+
const formatter = await loadFormatterModule();
|
|
271
|
+
if (!formatter || !options.phone) return formatter;
|
|
272
|
+
return await ensurePhone(formatter) ? formatter : null;
|
|
273
|
+
};
|
|
274
|
+
var loadFormatterModule = () => {
|
|
250
275
|
if (state && state.status === "resolved") {
|
|
251
276
|
if (!state.module) warnOnce();
|
|
252
277
|
return Promise.resolve(state.module);
|
|
@@ -381,7 +406,7 @@ var applyFormat = async (state2, helpers, config) => {
|
|
|
381
406
|
phase1Entries.push(entry);
|
|
382
407
|
}
|
|
383
408
|
}
|
|
384
|
-
const formatter = await loadFormatter();
|
|
409
|
+
const formatter = await loadFormatter({ phone: formatType === "phone" });
|
|
385
410
|
if (state2.isDestroyed) {
|
|
386
411
|
rollbackPhase1(phase1Entries, bucket, state2.formattedFields);
|
|
387
412
|
return;
|
|
@@ -520,6 +545,7 @@ var createDestroy = (state2, _helpers) => () => {
|
|
|
520
545
|
}
|
|
521
546
|
}
|
|
522
547
|
state2.watchedFields.clear();
|
|
548
|
+
state2.groupWatchers.clear();
|
|
523
549
|
state2.subscribers.clear();
|
|
524
550
|
state2.submitHandlers.clear();
|
|
525
551
|
state2.fieldCache.clear();
|
|
@@ -747,9 +773,9 @@ var writeFieldValue = (fields, value) => {
|
|
|
747
773
|
continue;
|
|
748
774
|
}
|
|
749
775
|
if (field instanceof HTMLSelectElement && field.multiple) {
|
|
750
|
-
const
|
|
776
|
+
const selectedValues2 = normalizedArray ?? [normalizedValue];
|
|
751
777
|
for (const option of field.options) {
|
|
752
|
-
option.selected =
|
|
778
|
+
option.selected = selectedValues2.includes(option.value);
|
|
753
779
|
}
|
|
754
780
|
continue;
|
|
755
781
|
}
|
|
@@ -784,8 +810,7 @@ var submitForm = (form2) => {
|
|
|
784
810
|
var createGetValue = (state2, helpers) => (name) => readFieldValue(helpers.getFieldsByName(name));
|
|
785
811
|
|
|
786
812
|
// src/api/observe.ts
|
|
787
|
-
var
|
|
788
|
-
if (state2.isDestroyed) return () => void 0;
|
|
813
|
+
var observeField = (state2, field, callback) => {
|
|
789
814
|
const callbacks = state2.watchedFields.get(field) ?? /* @__PURE__ */ new Set();
|
|
790
815
|
callbacks.add(callback);
|
|
791
816
|
state2.watchedFields.set(field, callbacks);
|
|
@@ -800,6 +825,26 @@ var createObserve = (state2, helpers) => (field, callback) => {
|
|
|
800
825
|
}
|
|
801
826
|
};
|
|
802
827
|
};
|
|
828
|
+
var observeFields = (state2, fields, callback) => {
|
|
829
|
+
const names = Array.from(new Set(fields));
|
|
830
|
+
if (names.length === 0) return () => void 0;
|
|
831
|
+
const entry = { fields: names, callback };
|
|
832
|
+
state2.groupWatchers.add(entry);
|
|
833
|
+
if (state2.element) {
|
|
834
|
+
const values = Object.fromEntries(names.map((name) => [name, state2.api.getValue(name)]));
|
|
835
|
+
callback(values, null, state2.element, state2.api.getState());
|
|
836
|
+
}
|
|
837
|
+
return () => {
|
|
838
|
+
state2.groupWatchers.delete(entry);
|
|
839
|
+
};
|
|
840
|
+
};
|
|
841
|
+
var createObserve = (state2, _helpers) => {
|
|
842
|
+
function observe(field, callback) {
|
|
843
|
+
if (state2.isDestroyed) return () => void 0;
|
|
844
|
+
return Array.isArray(field) ? observeFields(state2, field, callback) : observeField(state2, field, callback);
|
|
845
|
+
}
|
|
846
|
+
return observe;
|
|
847
|
+
};
|
|
803
848
|
|
|
804
849
|
// src/api/on-submit.ts
|
|
805
850
|
var createOnSubmit = (state2, _helpers) => (callback, preventDefault = true) => {
|
|
@@ -871,6 +916,75 @@ var createSetErrors = (state2, helpers) => (fields) => {
|
|
|
871
916
|
return state2.api;
|
|
872
917
|
};
|
|
873
918
|
|
|
919
|
+
// src/api/set-options.ts
|
|
920
|
+
var isGroup = (entry) => typeof entry === "object" && entry !== null && Array.isArray(entry.options);
|
|
921
|
+
var createOption = (entry) => {
|
|
922
|
+
const option = document.createElement("option");
|
|
923
|
+
if (typeof entry === "object") {
|
|
924
|
+
option.value = String(entry.value);
|
|
925
|
+
option.textContent = entry.label ?? String(entry.value);
|
|
926
|
+
option.disabled = Boolean(entry.disabled);
|
|
927
|
+
if (entry.selected) option.defaultSelected = true;
|
|
928
|
+
} else {
|
|
929
|
+
option.value = String(entry);
|
|
930
|
+
option.textContent = String(entry);
|
|
931
|
+
}
|
|
932
|
+
return option;
|
|
933
|
+
};
|
|
934
|
+
var buildNodes = (options) => {
|
|
935
|
+
const nodes = [];
|
|
936
|
+
let hasExplicitSelection = false;
|
|
937
|
+
const track = (option) => {
|
|
938
|
+
if (option.defaultSelected) hasExplicitSelection = true;
|
|
939
|
+
return option;
|
|
940
|
+
};
|
|
941
|
+
for (const entry of options) {
|
|
942
|
+
if (entry === null || entry === void 0) continue;
|
|
943
|
+
if (isGroup(entry)) {
|
|
944
|
+
const group = document.createElement("optgroup");
|
|
945
|
+
group.label = entry.label;
|
|
946
|
+
group.disabled = Boolean(entry.disabled);
|
|
947
|
+
for (const child of entry.options) {
|
|
948
|
+
if (child === null || child === void 0) continue;
|
|
949
|
+
group.appendChild(track(createOption(child)));
|
|
950
|
+
}
|
|
951
|
+
nodes.push(group);
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
nodes.push(track(createOption(entry)));
|
|
955
|
+
}
|
|
956
|
+
return { nodes, hasExplicitSelection };
|
|
957
|
+
};
|
|
958
|
+
var selectedValues = (select) => Array.from(select.selectedOptions, (option) => option.value);
|
|
959
|
+
var restoreSelection = (select, previous) => {
|
|
960
|
+
if (previous.length === 0) return;
|
|
961
|
+
const options = Array.from(select.options);
|
|
962
|
+
if (select.multiple) {
|
|
963
|
+
for (const option of options) option.selected = previous.includes(option.value);
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const match = options.find((option) => option.value === previous[0]);
|
|
967
|
+
if (match) match.selected = true;
|
|
968
|
+
};
|
|
969
|
+
var sameValues = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
|
|
970
|
+
var createSetOptions = (state2, helpers) => (name, options, config = {}) => {
|
|
971
|
+
if (!state2.element || state2.isDestroyed) return state2.api;
|
|
972
|
+
const selects = helpers.getFieldsByName(name).filter((field) => field instanceof HTMLSelectElement);
|
|
973
|
+
if (selects.length === 0) return state2.api;
|
|
974
|
+
const keepValue = config.keepValue ?? true;
|
|
975
|
+
const changed = [];
|
|
976
|
+
for (const select of selects) {
|
|
977
|
+
const previous = selectedValues(select);
|
|
978
|
+
const { nodes, hasExplicitSelection } = buildNodes(options);
|
|
979
|
+
select.replaceChildren(...nodes);
|
|
980
|
+
if (keepValue && !hasExplicitSelection) restoreSelection(select, previous);
|
|
981
|
+
if (!sameValues(previous, selectedValues(select))) changed.push(select);
|
|
982
|
+
}
|
|
983
|
+
helpers.commitOwnMutations(selects);
|
|
984
|
+
changed[0]?.dispatchEvent(new Event("input", { bubbles: true }));
|
|
985
|
+
return state2.api;
|
|
986
|
+
};
|
|
987
|
+
|
|
874
988
|
// src/api/set-value.ts
|
|
875
989
|
var createSetValue = (state2, helpers) => (name, value) => {
|
|
876
990
|
if (state2.isDestroyed) return state2.api;
|
|
@@ -894,28 +1008,46 @@ var createSubscribe = (state2, _helpers) => (listener) => {
|
|
|
894
1008
|
};
|
|
895
1009
|
|
|
896
1010
|
// src/api/unwatch.ts
|
|
897
|
-
var
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1011
|
+
var sameFields = (left, right) => left.length === right.size && left.every((name) => right.has(name));
|
|
1012
|
+
var createUnwatch = (state2, _helpers) => {
|
|
1013
|
+
function unwatch(field, callback) {
|
|
1014
|
+
if (field === void 0 || field === "") {
|
|
1015
|
+
state2.watchedFields.clear();
|
|
1016
|
+
state2.groupWatchers.clear();
|
|
1017
|
+
return state2.api;
|
|
1018
|
+
}
|
|
1019
|
+
if (Array.isArray(field)) {
|
|
1020
|
+
const names = new Set(field);
|
|
1021
|
+
for (const entry of Array.from(state2.groupWatchers)) {
|
|
1022
|
+
if (!sameFields(entry.fields, names)) continue;
|
|
1023
|
+
if (callback && entry.callback !== callback) continue;
|
|
1024
|
+
state2.groupWatchers.delete(entry);
|
|
1025
|
+
}
|
|
1026
|
+
return state2.api;
|
|
1027
|
+
}
|
|
1028
|
+
if (!callback) {
|
|
1029
|
+
state2.watchedFields.delete(field);
|
|
1030
|
+
return state2.api;
|
|
1031
|
+
}
|
|
1032
|
+
const callbacks = state2.watchedFields.get(field);
|
|
1033
|
+
callbacks?.delete(callback);
|
|
1034
|
+
if (callbacks && callbacks.size === 0) {
|
|
1035
|
+
state2.watchedFields.delete(field);
|
|
1036
|
+
}
|
|
904
1037
|
return state2.api;
|
|
905
1038
|
}
|
|
906
|
-
|
|
907
|
-
callbacks?.delete(callback);
|
|
908
|
-
if (callbacks && callbacks.size === 0) {
|
|
909
|
-
state2.watchedFields.delete(field);
|
|
910
|
-
}
|
|
911
|
-
return state2.api;
|
|
1039
|
+
return unwatch;
|
|
912
1040
|
};
|
|
913
1041
|
|
|
914
1042
|
// src/api/watch.ts
|
|
915
|
-
var createWatch = (state2, helpers) =>
|
|
1043
|
+
var createWatch = (state2, helpers) => {
|
|
916
1044
|
const observe = createObserve(state2, helpers);
|
|
917
|
-
|
|
918
|
-
|
|
1045
|
+
function watch(field, callback) {
|
|
1046
|
+
if (Array.isArray(field)) observe(field, callback);
|
|
1047
|
+
else observe(field, callback);
|
|
1048
|
+
return state2.api;
|
|
1049
|
+
}
|
|
1050
|
+
return watch;
|
|
919
1051
|
};
|
|
920
1052
|
|
|
921
1053
|
// src/core/validation.ts
|
|
@@ -1083,6 +1215,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1083
1215
|
attributes,
|
|
1084
1216
|
validators: normalizedOptions.validators ?? {},
|
|
1085
1217
|
watchedFields: /* @__PURE__ */ new Map(),
|
|
1218
|
+
groupWatchers: /* @__PURE__ */ new Set(),
|
|
1086
1219
|
subscribers: /* @__PURE__ */ new Set(),
|
|
1087
1220
|
submitHandlers: /* @__PURE__ */ new Set(),
|
|
1088
1221
|
fieldCache: /* @__PURE__ */ new Map(),
|
|
@@ -1253,7 +1386,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1253
1386
|
}
|
|
1254
1387
|
return affected;
|
|
1255
1388
|
};
|
|
1256
|
-
const
|
|
1389
|
+
const emitSingleWatchers = (name) => {
|
|
1257
1390
|
if (!state2.element || !state2.api) return;
|
|
1258
1391
|
const callbacks = state2.watchedFields.get(name);
|
|
1259
1392
|
if (!callbacks || callbacks.size === 0) return;
|
|
@@ -1262,6 +1395,23 @@ var createFormController = (target, options = {}) => {
|
|
|
1262
1395
|
const snapshot = state2.api.getState();
|
|
1263
1396
|
callbacks.forEach((callback) => callback(value, fieldElement, state2.element, snapshot));
|
|
1264
1397
|
};
|
|
1398
|
+
const emitGroupWatchers = (names) => {
|
|
1399
|
+
if (!state2.element || !state2.api || state2.groupWatchers.size === 0) return;
|
|
1400
|
+
let snapshot;
|
|
1401
|
+
for (const entry of Array.from(state2.groupWatchers)) {
|
|
1402
|
+
const changed = names ? names.find((name) => entry.fields.includes(name)) : null;
|
|
1403
|
+
if (changed === void 0) continue;
|
|
1404
|
+
snapshot ?? (snapshot = state2.api.getState());
|
|
1405
|
+
const values = Object.fromEntries(
|
|
1406
|
+
entry.fields.map((field) => [field, state2.api.getValue(field)])
|
|
1407
|
+
);
|
|
1408
|
+
entry.callback(values, changed, state2.element, snapshot);
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
const emitFieldWatchers = (name) => {
|
|
1412
|
+
emitSingleWatchers(name);
|
|
1413
|
+
emitGroupWatchers([name]);
|
|
1414
|
+
};
|
|
1265
1415
|
const runAutoSubmit = () => {
|
|
1266
1416
|
state2.autoSubmitTimer = null;
|
|
1267
1417
|
if (!state2.element || state2.isDestroyed || !state2.autoSubmitEnabled) return;
|
|
@@ -1282,8 +1432,20 @@ var createFormController = (target, options = {}) => {
|
|
|
1282
1432
|
}
|
|
1283
1433
|
runAutoSubmit();
|
|
1284
1434
|
};
|
|
1435
|
+
const selectSnapshots = /* @__PURE__ */ new WeakMap();
|
|
1436
|
+
const readSelectSnapshot = (select) => Array.from(select.selectedOptions, (option) => option.value).join("\0");
|
|
1437
|
+
const snapshotSelect = (select) => {
|
|
1438
|
+
selectSnapshots.set(select, readSelectSnapshot(select));
|
|
1439
|
+
};
|
|
1440
|
+
const snapshotAllSelects = () => {
|
|
1441
|
+
if (!state2.element) return;
|
|
1442
|
+
for (const field of getNamedFields(state2.element)) {
|
|
1443
|
+
if (field instanceof HTMLSelectElement) snapshotSelect(field);
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1285
1446
|
const emitAllFieldWatchers = () => {
|
|
1286
|
-
for (const name of Array.from(state2.watchedFields.keys()))
|
|
1447
|
+
for (const name of Array.from(state2.watchedFields.keys())) emitSingleWatchers(name);
|
|
1448
|
+
emitGroupWatchers(null);
|
|
1287
1449
|
};
|
|
1288
1450
|
const applyReset = () => {
|
|
1289
1451
|
if (!state2.element || state2.isDestroyed) return;
|
|
@@ -1295,6 +1457,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1295
1457
|
state2.validationElementErrors.clear();
|
|
1296
1458
|
clearAttributes(state2.element, [attributes.error, attributes.filled, "aria-invalid"]);
|
|
1297
1459
|
syncVisualState();
|
|
1460
|
+
snapshotAllSelects();
|
|
1298
1461
|
emitAllFieldWatchers();
|
|
1299
1462
|
notifySubscribers();
|
|
1300
1463
|
};
|
|
@@ -1309,7 +1472,8 @@ var createFormController = (target, options = {}) => {
|
|
|
1309
1472
|
validateNames,
|
|
1310
1473
|
emitFieldWatchers,
|
|
1311
1474
|
scheduleAutoSubmit,
|
|
1312
|
-
applyReset
|
|
1475
|
+
applyReset,
|
|
1476
|
+
commitOwnMutations: (selects) => commitOwnMutations(selects)
|
|
1313
1477
|
};
|
|
1314
1478
|
const handleDelegatedEvent = (event) => {
|
|
1315
1479
|
const target2 = event.target;
|
|
@@ -1317,6 +1481,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1317
1481
|
const name = target2.name;
|
|
1318
1482
|
if (!name) return;
|
|
1319
1483
|
clearFieldCache();
|
|
1484
|
+
if (target2 instanceof HTMLSelectElement) snapshotSelect(target2);
|
|
1320
1485
|
const canonical = resolveCanonicalForName(state2, name) ?? name;
|
|
1321
1486
|
const displayName = resolveDisplayNameForName(state2, name);
|
|
1322
1487
|
if (normalizedOptions.clearManualErrorsOnChange) {
|
|
@@ -1327,8 +1492,9 @@ var createFormController = (target, options = {}) => {
|
|
|
1327
1492
|
if (state2.isValidated && affectedValidationNames.some((field) => state2.validators[field] !== void 0)) {
|
|
1328
1493
|
validateNames(affectedValidationNames);
|
|
1329
1494
|
}
|
|
1330
|
-
|
|
1331
|
-
if (canonical !== name)
|
|
1495
|
+
emitSingleWatchers(canonical);
|
|
1496
|
+
if (canonical !== name) emitSingleWatchers(name);
|
|
1497
|
+
emitGroupWatchers(canonical !== name ? [canonical, name] : [canonical]);
|
|
1332
1498
|
notifySubscribers();
|
|
1333
1499
|
scheduleAutoSubmit();
|
|
1334
1500
|
};
|
|
@@ -1357,6 +1523,10 @@ var createFormController = (target, options = {}) => {
|
|
|
1357
1523
|
};
|
|
1358
1524
|
const handleSubmitEvent = (event) => {
|
|
1359
1525
|
if (!state2.element || state2.isDestroyed || !state2.api) return;
|
|
1526
|
+
if (!state2.isAutoSubmitting && state2.autoSubmitTimer) {
|
|
1527
|
+
clearTimeout(state2.autoSubmitTimer);
|
|
1528
|
+
state2.autoSubmitTimer = null;
|
|
1529
|
+
}
|
|
1360
1530
|
if (normalizedOptions.clearErrorsOnSubmit) state2.manualErrors = {};
|
|
1361
1531
|
const validation = state2.api.validate();
|
|
1362
1532
|
const handlers = Array.from(state2.submitHandlers);
|
|
@@ -1409,18 +1579,62 @@ var createFormController = (target, options = {}) => {
|
|
|
1409
1579
|
const cancel = () => clearTimeout(timer);
|
|
1410
1580
|
state2.cleanups.add(cancel);
|
|
1411
1581
|
};
|
|
1582
|
+
const touchesFields = (node) => node instanceof Element && (isFieldElement(node) || node.querySelector("input, select, textarea") !== null);
|
|
1583
|
+
const isStructural = (record) => record.type === "attributes" || Array.from(record.addedNodes).some(touchesFields) || Array.from(record.removedNodes).some(touchesFields);
|
|
1584
|
+
const isOptionNode = (node) => node instanceof HTMLOptionElement || node instanceof HTMLOptGroupElement;
|
|
1585
|
+
const optionListOwner = (record) => {
|
|
1586
|
+
if (record.type !== "childList") return null;
|
|
1587
|
+
const touchesOptions = Array.from(record.addedNodes).some(isOptionNode) || Array.from(record.removedNodes).some(isOptionNode);
|
|
1588
|
+
if (!touchesOptions) return null;
|
|
1589
|
+
const target2 = record.target;
|
|
1590
|
+
if (target2 instanceof HTMLSelectElement) return target2;
|
|
1591
|
+
if (target2 instanceof HTMLOptGroupElement && target2.parentElement instanceof HTMLSelectElement) {
|
|
1592
|
+
return target2.parentElement;
|
|
1593
|
+
}
|
|
1594
|
+
return null;
|
|
1595
|
+
};
|
|
1596
|
+
const handleMutations = (records) => {
|
|
1597
|
+
if (state2.isDestroyed) return;
|
|
1598
|
+
const structural = records.some(isStructural);
|
|
1599
|
+
const changedNames = /* @__PURE__ */ new Set();
|
|
1600
|
+
for (const record of records) {
|
|
1601
|
+
const select = optionListOwner(record);
|
|
1602
|
+
if (!select || !select.name) continue;
|
|
1603
|
+
const next = readSelectSnapshot(select);
|
|
1604
|
+
if (selectSnapshots.get(select) !== next) changedNames.add(select.name);
|
|
1605
|
+
selectSnapshots.set(select, next);
|
|
1606
|
+
}
|
|
1607
|
+
if (!structural && changedNames.size === 0) return;
|
|
1608
|
+
clearFieldCache();
|
|
1609
|
+
if (structural) {
|
|
1610
|
+
snapshotAllSelects();
|
|
1611
|
+
if (state2.isValidated) validateNames();
|
|
1612
|
+
else syncVisualState();
|
|
1613
|
+
} else {
|
|
1614
|
+
const affected = /* @__PURE__ */ new Set();
|
|
1615
|
+
for (const name of changedNames) {
|
|
1616
|
+
for (const field of getAffectedValidationNames(name)) affected.add(field);
|
|
1617
|
+
}
|
|
1618
|
+
const names = Array.from(affected);
|
|
1619
|
+
syncVisualState(Array.from(changedNames));
|
|
1620
|
+
if (state2.isValidated && names.some((field) => state2.validators[field] !== void 0)) {
|
|
1621
|
+
validateNames(names);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
for (const name of changedNames) emitFieldWatchers(name);
|
|
1625
|
+
notifySubscribers();
|
|
1626
|
+
};
|
|
1627
|
+
const commitOwnMutations = (selects) => {
|
|
1628
|
+
selects.forEach(snapshotSelect);
|
|
1629
|
+
const pending = state2.mutationObserver?.takeRecords() ?? [];
|
|
1630
|
+
const foreign = pending.filter(
|
|
1631
|
+
(record) => !selects.some((select) => select.contains(record.target))
|
|
1632
|
+
);
|
|
1633
|
+
if (foreign.length > 0) handleMutations(foreign);
|
|
1634
|
+
};
|
|
1412
1635
|
const startMutationObserver = () => {
|
|
1413
1636
|
if (!state2.element || typeof MutationObserver === "undefined") return;
|
|
1414
|
-
|
|
1415
|
-
const isRelevant = (record) => record.type === "attributes" || Array.from(record.addedNodes).some(touchesFields) || Array.from(record.removedNodes).some(touchesFields);
|
|
1416
|
-
state2.mutationObserver = new MutationObserver((records) => {
|
|
1417
|
-
if (state2.isDestroyed || !records.some(isRelevant)) return;
|
|
1418
|
-
clearFieldCache();
|
|
1419
|
-
if (state2.isValidated) {
|
|
1420
|
-
validateNames();
|
|
1421
|
-
} else syncVisualState();
|
|
1422
|
-
notifySubscribers();
|
|
1423
|
-
});
|
|
1637
|
+
state2.mutationObserver = new MutationObserver(handleMutations);
|
|
1424
1638
|
state2.mutationObserver.observe(state2.element, {
|
|
1425
1639
|
childList: true,
|
|
1426
1640
|
subtree: true,
|
|
@@ -1449,6 +1663,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1449
1663
|
setErrors: createSetErrors(state2, helpers),
|
|
1450
1664
|
clearErrors: createClearErrors(state2, helpers),
|
|
1451
1665
|
setValue: createSetValue(state2, helpers),
|
|
1666
|
+
setOptions: createSetOptions(state2, helpers),
|
|
1452
1667
|
getValue: createGetValue(state2, helpers),
|
|
1453
1668
|
getField: createGetField(state2, helpers),
|
|
1454
1669
|
validate: createValidate(state2, helpers),
|
|
@@ -1468,6 +1683,7 @@ var createFormController = (target, options = {}) => {
|
|
|
1468
1683
|
addListener2(document, "input", handleExternalDelegatedEvent);
|
|
1469
1684
|
addListener2(state2.element, "submit", handleSubmitEvent);
|
|
1470
1685
|
addListener2(state2.element, "reset", handleResetEvent);
|
|
1686
|
+
snapshotAllSelects();
|
|
1471
1687
|
startMutationObserver();
|
|
1472
1688
|
}
|
|
1473
1689
|
if (normalizedOptions.autoSubmit) {
|