@conform-to/dom 1.8.1 → 1.9.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/README.md +1 -1
- package/dist/dom.d.ts +32 -2
- package/dist/dom.js +111 -24
- package/dist/dom.mjs +104 -22
- package/dist/form.js +51 -40
- package/dist/form.mjs +49 -38
- package/dist/formdata.d.ts +122 -75
- package/dist/formdata.js +341 -241
- package/dist/formdata.mjs +328 -225
- package/dist/future/index.d.ts +5 -0
- package/dist/future/index.js +38 -0
- package/dist/future/index.mjs +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -9
- package/dist/index.mjs +2 -2
- package/dist/submission.d.ts +13 -0
- package/dist/submission.js +81 -15
- package/dist/submission.mjs +77 -13
- package/dist/types.d.ts +99 -0
- package/dist/util.d.ts +11 -0
- package/dist/util.js +67 -0
- package/dist/util.mjs +65 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
Version 1.
|
|
10
|
+
Version 1.9.0 / License MIT / Copyright (c) 2024 Edmund Hung
|
|
11
11
|
|
|
12
12
|
A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.
|
|
13
13
|
|
package/dist/dom.d.ts
CHANGED
|
@@ -10,11 +10,19 @@ export type Submitter = HTMLInputElement | HTMLButtonElement;
|
|
|
10
10
|
export declare function isInputElement(element: Element): element is HTMLInputElement;
|
|
11
11
|
export declare function isSelectElement(element: Element): element is HTMLSelectElement;
|
|
12
12
|
export declare function isTextAreaElement(element: Element): element is HTMLTextAreaElement;
|
|
13
|
+
/**
|
|
14
|
+
* A type guard to checks if the element is a submitter element.
|
|
15
|
+
* A submitter element is either an input or button element with type submit.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isSubmitter(element: HTMLElement): element is HTMLInputElement | HTMLButtonElement;
|
|
13
18
|
/**
|
|
14
19
|
* A type guard to check if the provided element is a field element, which
|
|
15
20
|
* is a form control excluding submit, button and reset type.
|
|
16
21
|
*/
|
|
17
22
|
export declare function isFieldElement(element: unknown): element is FieldElement;
|
|
23
|
+
export declare function isGlobalInstance<ClassName extends {
|
|
24
|
+
[K in keyof typeof globalThis]: (typeof globalThis)[K] extends new (...args: any) => any ? K : never;
|
|
25
|
+
}[keyof typeof globalThis]>(obj: unknown, className: ClassName): obj is InstanceType<(typeof globalThis)[ClassName]>;
|
|
18
26
|
/**
|
|
19
27
|
* Resolves the action from the submit event
|
|
20
28
|
* with respect to the submitter `formaction` attribute.
|
|
@@ -30,11 +38,20 @@ export declare function getFormEncType(event: SubmitEvent): 'application/x-www-f
|
|
|
30
38
|
* with respect to the submitter `formmethod` attribute.
|
|
31
39
|
*/
|
|
32
40
|
export declare function getFormMethod(event: SubmitEvent): 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
41
|
+
/**
|
|
42
|
+
* Creates a submit event that behaves like a real form submission.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createSubmitEvent(submitter?: HTMLElement | null): SubmitEvent;
|
|
33
45
|
/**
|
|
34
46
|
* Trigger a form submit event with an optional submitter.
|
|
35
47
|
* If the submitter is not mounted, it will be appended to the form and removed after submission.
|
|
36
48
|
*/
|
|
37
49
|
export declare function requestSubmit(form: HTMLFormElement | null | undefined, submitter: Submitter | null): void;
|
|
50
|
+
/**
|
|
51
|
+
* Triggers form submission with an intent value. This is achieved by
|
|
52
|
+
* creating a hidden button element with the intent value and then submitting it with the form.
|
|
53
|
+
*/
|
|
54
|
+
export declare function requestIntent(formElement: HTMLFormElement, intentName: string, intentValue: string): void;
|
|
38
55
|
export declare function createFileList(value: File | File[]): FileList;
|
|
39
56
|
type InputCallback = (event: {
|
|
40
57
|
type: 'input' | 'reset' | 'mutation';
|
|
@@ -50,8 +67,20 @@ export declare function createGlobalFormsObserver(): {
|
|
|
50
67
|
onFormUpdate(callback: FormCallback): () => void;
|
|
51
68
|
dispose(): void;
|
|
52
69
|
};
|
|
53
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Change the value of the given field element.
|
|
72
|
+
* Dispatches both `input` and `change` events only if the value is changed.
|
|
73
|
+
*/
|
|
74
|
+
export declare function change(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, value: string | string[] | File | File[] | FileList | null, options?: {
|
|
75
|
+
preventDefault?: boolean;
|
|
76
|
+
}): void;
|
|
77
|
+
/**
|
|
78
|
+
* Dispatches focus and focusin events on the given element.
|
|
79
|
+
*/
|
|
54
80
|
export declare function focus(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void;
|
|
81
|
+
/**
|
|
82
|
+
* Dispatches blur and focusout events on the given element.
|
|
83
|
+
*/
|
|
55
84
|
export declare function blur(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void;
|
|
56
85
|
export declare function normalizeStringValues(value: unknown): string[] | undefined;
|
|
57
86
|
export declare function normalizeFileValues(value: unknown): FileList | undefined;
|
|
@@ -62,6 +91,7 @@ export declare function normalizeFileValues(value: unknown): FileList | undefine
|
|
|
62
91
|
export declare function updateField(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, options: {
|
|
63
92
|
value?: unknown;
|
|
64
93
|
defaultValue?: unknown;
|
|
65
|
-
}):
|
|
94
|
+
}): boolean;
|
|
95
|
+
export declare function isDirtyInput(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): boolean;
|
|
66
96
|
export {};
|
|
67
97
|
//# sourceMappingURL=dom.d.ts.map
|
package/dist/dom.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var formdata = require('./formdata.js');
|
|
6
5
|
var util = require('./util.js');
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -24,6 +23,14 @@ function isTextAreaElement(element) {
|
|
|
24
23
|
return element.tagName === 'TEXTAREA';
|
|
25
24
|
}
|
|
26
25
|
|
|
26
|
+
/**
|
|
27
|
+
* A type guard to checks if the element is a submitter element.
|
|
28
|
+
* A submitter element is either an input or button element with type submit.
|
|
29
|
+
*/
|
|
30
|
+
function isSubmitter(element) {
|
|
31
|
+
return 'type' in element && element.type === 'submit';
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
/**
|
|
28
35
|
* A type guard to check if the provided element is a field element, which
|
|
29
36
|
* is a form control excluding submit, button and reset type.
|
|
@@ -39,6 +46,10 @@ function isFieldElement(element) {
|
|
|
39
46
|
}
|
|
40
47
|
return false;
|
|
41
48
|
}
|
|
49
|
+
function isGlobalInstance(obj, className) {
|
|
50
|
+
var Ctor = globalThis[className];
|
|
51
|
+
return typeof Ctor === 'function' && obj instanceof Ctor;
|
|
52
|
+
}
|
|
42
53
|
|
|
43
54
|
/**
|
|
44
55
|
* Resolves the action from the submit event
|
|
@@ -85,6 +96,17 @@ function getFormMethod(event) {
|
|
|
85
96
|
return 'GET';
|
|
86
97
|
}
|
|
87
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Creates a submit event that behaves like a real form submission.
|
|
101
|
+
*/
|
|
102
|
+
function createSubmitEvent(submitter) {
|
|
103
|
+
return new SubmitEvent('submit', {
|
|
104
|
+
bubbles: true,
|
|
105
|
+
cancelable: true,
|
|
106
|
+
submitter
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
/**
|
|
89
111
|
* Trigger a form submit event with an optional submitter.
|
|
90
112
|
* If the submitter is not mounted, it will be appended to the form and removed after submission.
|
|
@@ -94,14 +116,24 @@ function requestSubmit(form, submitter) {
|
|
|
94
116
|
if (typeof form.requestSubmit === 'function') {
|
|
95
117
|
form.requestSubmit(submitter);
|
|
96
118
|
} else {
|
|
97
|
-
|
|
98
|
-
bubbles: true,
|
|
99
|
-
cancelable: true,
|
|
100
|
-
submitter
|
|
101
|
-
});
|
|
102
|
-
form.dispatchEvent(_event);
|
|
119
|
+
form.dispatchEvent(createSubmitEvent(submitter));
|
|
103
120
|
}
|
|
104
121
|
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Triggers form submission with an intent value. This is achieved by
|
|
125
|
+
* creating a hidden button element with the intent value and then submitting it with the form.
|
|
126
|
+
*/
|
|
127
|
+
function requestIntent(formElement, intentName, intentValue) {
|
|
128
|
+
var submitter = document.createElement('button');
|
|
129
|
+
submitter.name = intentName;
|
|
130
|
+
submitter.value = intentValue;
|
|
131
|
+
submitter.hidden = true;
|
|
132
|
+
submitter.formNoValidate = true;
|
|
133
|
+
formElement.appendChild(submitter);
|
|
134
|
+
requestSubmit(formElement, submitter);
|
|
135
|
+
formElement.removeChild(submitter);
|
|
136
|
+
}
|
|
105
137
|
function createFileList(value) {
|
|
106
138
|
var dataTransfer = new DataTransfer();
|
|
107
139
|
if (Array.isArray(value)) {
|
|
@@ -301,21 +333,40 @@ function createGlobalFormsObserver() {
|
|
|
301
333
|
}
|
|
302
334
|
};
|
|
303
335
|
}
|
|
304
|
-
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Change the value of the given field element.
|
|
339
|
+
* Dispatches both `input` and `change` events only if the value is changed.
|
|
340
|
+
*/
|
|
341
|
+
function change(element, value, options) {
|
|
305
342
|
// The value should be set to the element before dispatching the event
|
|
306
|
-
updateField(element, {
|
|
343
|
+
var isChanged = updateField(element, {
|
|
307
344
|
value
|
|
308
345
|
});
|
|
346
|
+
if (isChanged) {
|
|
347
|
+
var inputEvent = new InputEvent('input', {
|
|
348
|
+
bubbles: true,
|
|
349
|
+
cancelable: true
|
|
350
|
+
});
|
|
351
|
+
var changeEvent = new Event('change', {
|
|
352
|
+
bubbles: true,
|
|
353
|
+
cancelable: true
|
|
354
|
+
});
|
|
355
|
+
if (options !== null && options !== void 0 && options.preventDefault) {
|
|
356
|
+
inputEvent.preventDefault();
|
|
357
|
+
changeEvent.preventDefault();
|
|
358
|
+
}
|
|
309
359
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
element.dispatchEvent(new Event('change', {
|
|
316
|
-
bubbles: true
|
|
317
|
-
}));
|
|
360
|
+
// Dispatch input event with the updated input value
|
|
361
|
+
element.dispatchEvent(inputEvent);
|
|
362
|
+
// Dispatch change event (necessary for select to update the selected option)
|
|
363
|
+
element.dispatchEvent(changeEvent);
|
|
364
|
+
}
|
|
318
365
|
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Dispatches focus and focusin events on the given element.
|
|
369
|
+
*/
|
|
319
370
|
function focus(element) {
|
|
320
371
|
// Only focusin event will be bubbled
|
|
321
372
|
element.dispatchEvent(new FocusEvent('focusin', {
|
|
@@ -323,6 +374,10 @@ function focus(element) {
|
|
|
323
374
|
}));
|
|
324
375
|
element.dispatchEvent(new FocusEvent('focus'));
|
|
325
376
|
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Dispatches blur and focusout events on the given element.
|
|
380
|
+
*/
|
|
326
381
|
function blur(element) {
|
|
327
382
|
// Only focusout event will be bubbled
|
|
328
383
|
element.dispatchEvent(new FocusEvent('focusout', {
|
|
@@ -342,9 +397,9 @@ function normalizeStringValues(value) {
|
|
|
342
397
|
function normalizeFileValues(value) {
|
|
343
398
|
if (typeof value === 'undefined') return undefined;
|
|
344
399
|
if (value === null) return createFileList([]);
|
|
345
|
-
if (
|
|
346
|
-
if (
|
|
347
|
-
if (Array.isArray(value) && value.every(item =>
|
|
400
|
+
if (isGlobalInstance(value, 'File')) return createFileList([value]);
|
|
401
|
+
if (isGlobalInstance(value, 'FileList')) return value;
|
|
402
|
+
if (Array.isArray(value) && value.every(item => isGlobalInstance(item, 'File'))) {
|
|
348
403
|
return createFileList(value);
|
|
349
404
|
}
|
|
350
405
|
throw new Error('Expected File, FileList or File[] for file input');
|
|
@@ -356,15 +411,17 @@ function normalizeFileValues(value) {
|
|
|
356
411
|
*/
|
|
357
412
|
function updateField(element, options) {
|
|
358
413
|
var _value$;
|
|
414
|
+
var isChanged = false;
|
|
359
415
|
if (isInputElement(element)) {
|
|
360
416
|
switch (element.type) {
|
|
361
417
|
case 'file':
|
|
362
418
|
{
|
|
363
419
|
var files = normalizeFileValues(options.value);
|
|
364
|
-
if (files) {
|
|
420
|
+
if (files && element.files !== files) {
|
|
365
421
|
element.files = files;
|
|
422
|
+
isChanged = true;
|
|
366
423
|
}
|
|
367
|
-
return;
|
|
424
|
+
return isChanged;
|
|
368
425
|
}
|
|
369
426
|
case 'checkbox':
|
|
370
427
|
case 'radio':
|
|
@@ -376,13 +433,14 @@ function updateField(element, options) {
|
|
|
376
433
|
if (element.type === 'checkbox' ? checked !== element.checked : checked) {
|
|
377
434
|
// Simulate a click to update the checked state
|
|
378
435
|
element.click();
|
|
436
|
+
isChanged = true;
|
|
379
437
|
}
|
|
380
438
|
element.checked = checked;
|
|
381
439
|
}
|
|
382
440
|
if (_defaultValue) {
|
|
383
441
|
element.defaultChecked = _defaultValue.includes(element.value);
|
|
384
442
|
}
|
|
385
|
-
return;
|
|
443
|
+
return isChanged;
|
|
386
444
|
}
|
|
387
445
|
}
|
|
388
446
|
} else if (isSelectElement(element)) {
|
|
@@ -397,6 +455,7 @@ function updateField(element, options) {
|
|
|
397
455
|
// Update the selected state of the option
|
|
398
456
|
if (option.selected !== selected) {
|
|
399
457
|
option.selected = selected;
|
|
458
|
+
isChanged = true;
|
|
400
459
|
}
|
|
401
460
|
|
|
402
461
|
// Remove the option from the value array
|
|
@@ -424,14 +483,16 @@ function updateField(element, options) {
|
|
|
424
483
|
var missingOptions = new Set([...(_value2 !== null && _value2 !== void 0 ? _value2 : []), ...(_defaultValue2 !== null && _defaultValue2 !== void 0 ? _defaultValue2 : [])]);
|
|
425
484
|
for (var optionValue of missingOptions) {
|
|
426
485
|
element.options.add(new Option(optionValue, optionValue, _defaultValue2 === null || _defaultValue2 === void 0 ? void 0 : _defaultValue2.includes(optionValue), _value2 === null || _value2 === void 0 ? void 0 : _value2.includes(optionValue)));
|
|
486
|
+
isChanged = true;
|
|
427
487
|
}
|
|
428
488
|
|
|
429
489
|
// If the select element is not multiple and the value is an empty array, unset the selected index
|
|
430
490
|
// This is to prevent the select element from showing the first option as selected
|
|
431
491
|
if (shouldUnselect) {
|
|
432
492
|
element.selectedIndex = -1;
|
|
493
|
+
isChanged = true;
|
|
433
494
|
}
|
|
434
|
-
return;
|
|
495
|
+
return isChanged;
|
|
435
496
|
}
|
|
436
497
|
var value = normalizeStringValues(options.value);
|
|
437
498
|
var defaultValue = normalizeStringValues(options.defaultValue);
|
|
@@ -457,26 +518,52 @@ function updateField(element, options) {
|
|
|
457
518
|
} else {
|
|
458
519
|
throw new Error('The given element does not have a value setter');
|
|
459
520
|
}
|
|
521
|
+
isChanged = true;
|
|
460
522
|
}
|
|
461
523
|
if (defaultValue) {
|
|
462
524
|
var _defaultValue$;
|
|
463
525
|
element.defaultValue = (_defaultValue$ = defaultValue[0]) !== null && _defaultValue$ !== void 0 ? _defaultValue$ : '';
|
|
464
526
|
}
|
|
527
|
+
return isChanged;
|
|
528
|
+
}
|
|
529
|
+
function isDirtyInput(element) {
|
|
530
|
+
var _element$files$length, _element$files;
|
|
531
|
+
if (isInputElement(element)) {
|
|
532
|
+
switch (element.type) {
|
|
533
|
+
case 'checkbox':
|
|
534
|
+
case 'radio':
|
|
535
|
+
return element.checked !== element.defaultChecked;
|
|
536
|
+
case 'file':
|
|
537
|
+
return ((_element$files$length = (_element$files = element.files) === null || _element$files === void 0 ? void 0 : _element$files.length) !== null && _element$files$length !== void 0 ? _element$files$length : 0) > 0;
|
|
538
|
+
default:
|
|
539
|
+
return element.value !== element.defaultValue;
|
|
540
|
+
}
|
|
541
|
+
} else if (isSelectElement(element)) {
|
|
542
|
+
return Array.from(element.options).some(option => option.selected !== option.defaultSelected);
|
|
543
|
+
} else if (isTextAreaElement(element)) {
|
|
544
|
+
return element.value !== element.defaultValue;
|
|
545
|
+
}
|
|
546
|
+
return false;
|
|
465
547
|
}
|
|
466
548
|
|
|
467
549
|
exports.blur = blur;
|
|
468
550
|
exports.change = change;
|
|
469
551
|
exports.createFileList = createFileList;
|
|
470
552
|
exports.createGlobalFormsObserver = createGlobalFormsObserver;
|
|
553
|
+
exports.createSubmitEvent = createSubmitEvent;
|
|
471
554
|
exports.focus = focus;
|
|
472
555
|
exports.getFormAction = getFormAction;
|
|
473
556
|
exports.getFormEncType = getFormEncType;
|
|
474
557
|
exports.getFormMethod = getFormMethod;
|
|
558
|
+
exports.isDirtyInput = isDirtyInput;
|
|
475
559
|
exports.isFieldElement = isFieldElement;
|
|
560
|
+
exports.isGlobalInstance = isGlobalInstance;
|
|
476
561
|
exports.isInputElement = isInputElement;
|
|
477
562
|
exports.isSelectElement = isSelectElement;
|
|
563
|
+
exports.isSubmitter = isSubmitter;
|
|
478
564
|
exports.isTextAreaElement = isTextAreaElement;
|
|
479
565
|
exports.normalizeFileValues = normalizeFileValues;
|
|
480
566
|
exports.normalizeStringValues = normalizeStringValues;
|
|
567
|
+
exports.requestIntent = requestIntent;
|
|
481
568
|
exports.requestSubmit = requestSubmit;
|
|
482
569
|
exports.updateField = updateField;
|
package/dist/dom.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isGlobalInstance } from './formdata.mjs';
|
|
2
1
|
import { invariant } from './util.mjs';
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -20,6 +19,14 @@ function isTextAreaElement(element) {
|
|
|
20
19
|
return element.tagName === 'TEXTAREA';
|
|
21
20
|
}
|
|
22
21
|
|
|
22
|
+
/**
|
|
23
|
+
* A type guard to checks if the element is a submitter element.
|
|
24
|
+
* A submitter element is either an input or button element with type submit.
|
|
25
|
+
*/
|
|
26
|
+
function isSubmitter(element) {
|
|
27
|
+
return 'type' in element && element.type === 'submit';
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
* A type guard to check if the provided element is a field element, which
|
|
25
32
|
* is a form control excluding submit, button and reset type.
|
|
@@ -35,6 +42,10 @@ function isFieldElement(element) {
|
|
|
35
42
|
}
|
|
36
43
|
return false;
|
|
37
44
|
}
|
|
45
|
+
function isGlobalInstance(obj, className) {
|
|
46
|
+
var Ctor = globalThis[className];
|
|
47
|
+
return typeof Ctor === 'function' && obj instanceof Ctor;
|
|
48
|
+
}
|
|
38
49
|
|
|
39
50
|
/**
|
|
40
51
|
* Resolves the action from the submit event
|
|
@@ -81,6 +92,17 @@ function getFormMethod(event) {
|
|
|
81
92
|
return 'GET';
|
|
82
93
|
}
|
|
83
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Creates a submit event that behaves like a real form submission.
|
|
97
|
+
*/
|
|
98
|
+
function createSubmitEvent(submitter) {
|
|
99
|
+
return new SubmitEvent('submit', {
|
|
100
|
+
bubbles: true,
|
|
101
|
+
cancelable: true,
|
|
102
|
+
submitter
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
84
106
|
/**
|
|
85
107
|
* Trigger a form submit event with an optional submitter.
|
|
86
108
|
* If the submitter is not mounted, it will be appended to the form and removed after submission.
|
|
@@ -90,14 +112,24 @@ function requestSubmit(form, submitter) {
|
|
|
90
112
|
if (typeof form.requestSubmit === 'function') {
|
|
91
113
|
form.requestSubmit(submitter);
|
|
92
114
|
} else {
|
|
93
|
-
|
|
94
|
-
bubbles: true,
|
|
95
|
-
cancelable: true,
|
|
96
|
-
submitter
|
|
97
|
-
});
|
|
98
|
-
form.dispatchEvent(_event);
|
|
115
|
+
form.dispatchEvent(createSubmitEvent(submitter));
|
|
99
116
|
}
|
|
100
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Triggers form submission with an intent value. This is achieved by
|
|
121
|
+
* creating a hidden button element with the intent value and then submitting it with the form.
|
|
122
|
+
*/
|
|
123
|
+
function requestIntent(formElement, intentName, intentValue) {
|
|
124
|
+
var submitter = document.createElement('button');
|
|
125
|
+
submitter.name = intentName;
|
|
126
|
+
submitter.value = intentValue;
|
|
127
|
+
submitter.hidden = true;
|
|
128
|
+
submitter.formNoValidate = true;
|
|
129
|
+
formElement.appendChild(submitter);
|
|
130
|
+
requestSubmit(formElement, submitter);
|
|
131
|
+
formElement.removeChild(submitter);
|
|
132
|
+
}
|
|
101
133
|
function createFileList(value) {
|
|
102
134
|
var dataTransfer = new DataTransfer();
|
|
103
135
|
if (Array.isArray(value)) {
|
|
@@ -297,21 +329,40 @@ function createGlobalFormsObserver() {
|
|
|
297
329
|
}
|
|
298
330
|
};
|
|
299
331
|
}
|
|
300
|
-
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Change the value of the given field element.
|
|
335
|
+
* Dispatches both `input` and `change` events only if the value is changed.
|
|
336
|
+
*/
|
|
337
|
+
function change(element, value, options) {
|
|
301
338
|
// The value should be set to the element before dispatching the event
|
|
302
|
-
updateField(element, {
|
|
339
|
+
var isChanged = updateField(element, {
|
|
303
340
|
value
|
|
304
341
|
});
|
|
342
|
+
if (isChanged) {
|
|
343
|
+
var inputEvent = new InputEvent('input', {
|
|
344
|
+
bubbles: true,
|
|
345
|
+
cancelable: true
|
|
346
|
+
});
|
|
347
|
+
var changeEvent = new Event('change', {
|
|
348
|
+
bubbles: true,
|
|
349
|
+
cancelable: true
|
|
350
|
+
});
|
|
351
|
+
if (options !== null && options !== void 0 && options.preventDefault) {
|
|
352
|
+
inputEvent.preventDefault();
|
|
353
|
+
changeEvent.preventDefault();
|
|
354
|
+
}
|
|
305
355
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
element.dispatchEvent(new Event('change', {
|
|
312
|
-
bubbles: true
|
|
313
|
-
}));
|
|
356
|
+
// Dispatch input event with the updated input value
|
|
357
|
+
element.dispatchEvent(inputEvent);
|
|
358
|
+
// Dispatch change event (necessary for select to update the selected option)
|
|
359
|
+
element.dispatchEvent(changeEvent);
|
|
360
|
+
}
|
|
314
361
|
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Dispatches focus and focusin events on the given element.
|
|
365
|
+
*/
|
|
315
366
|
function focus(element) {
|
|
316
367
|
// Only focusin event will be bubbled
|
|
317
368
|
element.dispatchEvent(new FocusEvent('focusin', {
|
|
@@ -319,6 +370,10 @@ function focus(element) {
|
|
|
319
370
|
}));
|
|
320
371
|
element.dispatchEvent(new FocusEvent('focus'));
|
|
321
372
|
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Dispatches blur and focusout events on the given element.
|
|
376
|
+
*/
|
|
322
377
|
function blur(element) {
|
|
323
378
|
// Only focusout event will be bubbled
|
|
324
379
|
element.dispatchEvent(new FocusEvent('focusout', {
|
|
@@ -352,15 +407,17 @@ function normalizeFileValues(value) {
|
|
|
352
407
|
*/
|
|
353
408
|
function updateField(element, options) {
|
|
354
409
|
var _value$;
|
|
410
|
+
var isChanged = false;
|
|
355
411
|
if (isInputElement(element)) {
|
|
356
412
|
switch (element.type) {
|
|
357
413
|
case 'file':
|
|
358
414
|
{
|
|
359
415
|
var files = normalizeFileValues(options.value);
|
|
360
|
-
if (files) {
|
|
416
|
+
if (files && element.files !== files) {
|
|
361
417
|
element.files = files;
|
|
418
|
+
isChanged = true;
|
|
362
419
|
}
|
|
363
|
-
return;
|
|
420
|
+
return isChanged;
|
|
364
421
|
}
|
|
365
422
|
case 'checkbox':
|
|
366
423
|
case 'radio':
|
|
@@ -372,13 +429,14 @@ function updateField(element, options) {
|
|
|
372
429
|
if (element.type === 'checkbox' ? checked !== element.checked : checked) {
|
|
373
430
|
// Simulate a click to update the checked state
|
|
374
431
|
element.click();
|
|
432
|
+
isChanged = true;
|
|
375
433
|
}
|
|
376
434
|
element.checked = checked;
|
|
377
435
|
}
|
|
378
436
|
if (_defaultValue) {
|
|
379
437
|
element.defaultChecked = _defaultValue.includes(element.value);
|
|
380
438
|
}
|
|
381
|
-
return;
|
|
439
|
+
return isChanged;
|
|
382
440
|
}
|
|
383
441
|
}
|
|
384
442
|
} else if (isSelectElement(element)) {
|
|
@@ -393,6 +451,7 @@ function updateField(element, options) {
|
|
|
393
451
|
// Update the selected state of the option
|
|
394
452
|
if (option.selected !== selected) {
|
|
395
453
|
option.selected = selected;
|
|
454
|
+
isChanged = true;
|
|
396
455
|
}
|
|
397
456
|
|
|
398
457
|
// Remove the option from the value array
|
|
@@ -420,14 +479,16 @@ function updateField(element, options) {
|
|
|
420
479
|
var missingOptions = new Set([...(_value2 !== null && _value2 !== void 0 ? _value2 : []), ...(_defaultValue2 !== null && _defaultValue2 !== void 0 ? _defaultValue2 : [])]);
|
|
421
480
|
for (var optionValue of missingOptions) {
|
|
422
481
|
element.options.add(new Option(optionValue, optionValue, _defaultValue2 === null || _defaultValue2 === void 0 ? void 0 : _defaultValue2.includes(optionValue), _value2 === null || _value2 === void 0 ? void 0 : _value2.includes(optionValue)));
|
|
482
|
+
isChanged = true;
|
|
423
483
|
}
|
|
424
484
|
|
|
425
485
|
// If the select element is not multiple and the value is an empty array, unset the selected index
|
|
426
486
|
// This is to prevent the select element from showing the first option as selected
|
|
427
487
|
if (shouldUnselect) {
|
|
428
488
|
element.selectedIndex = -1;
|
|
489
|
+
isChanged = true;
|
|
429
490
|
}
|
|
430
|
-
return;
|
|
491
|
+
return isChanged;
|
|
431
492
|
}
|
|
432
493
|
var value = normalizeStringValues(options.value);
|
|
433
494
|
var defaultValue = normalizeStringValues(options.defaultValue);
|
|
@@ -453,11 +514,32 @@ function updateField(element, options) {
|
|
|
453
514
|
} else {
|
|
454
515
|
throw new Error('The given element does not have a value setter');
|
|
455
516
|
}
|
|
517
|
+
isChanged = true;
|
|
456
518
|
}
|
|
457
519
|
if (defaultValue) {
|
|
458
520
|
var _defaultValue$;
|
|
459
521
|
element.defaultValue = (_defaultValue$ = defaultValue[0]) !== null && _defaultValue$ !== void 0 ? _defaultValue$ : '';
|
|
460
522
|
}
|
|
523
|
+
return isChanged;
|
|
524
|
+
}
|
|
525
|
+
function isDirtyInput(element) {
|
|
526
|
+
var _element$files$length, _element$files;
|
|
527
|
+
if (isInputElement(element)) {
|
|
528
|
+
switch (element.type) {
|
|
529
|
+
case 'checkbox':
|
|
530
|
+
case 'radio':
|
|
531
|
+
return element.checked !== element.defaultChecked;
|
|
532
|
+
case 'file':
|
|
533
|
+
return ((_element$files$length = (_element$files = element.files) === null || _element$files === void 0 ? void 0 : _element$files.length) !== null && _element$files$length !== void 0 ? _element$files$length : 0) > 0;
|
|
534
|
+
default:
|
|
535
|
+
return element.value !== element.defaultValue;
|
|
536
|
+
}
|
|
537
|
+
} else if (isSelectElement(element)) {
|
|
538
|
+
return Array.from(element.options).some(option => option.selected !== option.defaultSelected);
|
|
539
|
+
} else if (isTextAreaElement(element)) {
|
|
540
|
+
return element.value !== element.defaultValue;
|
|
541
|
+
}
|
|
542
|
+
return false;
|
|
461
543
|
}
|
|
462
544
|
|
|
463
|
-
export { blur, change, createFileList, createGlobalFormsObserver, focus, getFormAction, getFormEncType, getFormMethod, isFieldElement, isInputElement, isSelectElement, isTextAreaElement, normalizeFileValues, normalizeStringValues, requestSubmit, updateField };
|
|
545
|
+
export { blur, change, createFileList, createGlobalFormsObserver, createSubmitEvent, focus, getFormAction, getFormEncType, getFormMethod, isDirtyInput, isFieldElement, isGlobalInstance, isInputElement, isSelectElement, isSubmitter, isTextAreaElement, normalizeFileValues, normalizeStringValues, requestIntent, requestSubmit, updateField };
|