auto-webmcp 0.2.9 → 0.3.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/dist/analyzer.d.ts +7 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/auto-webmcp.cjs.js +156 -21
- package/dist/auto-webmcp.cjs.js.map +2 -2
- package/dist/auto-webmcp.esm.js +156 -21
- package/dist/auto-webmcp.esm.js.map +2 -2
- package/dist/auto-webmcp.iife.js +2 -2
- package/dist/auto-webmcp.iife.js.map +3 -3
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/registry.d.ts +7 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/analyzer.d.ts
CHANGED
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { JsonSchema } from './schema.js';
|
|
5
5
|
import { FormOverride } from './config.js';
|
|
6
|
+
export interface ToolAnnotations {
|
|
7
|
+
readOnlyHint?: boolean;
|
|
8
|
+
destructiveHint?: boolean;
|
|
9
|
+
idempotentHint?: boolean;
|
|
10
|
+
openWorldHint?: boolean;
|
|
11
|
+
}
|
|
6
12
|
export interface ToolMetadata {
|
|
7
13
|
name: string;
|
|
8
14
|
description: string;
|
|
9
15
|
inputSchema: JsonSchema;
|
|
16
|
+
annotations?: ToolAnnotations;
|
|
10
17
|
/** Key → DOM element for fields not addressable by name (id-keyed or ARIA-role controls). */
|
|
11
18
|
fieldElements?: Map<string, Element>;
|
|
12
19
|
}
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;AAynBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,EACzE,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAKd"}
|
package/dist/auto-webmcp.cjs.js
CHANGED
|
@@ -40,22 +40,21 @@ async function registerFormTool(form, metadata, execute) {
|
|
|
40
40
|
if (existing) {
|
|
41
41
|
await unregisterFormTool(form);
|
|
42
42
|
}
|
|
43
|
+
const toolDef = {
|
|
44
|
+
name: metadata.name,
|
|
45
|
+
description: metadata.description,
|
|
46
|
+
inputSchema: metadata.inputSchema,
|
|
47
|
+
execute
|
|
48
|
+
};
|
|
49
|
+
if (metadata.annotations && Object.keys(metadata.annotations).length > 0) {
|
|
50
|
+
toolDef.annotations = metadata.annotations;
|
|
51
|
+
}
|
|
43
52
|
try {
|
|
44
|
-
await navigator.modelContext.registerTool(
|
|
45
|
-
name: metadata.name,
|
|
46
|
-
description: metadata.description,
|
|
47
|
-
inputSchema: metadata.inputSchema,
|
|
48
|
-
execute
|
|
49
|
-
});
|
|
53
|
+
await navigator.modelContext.registerTool(toolDef);
|
|
50
54
|
} catch {
|
|
51
55
|
try {
|
|
52
56
|
await navigator.modelContext.unregisterTool(metadata.name);
|
|
53
|
-
await navigator.modelContext.registerTool(
|
|
54
|
-
name: metadata.name,
|
|
55
|
-
description: metadata.description,
|
|
56
|
-
inputSchema: metadata.inputSchema,
|
|
57
|
-
execute
|
|
58
|
-
});
|
|
57
|
+
await navigator.modelContext.registerTool(toolDef);
|
|
59
58
|
} catch {
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -207,6 +206,14 @@ function buildStringSchema(input) {
|
|
|
207
206
|
}
|
|
208
207
|
return prop;
|
|
209
208
|
}
|
|
209
|
+
var PLACEHOLDER_PATTERNS = /^(select|choose|pick)\b|^--+|---/i;
|
|
210
|
+
function isPlaceholderOption(opt) {
|
|
211
|
+
if (opt.disabled)
|
|
212
|
+
return true;
|
|
213
|
+
if (opt.value !== "")
|
|
214
|
+
return false;
|
|
215
|
+
return PLACEHOLDER_PATTERNS.test(opt.text.trim());
|
|
216
|
+
}
|
|
210
217
|
function mapSelectElement(select) {
|
|
211
218
|
const enumValues = [];
|
|
212
219
|
const oneOf = [];
|
|
@@ -218,7 +225,7 @@ function mapSelectElement(select) {
|
|
|
218
225
|
for (const opt of Array.from(child.children)) {
|
|
219
226
|
if (!(opt instanceof HTMLOptionElement))
|
|
220
227
|
continue;
|
|
221
|
-
if (opt
|
|
228
|
+
if (isPlaceholderOption(opt))
|
|
222
229
|
continue;
|
|
223
230
|
enumValues.push(opt.value);
|
|
224
231
|
const entry = {
|
|
@@ -230,7 +237,7 @@ function mapSelectElement(select) {
|
|
|
230
237
|
oneOf.push(entry);
|
|
231
238
|
}
|
|
232
239
|
} else if (child instanceof HTMLOptionElement) {
|
|
233
|
-
if (child
|
|
240
|
+
if (isPlaceholderOption(child))
|
|
234
241
|
continue;
|
|
235
242
|
enumValues.push(child.value);
|
|
236
243
|
oneOf.push({ const: child.value, title: child.text.trim() || child.value });
|
|
@@ -238,6 +245,9 @@ function mapSelectElement(select) {
|
|
|
238
245
|
}
|
|
239
246
|
if (enumValues.length === 0)
|
|
240
247
|
return { type: "string" };
|
|
248
|
+
if (select.multiple) {
|
|
249
|
+
return { type: "array", items: { type: "string", enum: enumValues } };
|
|
250
|
+
}
|
|
241
251
|
return { type: "string", enum: enumValues, oneOf };
|
|
242
252
|
}
|
|
243
253
|
function collectCheckboxEnum(form, name) {
|
|
@@ -329,7 +339,8 @@ function analyzeForm(form, override) {
|
|
|
329
339
|
const name = override?.name ?? inferToolName(form);
|
|
330
340
|
const description = override?.description ?? inferToolDescription(form);
|
|
331
341
|
const { schema: inputSchema, fieldElements } = buildSchema(form);
|
|
332
|
-
|
|
342
|
+
const annotations = inferAnnotations(form);
|
|
343
|
+
return { name, description, inputSchema, annotations, fieldElements };
|
|
333
344
|
}
|
|
334
345
|
function inferToolName(form) {
|
|
335
346
|
const nativeName = form.getAttribute("toolname");
|
|
@@ -426,6 +437,72 @@ function inferToolDescription(form) {
|
|
|
426
437
|
return pageTitle;
|
|
427
438
|
return "Submit form";
|
|
428
439
|
}
|
|
440
|
+
var READONLY_BUTTON_PATTERNS = /^(search|find|look|filter|browse|view|show|check|preview|get|fetch|retrieve|load)\b/i;
|
|
441
|
+
var DESTRUCTIVE_BUTTON_PATTERNS = /^(delete|remove|cancel|terminate|destroy|purge|revoke|unsubscribe|deactivate)\b/i;
|
|
442
|
+
var DESTRUCTIVE_URL_PATTERNS = /\/(delete|remove|cancel|destroy)\b/i;
|
|
443
|
+
function inferAnnotations(form) {
|
|
444
|
+
const annotations = {};
|
|
445
|
+
if (form.dataset["webmcpReadonly"] !== void 0) {
|
|
446
|
+
annotations.readOnlyHint = form.dataset["webmcpReadonly"] !== "false";
|
|
447
|
+
}
|
|
448
|
+
if (form.dataset["webmcpDestructive"] !== void 0) {
|
|
449
|
+
annotations.destructiveHint = form.dataset["webmcpDestructive"] !== "false";
|
|
450
|
+
}
|
|
451
|
+
if (form.dataset["webmcpIdempotent"] !== void 0) {
|
|
452
|
+
annotations.idempotentHint = form.dataset["webmcpIdempotent"] !== "false";
|
|
453
|
+
}
|
|
454
|
+
if (form.dataset["webmcpOpenworld"] !== void 0) {
|
|
455
|
+
annotations.openWorldHint = form.dataset["webmcpOpenworld"] !== "false";
|
|
456
|
+
}
|
|
457
|
+
if (annotations.readOnlyHint === void 0) {
|
|
458
|
+
const isGet = form.method.toLowerCase() === "get";
|
|
459
|
+
const submitText = getSubmitButtonText(form);
|
|
460
|
+
const isReadLabel = submitText ? READONLY_BUTTON_PATTERNS.test(submitText.trim()) : false;
|
|
461
|
+
if (isGet || isReadLabel)
|
|
462
|
+
annotations.readOnlyHint = true;
|
|
463
|
+
}
|
|
464
|
+
if (annotations.destructiveHint === void 0) {
|
|
465
|
+
const submitText = getSubmitButtonText(form);
|
|
466
|
+
const isDestructiveLabel = submitText ? DESTRUCTIVE_BUTTON_PATTERNS.test(submitText.trim()) : false;
|
|
467
|
+
const isDestructiveUrl = form.action ? DESTRUCTIVE_URL_PATTERNS.test(form.action) : false;
|
|
468
|
+
if (isDestructiveLabel || isDestructiveUrl)
|
|
469
|
+
annotations.destructiveHint = true;
|
|
470
|
+
}
|
|
471
|
+
if (annotations.idempotentHint === void 0) {
|
|
472
|
+
if (annotations.readOnlyHint === true || form.method.toLowerCase() === "get") {
|
|
473
|
+
annotations.idempotentHint = true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (annotations.openWorldHint === void 0) {
|
|
477
|
+
annotations.openWorldHint = annotations.readOnlyHint !== true;
|
|
478
|
+
}
|
|
479
|
+
const hasNonDefault = annotations.readOnlyHint === true || annotations.destructiveHint === true || annotations.idempotentHint === true || annotations.openWorldHint === false;
|
|
480
|
+
return hasNonDefault ? annotations : {};
|
|
481
|
+
}
|
|
482
|
+
function extractDefaultValue(control) {
|
|
483
|
+
if (control instanceof HTMLInputElement) {
|
|
484
|
+
const type = control.type.toLowerCase();
|
|
485
|
+
if (type === "checkbox")
|
|
486
|
+
return control.checked ? true : void 0;
|
|
487
|
+
if (type === "radio")
|
|
488
|
+
return void 0;
|
|
489
|
+
if (type === "number" || type === "range") {
|
|
490
|
+
return control.value !== "" ? parseFloat(control.value) : void 0;
|
|
491
|
+
}
|
|
492
|
+
return control.value !== "" ? control.value : void 0;
|
|
493
|
+
}
|
|
494
|
+
if (control instanceof HTMLTextAreaElement) {
|
|
495
|
+
return control.value !== "" ? control.value : void 0;
|
|
496
|
+
}
|
|
497
|
+
if (control instanceof HTMLSelectElement) {
|
|
498
|
+
if (control.multiple) {
|
|
499
|
+
const selected = Array.from(control.options).filter((o) => o.selected).map((o) => o.value);
|
|
500
|
+
return selected.length > 0 ? selected : void 0;
|
|
501
|
+
}
|
|
502
|
+
return control.value !== "" ? control.value : void 0;
|
|
503
|
+
}
|
|
504
|
+
return void 0;
|
|
505
|
+
}
|
|
429
506
|
function buildSchema(form) {
|
|
430
507
|
const properties = {};
|
|
431
508
|
const required = [];
|
|
@@ -461,11 +538,19 @@ function buildSchema(form) {
|
|
|
461
538
|
const desc = inferFieldDescription(control);
|
|
462
539
|
if (desc)
|
|
463
540
|
schemaProp.description = desc;
|
|
541
|
+
const defaultVal = extractDefaultValue(control);
|
|
542
|
+
if (defaultVal !== void 0)
|
|
543
|
+
schemaProp.default = defaultVal;
|
|
464
544
|
if (control instanceof HTMLInputElement && control.type === "radio") {
|
|
465
545
|
schemaProp.enum = collectRadioEnum(form, fieldKey);
|
|
466
546
|
const radioOneOf = collectRadioOneOf(form, fieldKey);
|
|
467
547
|
if (radioOneOf.length > 0)
|
|
468
548
|
schemaProp.oneOf = radioOneOf;
|
|
549
|
+
const checkedRadio = form.querySelector(
|
|
550
|
+
`input[type="radio"][name="${CSS.escape(fieldKey)}"]:checked`
|
|
551
|
+
);
|
|
552
|
+
if (checkedRadio?.value)
|
|
553
|
+
schemaProp.default = checkedRadio.value;
|
|
469
554
|
}
|
|
470
555
|
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
471
556
|
const checkboxValues = collectCheckboxEnum(form, fieldKey);
|
|
@@ -477,6 +562,13 @@ function buildSchema(form) {
|
|
|
477
562
|
};
|
|
478
563
|
if (schemaProp.description)
|
|
479
564
|
arrayProp.description = schemaProp.description;
|
|
565
|
+
const checkedBoxes = Array.from(
|
|
566
|
+
form.querySelectorAll(
|
|
567
|
+
`input[type="checkbox"][name="${CSS.escape(fieldKey)}"]:checked`
|
|
568
|
+
)
|
|
569
|
+
).map((b) => b.value);
|
|
570
|
+
if (checkedBoxes.length > 0)
|
|
571
|
+
arrayProp.default = checkedBoxes;
|
|
480
572
|
properties[fieldKey] = arrayProp;
|
|
481
573
|
if (control.required)
|
|
482
574
|
required.push(fieldKey);
|
|
@@ -599,6 +691,9 @@ function resolveAriaFieldKey(el) {
|
|
|
599
691
|
return null;
|
|
600
692
|
}
|
|
601
693
|
function inferAriaFieldTitle(el) {
|
|
694
|
+
const nativeTitle = el.getAttribute("toolparamtitle");
|
|
695
|
+
if (nativeTitle?.trim())
|
|
696
|
+
return nativeTitle.trim();
|
|
602
697
|
const htmlEl = el;
|
|
603
698
|
if (htmlEl.dataset?.["webmcpTitle"])
|
|
604
699
|
return htmlEl.dataset["webmcpTitle"];
|
|
@@ -637,6 +732,9 @@ function inferAriaFieldDescription(el) {
|
|
|
637
732
|
return "";
|
|
638
733
|
}
|
|
639
734
|
function inferFieldTitle(control) {
|
|
735
|
+
const nativeTitle = control.getAttribute("toolparamtitle");
|
|
736
|
+
if (nativeTitle?.trim())
|
|
737
|
+
return nativeTitle.trim();
|
|
640
738
|
if ("dataset" in control && control.dataset["webmcpTitle"]) {
|
|
641
739
|
return control.dataset["webmcpTitle"];
|
|
642
740
|
}
|
|
@@ -834,6 +932,7 @@ var lastParams = /* @__PURE__ */ new WeakMap();
|
|
|
834
932
|
var formFieldElements = /* @__PURE__ */ new WeakMap();
|
|
835
933
|
var pendingWarnings = /* @__PURE__ */ new WeakMap();
|
|
836
934
|
var pendingFillWarnings = /* @__PURE__ */ new WeakMap();
|
|
935
|
+
var lastFilledSnapshot = /* @__PURE__ */ new WeakMap();
|
|
837
936
|
var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
838
937
|
var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
839
938
|
var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
|
|
@@ -894,6 +993,7 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
894
993
|
const { resolve } = pending;
|
|
895
994
|
pendingExecutions.delete(form);
|
|
896
995
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
996
|
+
lastFilledSnapshot.delete(form);
|
|
897
997
|
const missing = pendingWarnings.get(form);
|
|
898
998
|
pendingWarnings.delete(form);
|
|
899
999
|
const fillWarnings = pendingFillWarnings.get(form) ?? [];
|
|
@@ -912,6 +1012,7 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
912
1012
|
resolve(result);
|
|
913
1013
|
});
|
|
914
1014
|
form.addEventListener("reset", () => {
|
|
1015
|
+
lastFilledSnapshot.delete(form);
|
|
915
1016
|
window.dispatchEvent(new CustomEvent("toolcancel", { detail: { toolName } }));
|
|
916
1017
|
});
|
|
917
1018
|
}
|
|
@@ -964,16 +1065,30 @@ function findNativeField(form, key) {
|
|
|
964
1065
|
function fillFormFields(form, params) {
|
|
965
1066
|
lastParams.set(form, params);
|
|
966
1067
|
const fieldEls = formFieldElements.get(form);
|
|
1068
|
+
const snapshot = {};
|
|
967
1069
|
for (const [key, value] of Object.entries(params)) {
|
|
968
1070
|
const input = findNativeField(form, key);
|
|
969
1071
|
if (input) {
|
|
970
1072
|
if (input instanceof HTMLInputElement) {
|
|
971
1073
|
fillInput(input, form, key, value);
|
|
1074
|
+
if (input.type === "checkbox") {
|
|
1075
|
+
if (Array.isArray(value)) {
|
|
1076
|
+
const esc = CSS.escape(key);
|
|
1077
|
+
snapshot[key] = Array.from(
|
|
1078
|
+
form.querySelectorAll(`input[type="checkbox"][name="${esc}"]`)
|
|
1079
|
+
).filter((b) => b.checked).map((b) => b.value);
|
|
1080
|
+
} else {
|
|
1081
|
+
snapshot[key] = input.checked;
|
|
1082
|
+
}
|
|
1083
|
+
} else {
|
|
1084
|
+
snapshot[key] = input.value;
|
|
1085
|
+
}
|
|
972
1086
|
} else if (input instanceof HTMLTextAreaElement) {
|
|
973
1087
|
setReactValue(input, String(value ?? ""));
|
|
1088
|
+
snapshot[key] = input.value;
|
|
974
1089
|
} else if (input instanceof HTMLSelectElement) {
|
|
975
|
-
input
|
|
976
|
-
input.
|
|
1090
|
+
fillSelectElement(input, value);
|
|
1091
|
+
snapshot[key] = input.multiple ? Array.from(input.options).filter((o) => o.selected).map((o) => o.value) : input.value;
|
|
977
1092
|
}
|
|
978
1093
|
continue;
|
|
979
1094
|
}
|
|
@@ -990,16 +1105,20 @@ function fillFormFields(form, params) {
|
|
|
990
1105
|
}
|
|
991
1106
|
if (effectiveEl instanceof HTMLInputElement) {
|
|
992
1107
|
fillInput(effectiveEl, form, key, value);
|
|
1108
|
+
snapshot[key] = effectiveEl.type === "checkbox" ? effectiveEl.checked : effectiveEl.value;
|
|
993
1109
|
} else if (effectiveEl instanceof HTMLTextAreaElement) {
|
|
994
1110
|
setReactValue(effectiveEl, String(value ?? ""));
|
|
1111
|
+
snapshot[key] = effectiveEl.value;
|
|
995
1112
|
} else if (effectiveEl instanceof HTMLSelectElement) {
|
|
996
|
-
effectiveEl
|
|
997
|
-
effectiveEl.
|
|
1113
|
+
fillSelectElement(effectiveEl, value);
|
|
1114
|
+
snapshot[key] = effectiveEl.multiple ? Array.from(effectiveEl.options).filter((o) => o.selected).map((o) => o.value) : effectiveEl.value;
|
|
998
1115
|
} else {
|
|
999
1116
|
fillAriaField(effectiveEl, value);
|
|
1117
|
+
snapshot[key] = value;
|
|
1000
1118
|
}
|
|
1001
1119
|
}
|
|
1002
1120
|
}
|
|
1121
|
+
lastFilledSnapshot.set(form, snapshot);
|
|
1003
1122
|
}
|
|
1004
1123
|
function fillInput(input, form, key, value) {
|
|
1005
1124
|
const type = input.type.toLowerCase();
|
|
@@ -1056,6 +1175,18 @@ function fillInput(input, form, key, value) {
|
|
|
1056
1175
|
}
|
|
1057
1176
|
setReactValue(input, String(value ?? ""));
|
|
1058
1177
|
}
|
|
1178
|
+
function fillSelectElement(select, value) {
|
|
1179
|
+
if (select.multiple) {
|
|
1180
|
+
const vals = Array.isArray(value) ? value.map(String) : [String(value ?? "")];
|
|
1181
|
+
for (const opt of Array.from(select.options)) {
|
|
1182
|
+
opt.selected = vals.includes(opt.value);
|
|
1183
|
+
}
|
|
1184
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
select.value = String(value ?? "");
|
|
1188
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1189
|
+
}
|
|
1059
1190
|
function fillAriaField(el, value) {
|
|
1060
1191
|
const role = el.getAttribute("role");
|
|
1061
1192
|
if (role === "checkbox" || role === "switch") {
|
|
@@ -1094,6 +1225,7 @@ function fillAriaField(el, value) {
|
|
|
1094
1225
|
function serializeFormData(form, params, fieldEls) {
|
|
1095
1226
|
const result = {};
|
|
1096
1227
|
const data = new FormData(form);
|
|
1228
|
+
const snapshot = lastFilledSnapshot.get(form);
|
|
1097
1229
|
for (const [key, val] of data.entries()) {
|
|
1098
1230
|
if (result[key] !== void 0) {
|
|
1099
1231
|
const existing = result[key];
|
|
@@ -1110,6 +1242,10 @@ function serializeFormData(form, params, fieldEls) {
|
|
|
1110
1242
|
for (const key of Object.keys(params)) {
|
|
1111
1243
|
if (key in result)
|
|
1112
1244
|
continue;
|
|
1245
|
+
if (snapshot && key in snapshot) {
|
|
1246
|
+
result[key] = snapshot[key];
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1113
1249
|
const el = findNativeField(form, key) ?? fieldEls?.get(key) ?? null;
|
|
1114
1250
|
if (!el)
|
|
1115
1251
|
continue;
|
|
@@ -1148,8 +1284,7 @@ function fillElement(el, value) {
|
|
|
1148
1284
|
} else if (el instanceof HTMLTextAreaElement) {
|
|
1149
1285
|
setReactValue(el, String(value ?? ""));
|
|
1150
1286
|
} else if (el instanceof HTMLSelectElement) {
|
|
1151
|
-
el
|
|
1152
|
-
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1287
|
+
fillSelectElement(el, value);
|
|
1153
1288
|
} else {
|
|
1154
1289
|
fillAriaField(el, value);
|
|
1155
1290
|
}
|