@conform-to/react 1.8.2 → 1.9.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 +11 -11
- package/dist/future/dom.d.ts +36 -0
- package/dist/future/dom.js +226 -0
- package/dist/future/dom.mjs +212 -0
- package/dist/future/hooks.d.ts +145 -54
- package/dist/future/hooks.js +566 -38
- package/dist/future/hooks.mjs +550 -33
- package/dist/future/index.d.ts +4 -3
- package/dist/future/index.js +15 -2
- package/dist/future/index.mjs +2 -2
- package/dist/future/intent.d.ts +35 -0
- package/dist/future/intent.js +305 -0
- package/dist/future/intent.mjs +294 -0
- package/dist/future/state.d.ts +57 -0
- package/dist/future/state.js +318 -0
- package/dist/future/state.mjs +300 -0
- package/dist/future/types.d.ts +374 -0
- package/dist/future/util.d.ts +65 -36
- package/dist/future/util.js +198 -116
- package/dist/future/util.mjs +182 -110
- package/package.json +3 -2
- package/dist/future/context.d.ts +0 -15
- package/dist/future/context.js +0 -12
- package/dist/future/context.mjs +0 -8
package/README.md
CHANGED
|
@@ -7,23 +7,23 @@
|
|
|
7
7
|
╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
Version 1.
|
|
10
|
+
Version 1.9.1 / License MIT / Copyright (c) 2025 Edmund Hung
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Progressively enhance HTML forms with React. Build resilient, type-safe forms with no hassle using web standards.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## Getting Started
|
|
15
15
|
|
|
16
16
|
Check out the overview and tutorial at our website https://conform.guide
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
## Features
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
20
|
+
- Full type safety with schema field inference
|
|
21
|
+
- Standard Schema support with enhanced Zod and Valibot integration
|
|
22
|
+
- Progressive enhancement first design with built-in accessibility features
|
|
23
|
+
- Native Server Actions support for Remix and Next.js
|
|
24
|
+
- Built on web standards for flexible composition with other tools
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
## Documentation
|
|
27
27
|
|
|
28
28
|
- Validation: https://conform.guide/validation
|
|
29
29
|
- Nested object and Array: https://conform.guide/complex-structures
|
|
@@ -31,6 +31,6 @@ Check out the overview and tutorial at our website https://conform.guide
|
|
|
31
31
|
- Intent button: https://conform.guide/intent-button
|
|
32
32
|
- Accessibility Guide: https://conform.guide/accessibility
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
## Support
|
|
35
35
|
|
|
36
36
|
To report a bug, please open an issue on the repository at https://github.com/edmundhung/conform. For feature requests and questions, you can post them in the Discussions section.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Serialize } from '@conform-to/dom/future';
|
|
2
|
+
import type { ErrorContext, FormRef, InputSnapshot, IntentDispatcher } from './types';
|
|
3
|
+
export declare function getFormElement(formRef: FormRef | undefined): HTMLFormElement | null;
|
|
4
|
+
export declare function getSubmitEvent(event: React.FormEvent<HTMLFormElement>): SubmitEvent;
|
|
5
|
+
export declare function initializeField(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, options: {
|
|
6
|
+
defaultValue?: string | string[] | File | File[] | null;
|
|
7
|
+
defaultChecked?: boolean;
|
|
8
|
+
value?: string;
|
|
9
|
+
} | undefined): void;
|
|
10
|
+
/**
|
|
11
|
+
* Makes hidden form inputs focusable with visually hidden styles
|
|
12
|
+
*/
|
|
13
|
+
export declare function makeInputFocusable(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void;
|
|
14
|
+
export declare function getRadioGroupValue(inputs: Array<HTMLInputElement>): string | undefined;
|
|
15
|
+
export declare function getCheckboxGroupValue(inputs: Array<HTMLInputElement>): string[] | undefined;
|
|
16
|
+
export declare function getInputSnapshot(input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): InputSnapshot;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an InputSnapshot based on the provided options:
|
|
19
|
+
* - checkbox/radio: value / defaultChecked
|
|
20
|
+
* - file inputs: defaultValue is File or FileList
|
|
21
|
+
* - select multiple: defaultValue is string array
|
|
22
|
+
* - others: defaultValue is string
|
|
23
|
+
*/
|
|
24
|
+
export declare function createDefaultSnapshot(defaultValue: string | string[] | File | File[] | FileList | null | undefined, defaultChecked: boolean | undefined, value: string | undefined): InputSnapshot;
|
|
25
|
+
/**
|
|
26
|
+
* Focuses the first field with validation errors on default form submission.
|
|
27
|
+
* Does nothing if the submission was triggered with a specific intent (e.g. validate / insert)
|
|
28
|
+
*/
|
|
29
|
+
export declare function focusFirstInvalidField<ErrorShape>(ctx: ErrorContext<ErrorShape>): void;
|
|
30
|
+
export declare function updateFormValue(form: HTMLFormElement, intendedValue: Record<string, unknown>, serialize: Serialize): void;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a proxy that dynamically generates intent dispatch functions.
|
|
33
|
+
* Each property access returns a function that submits the intent to the form.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createIntentDispatcher(formElement: HTMLFormElement | (() => HTMLFormElement | null), intentName: string): IntentDispatcher;
|
|
36
|
+
//# sourceMappingURL=dom.d.ts.map
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var future = require('@conform-to/dom/future');
|
|
6
|
+
var intent = require('./intent.js');
|
|
7
|
+
|
|
8
|
+
function getFormElement(formRef) {
|
|
9
|
+
var _element$form;
|
|
10
|
+
if (typeof formRef === 'string') {
|
|
11
|
+
return document.forms.namedItem(formRef);
|
|
12
|
+
}
|
|
13
|
+
var element = formRef === null || formRef === void 0 ? void 0 : formRef.current;
|
|
14
|
+
if (element instanceof HTMLFormElement) {
|
|
15
|
+
return element;
|
|
16
|
+
}
|
|
17
|
+
return (_element$form = element === null || element === void 0 ? void 0 : element.form) !== null && _element$form !== void 0 ? _element$form : null;
|
|
18
|
+
}
|
|
19
|
+
function getSubmitEvent(event) {
|
|
20
|
+
if (event.type !== 'submit') {
|
|
21
|
+
throw new Error('The event is not a submit event');
|
|
22
|
+
}
|
|
23
|
+
return event.nativeEvent;
|
|
24
|
+
}
|
|
25
|
+
function initializeField(element, options) {
|
|
26
|
+
var _options$value;
|
|
27
|
+
if (element.dataset.conform) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
var defaultValue = typeof (options === null || options === void 0 ? void 0 : options.value) === 'string' || typeof (options === null || options === void 0 ? void 0 : options.defaultChecked) === 'boolean' ? options.defaultChecked ? (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on' : null : options === null || options === void 0 ? void 0 : options.defaultValue;
|
|
31
|
+
|
|
32
|
+
// Update the value of the element, including the default value
|
|
33
|
+
future.updateField(element, {
|
|
34
|
+
value: defaultValue,
|
|
35
|
+
defaultValue
|
|
36
|
+
});
|
|
37
|
+
element.dataset.conform = 'initialized';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Makes hidden form inputs focusable with visually hidden styles
|
|
42
|
+
*/
|
|
43
|
+
function makeInputFocusable(element) {
|
|
44
|
+
if (!element.hidden && element.type !== 'hidden') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Style the element to be visually hidden
|
|
49
|
+
element.style.position = 'absolute';
|
|
50
|
+
element.style.width = '1px';
|
|
51
|
+
element.style.height = '1px';
|
|
52
|
+
element.style.padding = '0';
|
|
53
|
+
element.style.margin = '-1px';
|
|
54
|
+
element.style.overflow = 'hidden';
|
|
55
|
+
element.style.clip = 'rect(0,0,0,0)';
|
|
56
|
+
element.style.whiteSpace = 'nowrap';
|
|
57
|
+
element.style.border = '0';
|
|
58
|
+
|
|
59
|
+
// Hide the element from screen readers
|
|
60
|
+
element.setAttribute('aria-hidden', 'true');
|
|
61
|
+
|
|
62
|
+
// Make sure people won't tab to this element
|
|
63
|
+
element.tabIndex = -1;
|
|
64
|
+
|
|
65
|
+
// Set the element to be visible again so it can be focused
|
|
66
|
+
if (element.hidden) {
|
|
67
|
+
element.hidden = false;
|
|
68
|
+
}
|
|
69
|
+
if (element.type === 'hidden') {
|
|
70
|
+
element.setAttribute('type', 'text');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getRadioGroupValue(inputs) {
|
|
74
|
+
for (var input of inputs) {
|
|
75
|
+
if (input.type === 'radio' && input.checked) {
|
|
76
|
+
return input.value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function getCheckboxGroupValue(inputs) {
|
|
81
|
+
var values;
|
|
82
|
+
for (var input of inputs) {
|
|
83
|
+
if (input.type === 'checkbox') {
|
|
84
|
+
var _values;
|
|
85
|
+
(_values = values) !== null && _values !== void 0 ? _values : values = [];
|
|
86
|
+
if (input.checked) {
|
|
87
|
+
values.push(input.value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return values;
|
|
92
|
+
}
|
|
93
|
+
function getInputSnapshot(input) {
|
|
94
|
+
if (input instanceof HTMLInputElement) {
|
|
95
|
+
switch (input.type) {
|
|
96
|
+
case 'file':
|
|
97
|
+
return {
|
|
98
|
+
files: input.files ? Array.from(input.files) : undefined
|
|
99
|
+
};
|
|
100
|
+
case 'radio':
|
|
101
|
+
case 'checkbox':
|
|
102
|
+
return {
|
|
103
|
+
value: input.value,
|
|
104
|
+
checked: input.checked
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
} else if (input instanceof HTMLSelectElement && input.multiple) {
|
|
108
|
+
return {
|
|
109
|
+
options: Array.from(input.selectedOptions).map(option => option.value)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
value: input.value
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Creates an InputSnapshot based on the provided options:
|
|
119
|
+
* - checkbox/radio: value / defaultChecked
|
|
120
|
+
* - file inputs: defaultValue is File or FileList
|
|
121
|
+
* - select multiple: defaultValue is string array
|
|
122
|
+
* - others: defaultValue is string
|
|
123
|
+
*/
|
|
124
|
+
function createDefaultSnapshot(defaultValue, defaultChecked, value) {
|
|
125
|
+
if (typeof value === 'string' || typeof defaultChecked === 'boolean') {
|
|
126
|
+
return {
|
|
127
|
+
value: value !== null && value !== void 0 ? value : 'on',
|
|
128
|
+
checked: defaultChecked
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (typeof defaultValue === 'string') {
|
|
132
|
+
return {
|
|
133
|
+
value: defaultValue
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(defaultValue)) {
|
|
137
|
+
if (defaultValue.every(item => typeof item === 'string')) {
|
|
138
|
+
return {
|
|
139
|
+
options: defaultValue
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
return {
|
|
143
|
+
files: defaultValue
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (future.isGlobalInstance(defaultValue, 'File')) {
|
|
148
|
+
return {
|
|
149
|
+
files: [defaultValue]
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (future.isGlobalInstance(defaultValue, 'FileList')) {
|
|
153
|
+
return {
|
|
154
|
+
files: Array.from(defaultValue)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Focuses the first field with validation errors on default form submission.
|
|
162
|
+
* Does nothing if the submission was triggered with a specific intent (e.g. validate / insert)
|
|
163
|
+
*/
|
|
164
|
+
function focusFirstInvalidField(ctx) {
|
|
165
|
+
if (ctx.intent) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
for (var element of ctx.formElement.elements) {
|
|
169
|
+
var _ctx$error$fieldError;
|
|
170
|
+
if (future.isFieldElement(element) && (_ctx$error$fieldError = ctx.error.fieldErrors[element.name]) !== null && _ctx$error$fieldError !== void 0 && _ctx$error$fieldError.length) {
|
|
171
|
+
element.focus();
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function updateFormValue(form, intendedValue, serialize) {
|
|
177
|
+
for (var element of form.elements) {
|
|
178
|
+
if (future.isFieldElement(element) && element.name) {
|
|
179
|
+
var value = future.getValueAtPath(intendedValue, element.name);
|
|
180
|
+
var serializedValue = serialize(value);
|
|
181
|
+
if (typeof serializedValue !== 'undefined') {
|
|
182
|
+
future.change(element, serializedValue, {
|
|
183
|
+
preventDefault: true
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Creates a proxy that dynamically generates intent dispatch functions.
|
|
192
|
+
* Each property access returns a function that submits the intent to the form.
|
|
193
|
+
*/
|
|
194
|
+
function createIntentDispatcher(formElement, intentName) {
|
|
195
|
+
return new Proxy({}, {
|
|
196
|
+
get(target, type, receiver) {
|
|
197
|
+
if (typeof type === 'string') {
|
|
198
|
+
var _target$type;
|
|
199
|
+
// @ts-expect-error
|
|
200
|
+
(_target$type = target[type]) !== null && _target$type !== void 0 ? _target$type : target[type] = payload => {
|
|
201
|
+
var form = typeof formElement === 'function' ? formElement() : formElement;
|
|
202
|
+
if (!form) {
|
|
203
|
+
throw new Error("Dispatching \"".concat(type, "\" intent failed; No form element found."));
|
|
204
|
+
}
|
|
205
|
+
future.requestIntent(form, intentName, intent.serializeIntent({
|
|
206
|
+
type,
|
|
207
|
+
payload
|
|
208
|
+
}));
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return Reflect.get(target, type, receiver);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
exports.createDefaultSnapshot = createDefaultSnapshot;
|
|
217
|
+
exports.createIntentDispatcher = createIntentDispatcher;
|
|
218
|
+
exports.focusFirstInvalidField = focusFirstInvalidField;
|
|
219
|
+
exports.getCheckboxGroupValue = getCheckboxGroupValue;
|
|
220
|
+
exports.getFormElement = getFormElement;
|
|
221
|
+
exports.getInputSnapshot = getInputSnapshot;
|
|
222
|
+
exports.getRadioGroupValue = getRadioGroupValue;
|
|
223
|
+
exports.getSubmitEvent = getSubmitEvent;
|
|
224
|
+
exports.initializeField = initializeField;
|
|
225
|
+
exports.makeInputFocusable = makeInputFocusable;
|
|
226
|
+
exports.updateFormValue = updateFormValue;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { updateField, isGlobalInstance, isFieldElement, requestIntent, getValueAtPath, change } from '@conform-to/dom/future';
|
|
2
|
+
import { serializeIntent } from './intent.mjs';
|
|
3
|
+
|
|
4
|
+
function getFormElement(formRef) {
|
|
5
|
+
var _element$form;
|
|
6
|
+
if (typeof formRef === 'string') {
|
|
7
|
+
return document.forms.namedItem(formRef);
|
|
8
|
+
}
|
|
9
|
+
var element = formRef === null || formRef === void 0 ? void 0 : formRef.current;
|
|
10
|
+
if (element instanceof HTMLFormElement) {
|
|
11
|
+
return element;
|
|
12
|
+
}
|
|
13
|
+
return (_element$form = element === null || element === void 0 ? void 0 : element.form) !== null && _element$form !== void 0 ? _element$form : null;
|
|
14
|
+
}
|
|
15
|
+
function getSubmitEvent(event) {
|
|
16
|
+
if (event.type !== 'submit') {
|
|
17
|
+
throw new Error('The event is not a submit event');
|
|
18
|
+
}
|
|
19
|
+
return event.nativeEvent;
|
|
20
|
+
}
|
|
21
|
+
function initializeField(element, options) {
|
|
22
|
+
var _options$value;
|
|
23
|
+
if (element.dataset.conform) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var defaultValue = typeof (options === null || options === void 0 ? void 0 : options.value) === 'string' || typeof (options === null || options === void 0 ? void 0 : options.defaultChecked) === 'boolean' ? options.defaultChecked ? (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on' : null : options === null || options === void 0 ? void 0 : options.defaultValue;
|
|
27
|
+
|
|
28
|
+
// Update the value of the element, including the default value
|
|
29
|
+
updateField(element, {
|
|
30
|
+
value: defaultValue,
|
|
31
|
+
defaultValue
|
|
32
|
+
});
|
|
33
|
+
element.dataset.conform = 'initialized';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Makes hidden form inputs focusable with visually hidden styles
|
|
38
|
+
*/
|
|
39
|
+
function makeInputFocusable(element) {
|
|
40
|
+
if (!element.hidden && element.type !== 'hidden') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Style the element to be visually hidden
|
|
45
|
+
element.style.position = 'absolute';
|
|
46
|
+
element.style.width = '1px';
|
|
47
|
+
element.style.height = '1px';
|
|
48
|
+
element.style.padding = '0';
|
|
49
|
+
element.style.margin = '-1px';
|
|
50
|
+
element.style.overflow = 'hidden';
|
|
51
|
+
element.style.clip = 'rect(0,0,0,0)';
|
|
52
|
+
element.style.whiteSpace = 'nowrap';
|
|
53
|
+
element.style.border = '0';
|
|
54
|
+
|
|
55
|
+
// Hide the element from screen readers
|
|
56
|
+
element.setAttribute('aria-hidden', 'true');
|
|
57
|
+
|
|
58
|
+
// Make sure people won't tab to this element
|
|
59
|
+
element.tabIndex = -1;
|
|
60
|
+
|
|
61
|
+
// Set the element to be visible again so it can be focused
|
|
62
|
+
if (element.hidden) {
|
|
63
|
+
element.hidden = false;
|
|
64
|
+
}
|
|
65
|
+
if (element.type === 'hidden') {
|
|
66
|
+
element.setAttribute('type', 'text');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function getRadioGroupValue(inputs) {
|
|
70
|
+
for (var input of inputs) {
|
|
71
|
+
if (input.type === 'radio' && input.checked) {
|
|
72
|
+
return input.value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getCheckboxGroupValue(inputs) {
|
|
77
|
+
var values;
|
|
78
|
+
for (var input of inputs) {
|
|
79
|
+
if (input.type === 'checkbox') {
|
|
80
|
+
var _values;
|
|
81
|
+
(_values = values) !== null && _values !== void 0 ? _values : values = [];
|
|
82
|
+
if (input.checked) {
|
|
83
|
+
values.push(input.value);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return values;
|
|
88
|
+
}
|
|
89
|
+
function getInputSnapshot(input) {
|
|
90
|
+
if (input instanceof HTMLInputElement) {
|
|
91
|
+
switch (input.type) {
|
|
92
|
+
case 'file':
|
|
93
|
+
return {
|
|
94
|
+
files: input.files ? Array.from(input.files) : undefined
|
|
95
|
+
};
|
|
96
|
+
case 'radio':
|
|
97
|
+
case 'checkbox':
|
|
98
|
+
return {
|
|
99
|
+
value: input.value,
|
|
100
|
+
checked: input.checked
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
} else if (input instanceof HTMLSelectElement && input.multiple) {
|
|
104
|
+
return {
|
|
105
|
+
options: Array.from(input.selectedOptions).map(option => option.value)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
value: input.value
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Creates an InputSnapshot based on the provided options:
|
|
115
|
+
* - checkbox/radio: value / defaultChecked
|
|
116
|
+
* - file inputs: defaultValue is File or FileList
|
|
117
|
+
* - select multiple: defaultValue is string array
|
|
118
|
+
* - others: defaultValue is string
|
|
119
|
+
*/
|
|
120
|
+
function createDefaultSnapshot(defaultValue, defaultChecked, value) {
|
|
121
|
+
if (typeof value === 'string' || typeof defaultChecked === 'boolean') {
|
|
122
|
+
return {
|
|
123
|
+
value: value !== null && value !== void 0 ? value : 'on',
|
|
124
|
+
checked: defaultChecked
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (typeof defaultValue === 'string') {
|
|
128
|
+
return {
|
|
129
|
+
value: defaultValue
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (Array.isArray(defaultValue)) {
|
|
133
|
+
if (defaultValue.every(item => typeof item === 'string')) {
|
|
134
|
+
return {
|
|
135
|
+
options: defaultValue
|
|
136
|
+
};
|
|
137
|
+
} else {
|
|
138
|
+
return {
|
|
139
|
+
files: defaultValue
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (isGlobalInstance(defaultValue, 'File')) {
|
|
144
|
+
return {
|
|
145
|
+
files: [defaultValue]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (isGlobalInstance(defaultValue, 'FileList')) {
|
|
149
|
+
return {
|
|
150
|
+
files: Array.from(defaultValue)
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Focuses the first field with validation errors on default form submission.
|
|
158
|
+
* Does nothing if the submission was triggered with a specific intent (e.g. validate / insert)
|
|
159
|
+
*/
|
|
160
|
+
function focusFirstInvalidField(ctx) {
|
|
161
|
+
if (ctx.intent) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
for (var element of ctx.formElement.elements) {
|
|
165
|
+
var _ctx$error$fieldError;
|
|
166
|
+
if (isFieldElement(element) && (_ctx$error$fieldError = ctx.error.fieldErrors[element.name]) !== null && _ctx$error$fieldError !== void 0 && _ctx$error$fieldError.length) {
|
|
167
|
+
element.focus();
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function updateFormValue(form, intendedValue, serialize) {
|
|
173
|
+
for (var element of form.elements) {
|
|
174
|
+
if (isFieldElement(element) && element.name) {
|
|
175
|
+
var value = getValueAtPath(intendedValue, element.name);
|
|
176
|
+
var serializedValue = serialize(value);
|
|
177
|
+
if (typeof serializedValue !== 'undefined') {
|
|
178
|
+
change(element, serializedValue, {
|
|
179
|
+
preventDefault: true
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Creates a proxy that dynamically generates intent dispatch functions.
|
|
188
|
+
* Each property access returns a function that submits the intent to the form.
|
|
189
|
+
*/
|
|
190
|
+
function createIntentDispatcher(formElement, intentName) {
|
|
191
|
+
return new Proxy({}, {
|
|
192
|
+
get(target, type, receiver) {
|
|
193
|
+
if (typeof type === 'string') {
|
|
194
|
+
var _target$type;
|
|
195
|
+
// @ts-expect-error
|
|
196
|
+
(_target$type = target[type]) !== null && _target$type !== void 0 ? _target$type : target[type] = payload => {
|
|
197
|
+
var form = typeof formElement === 'function' ? formElement() : formElement;
|
|
198
|
+
if (!form) {
|
|
199
|
+
throw new Error("Dispatching \"".concat(type, "\" intent failed; No form element found."));
|
|
200
|
+
}
|
|
201
|
+
requestIntent(form, intentName, serializeIntent({
|
|
202
|
+
type,
|
|
203
|
+
payload
|
|
204
|
+
}));
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return Reflect.get(target, type, receiver);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export { createDefaultSnapshot, createIntentDispatcher, focusFirstInvalidField, getCheckboxGroupValue, getFormElement, getInputSnapshot, getRadioGroupValue, getSubmitEvent, initializeField, makeInputFocusable, updateFormValue };
|