@conform-to/dom 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/dom.d.ts +31 -2
- package/dist/dom.js +91 -24
- package/dist/dom.mjs +85 -22
- package/dist/form.js +37 -32
- package/dist/form.mjs +34 -29
- 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/dist/formdata.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var dom = require('./dom.js');
|
|
7
|
+
var util = require('./util.js');
|
|
8
|
+
|
|
9
|
+
var DEFAULT_INTENT_NAME = '__INTENT__';
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Construct a form data with the submitter value.
|
|
@@ -13,253 +17,231 @@ var submission = require('./submission.js');
|
|
|
13
17
|
*/
|
|
14
18
|
function getFormData(form, submitter) {
|
|
15
19
|
var payload = new FormData(form, submitter);
|
|
16
|
-
if (submitter
|
|
17
|
-
|
|
20
|
+
if (submitter) {
|
|
21
|
+
if (!dom.isSubmitter(submitter)) {
|
|
22
|
+
throw new TypeError('The submitter must be an input or button element with type submit.');
|
|
23
|
+
}
|
|
24
|
+
if (submitter.name) {
|
|
25
|
+
var entries = payload.getAll(submitter.name);
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
// This assumes the submitter value to be always unique, which should be fine in most cases
|
|
28
|
+
if (!entries.includes(submitter.value)) {
|
|
29
|
+
payload.append(submitter.name, submitter.value);
|
|
30
|
+
}
|
|
22
31
|
}
|
|
23
32
|
}
|
|
24
33
|
return payload;
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
|
-
*
|
|
37
|
+
* Convert a string path into an array of segments.
|
|
38
|
+
*
|
|
29
39
|
* @example
|
|
30
40
|
* ```js
|
|
31
|
-
*
|
|
41
|
+
* getPathSegments("object.key"); // → ['object', 'key']
|
|
42
|
+
* getPathSegments("array[0].content"); // → ['array', 0, 'content']
|
|
43
|
+
* getPathSegments("todos[]"); // → ['todos', '']
|
|
32
44
|
* ```
|
|
33
45
|
*/
|
|
34
|
-
function
|
|
35
|
-
if (!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
function getPathSegments(path) {
|
|
47
|
+
if (!path) return [];
|
|
48
|
+
var tokenRegex = /([^.[\]]+)|\[(\d*)\]/g;
|
|
49
|
+
var segments = [];
|
|
50
|
+
var lastIndex = 0,
|
|
51
|
+
match;
|
|
52
|
+
while (match = tokenRegex.exec(path)) {
|
|
53
|
+
// allow a single “.” between tokens
|
|
54
|
+
if (match.index !== lastIndex) {
|
|
55
|
+
if (!(match.index === lastIndex + 1 && path[lastIndex] === '.')) {
|
|
56
|
+
throw new Error("Invalid path syntax at position ".concat(lastIndex, " in \"").concat(path, "\""));
|
|
45
57
|
}
|
|
46
58
|
}
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
var [, key, index] = match;
|
|
60
|
+
if (key !== undefined) {
|
|
61
|
+
if (key === '__proto__' || key === 'constructor') {
|
|
62
|
+
throw new Error("Invalid path segment \"".concat(key, "\""));
|
|
63
|
+
}
|
|
64
|
+
segments.push(key);
|
|
65
|
+
} else if (index === '') {
|
|
66
|
+
segments.push('');
|
|
67
|
+
} else {
|
|
68
|
+
var number = Number(index);
|
|
69
|
+
if (!Number.isInteger(number) || number < 0) {
|
|
70
|
+
throw new Error("Invalid path segment: array index must be a non-negative integer, got ".concat(number));
|
|
71
|
+
}
|
|
72
|
+
segments.push(number);
|
|
73
|
+
}
|
|
74
|
+
lastIndex = tokenRegex.lastIndex;
|
|
75
|
+
}
|
|
76
|
+
if (lastIndex !== path.length) {
|
|
77
|
+
throw new Error("Invalid path syntax at position ".concat(lastIndex, " in \"").concat(path, "\""));
|
|
78
|
+
}
|
|
79
|
+
return segments;
|
|
49
80
|
}
|
|
50
81
|
|
|
51
82
|
/**
|
|
52
|
-
* Returns a formatted name from the
|
|
83
|
+
* Returns a formatted name from the path segments based on the dot and bracket notation.
|
|
84
|
+
*
|
|
53
85
|
* @example
|
|
54
86
|
* ```js
|
|
55
|
-
*
|
|
87
|
+
* formatPathSegments(['object', 'key']); // → "object.key"
|
|
88
|
+
* formatPathSegments(['array', 0, 'content']); // → "array[0].content"
|
|
89
|
+
* formatPathSegments(['todos', '']); // → "todos[]"
|
|
56
90
|
* ```
|
|
57
91
|
*/
|
|
58
|
-
function
|
|
59
|
-
return
|
|
60
|
-
if (typeof path === 'number') {
|
|
61
|
-
return "".concat(name, "[").concat(Number.isNaN(path) ? '' : path, "]");
|
|
62
|
-
}
|
|
63
|
-
if (name === '' || path === '') {
|
|
64
|
-
return [name, path].join('');
|
|
65
|
-
}
|
|
66
|
-
return [name, path].join('.');
|
|
67
|
-
}, '');
|
|
92
|
+
function formatPathSegments(segments) {
|
|
93
|
+
return segments.reduce((path, segment) => appendPathSegment(path, segment), '');
|
|
68
94
|
}
|
|
69
95
|
|
|
70
96
|
/**
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Check if a name match the prefix paths
|
|
79
|
-
*/
|
|
80
|
-
function isPrefix(name, prefix) {
|
|
81
|
-
var paths = getPaths(name);
|
|
82
|
-
var prefixPaths = getPaths(prefix);
|
|
83
|
-
return paths.length >= prefixPaths.length && prefixPaths.every((path, index) => paths[index] === path);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Compare the parent and child paths to get the relative paths
|
|
88
|
-
* Returns null if the child paths do not start with the parent paths
|
|
97
|
+
* Append one more segment onto an existing path string.
|
|
98
|
+
*
|
|
99
|
+
* - segment = `undefined` ⇒ no-op
|
|
100
|
+
* - segment = `""` ⇒ empty brackets "[]"
|
|
101
|
+
* - segment = `number` ⇒ bracket notation "[n]"
|
|
102
|
+
* - segment = `string` ⇒ dot-notation ".prop"
|
|
89
103
|
*/
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return childPaths.slice(parentPaths.length);
|
|
104
|
+
function appendPathSegment(path, segment) {
|
|
105
|
+
// 1) nothing to append
|
|
106
|
+
if (typeof segment === 'undefined') {
|
|
107
|
+
return path !== null && path !== void 0 ? path : '';
|
|
95
108
|
}
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
109
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
var paths = getPaths(name);
|
|
104
|
-
var length = paths.length;
|
|
105
|
-
var lastIndex = length - 1;
|
|
106
|
-
var index = -1;
|
|
107
|
-
var pointer = target;
|
|
108
|
-
while (pointer != null && ++index < length) {
|
|
109
|
-
var _key = paths[index];
|
|
110
|
-
var nextKey = paths[index + 1];
|
|
111
|
-
var newValue = index != lastIndex ? Object.prototype.hasOwnProperty.call(pointer, _key) && pointer[_key] !== null ? pointer[_key] : typeof nextKey === 'number' ? [] : {} : valueFn(pointer[_key]);
|
|
112
|
-
pointer[_key] = newValue;
|
|
113
|
-
pointer = pointer[_key];
|
|
110
|
+
// 2) explicit empty-segment => empty bracket
|
|
111
|
+
if (segment === '') {
|
|
112
|
+
// even as first segment, "[]" is valid
|
|
113
|
+
return "".concat(path, "[]");
|
|
114
114
|
}
|
|
115
|
-
}
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
function getValue(target, name) {
|
|
121
|
-
var pointer = target;
|
|
122
|
-
for (var path of getPaths(name)) {
|
|
123
|
-
if (typeof pointer === 'undefined' || pointer == null) {
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
if (!Object.prototype.hasOwnProperty.call(pointer, path)) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (isPlainObject(pointer) && typeof path === 'string') {
|
|
130
|
-
pointer = pointer[path];
|
|
131
|
-
} else if (Array.isArray(pointer) && typeof path === 'number') {
|
|
132
|
-
pointer = pointer[path];
|
|
133
|
-
} else {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
116
|
+
// 3) numeric index => [n]
|
|
117
|
+
if (typeof segment === 'number') {
|
|
118
|
+
return "".concat(path, "[").concat(segment, "]");
|
|
136
119
|
}
|
|
137
|
-
|
|
120
|
+
|
|
121
|
+
// 4) non-empty string => .prop (no leading dot if no base)
|
|
122
|
+
return path ? "".concat(path, ".").concat(segment) : segment;
|
|
138
123
|
}
|
|
139
124
|
|
|
140
125
|
/**
|
|
141
|
-
*
|
|
126
|
+
* Returns true if `prefix` is a valid leading path of `name`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```js
|
|
130
|
+
* isPrefix("foo.bar.baz", "foo.bar") // → true
|
|
131
|
+
* isPrefix("foo.bar[3].baz", "foo.bar[3]") // → true
|
|
132
|
+
* isPrefix("foo.bar[3].baz", "foo.bar") // → true
|
|
133
|
+
* isPrefix("foo.bar[3].baz", "foo.baz") // → false
|
|
134
|
+
* isPrefix("foo", "foo.bar") // → false
|
|
135
|
+
* ```
|
|
142
136
|
*/
|
|
143
|
-
function
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
|
-
function isGlobalInstance(obj, className) {
|
|
147
|
-
var Ctor = globalThis[className];
|
|
148
|
-
return typeof Ctor === 'function' && obj instanceof Ctor;
|
|
137
|
+
function isPrefix(name, prefix) {
|
|
138
|
+
return getRelativePath(name, getPathSegments(prefix)) !== null;
|
|
149
139
|
}
|
|
150
140
|
|
|
151
141
|
/**
|
|
152
|
-
*
|
|
142
|
+
* Return the segments of `fullPathStr` that come after the `baseSegments` prefix.
|
|
143
|
+
*
|
|
144
|
+
* @param fullPathStr Full path as a dot/bracket string
|
|
145
|
+
* @param basePath Base path, already parsed into segments
|
|
146
|
+
* @returns The “tail” segments, or `null` if `fullPathStr` isn’t nested under `baseSegments`
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```js
|
|
150
|
+
* getRelativePath("foo.bar[0].qux", ["foo","bar"]) // → [0, "qux"]
|
|
151
|
+
* getRelativePath("a.b.c.d", ["a","b"]) // → ["c","d"]
|
|
152
|
+
* getRelativePath("foo", ["foo","bar"]) // → null
|
|
153
|
+
* ```
|
|
153
154
|
*/
|
|
155
|
+
function getRelativePath(name, basePath) {
|
|
156
|
+
var fullPath = getPathSegments(name);
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
var obj = Object.keys(value).sort().reduce((result, key) => {
|
|
159
|
-
var data = normalize(value[key], acceptFile);
|
|
160
|
-
if (typeof data !== 'undefined') {
|
|
161
|
-
result[key] = data;
|
|
162
|
-
}
|
|
163
|
-
return result;
|
|
164
|
-
}, {});
|
|
165
|
-
if (Object.keys(obj).length === 0) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
return obj;
|
|
169
|
-
}
|
|
170
|
-
if (Array.isArray(value)) {
|
|
171
|
-
if (value.length === 0) {
|
|
172
|
-
return undefined;
|
|
173
|
-
}
|
|
174
|
-
return value.map(item => normalize(item, acceptFile));
|
|
175
|
-
}
|
|
176
|
-
if (typeof value === 'string' && value === '' || value === null || isGlobalInstance(value, 'File') && (!acceptFile || value.size === 0)) {
|
|
177
|
-
return;
|
|
158
|
+
// if full is at least as long *and* starts with the base…
|
|
159
|
+
if (fullPath.length >= basePath.length && basePath.every((segment, i) => segment === fullPath[i])) {
|
|
160
|
+
return fullPath.slice(basePath.length);
|
|
178
161
|
}
|
|
179
|
-
return
|
|
162
|
+
return null;
|
|
180
163
|
}
|
|
181
164
|
|
|
182
165
|
/**
|
|
183
|
-
*
|
|
166
|
+
* Assign a value to a target object by following the path segments.
|
|
184
167
|
*/
|
|
185
|
-
function
|
|
186
|
-
var
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (typeof value !== 'undefined') {
|
|
193
|
-
result[prefix] = value;
|
|
168
|
+
function setValueAtPath(target, pathOrSegments, valueOrFn) {
|
|
169
|
+
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
170
|
+
try {
|
|
171
|
+
// 1) normalize + validate path
|
|
172
|
+
var segments = typeof pathOrSegments === 'string' ? getPathSegments(pathOrSegments) : pathOrSegments;
|
|
173
|
+
if (segments.length === 0) {
|
|
174
|
+
throw new Error('Cannot set value at the object root');
|
|
194
175
|
}
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
process(data[i], "".concat(prefix, "[").concat(i, "]"));
|
|
198
|
-
}
|
|
199
|
-
} else if (isPlainObject(data)) {
|
|
200
|
-
for (var [_key2, _value] of Object.entries(data)) {
|
|
201
|
-
process(_value, prefix ? "".concat(prefix, ".").concat(_key2) : _key2);
|
|
202
|
-
}
|
|
176
|
+
if (segments.some((segment, i) => segment === '' && i < segments.length - 1)) {
|
|
177
|
+
throw new Error("Empty brackets '[]' only allowed at end of path (\"".concat(pathOrSegments, "\")"));
|
|
203
178
|
}
|
|
204
|
-
}
|
|
205
|
-
if (data) {
|
|
206
|
-
var _options$prefix;
|
|
207
|
-
process(data, (_options$prefix = options.prefix) !== null && _options$prefix !== void 0 ? _options$prefix : '');
|
|
208
|
-
}
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
function deepEqual(left, right) {
|
|
212
|
-
if (Object.is(left, right)) {
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
if (left == null || right == null) {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
179
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
var
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
180
|
+
// 2) clone root if needed
|
|
181
|
+
var result = options.clone ? _rollupPluginBabelHelpers.objectSpread2({}, target) : target;
|
|
182
|
+
var pointer = result;
|
|
183
|
+
|
|
184
|
+
// 3) drill down, cloning ancestors
|
|
185
|
+
for (var i = 0; i < segments.length - 1; i++) {
|
|
186
|
+
var currentSegment = segments[i];
|
|
187
|
+
var nextSegment = segments[i + 1];
|
|
188
|
+
var child = pointer[currentSegment];
|
|
189
|
+
if (Array.isArray(child)) {
|
|
190
|
+
child = options.clone ? child.slice() : child;
|
|
191
|
+
} else if (util.isPlainObject(child)) {
|
|
192
|
+
child = options.clone ? _rollupPluginBabelHelpers.objectSpread2({}, child) : child;
|
|
193
|
+
} else {
|
|
194
|
+
child = typeof nextSegment === 'number' || nextSegment === '' ? [] : {};
|
|
229
195
|
}
|
|
196
|
+
pointer[currentSegment] = child;
|
|
197
|
+
pointer = child;
|
|
230
198
|
}
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
199
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return false;
|
|
200
|
+
// 4) final set or push
|
|
201
|
+
var last = segments[segments.length - 1];
|
|
202
|
+
var oldValue = pointer[last];
|
|
203
|
+
var newValue = typeof valueOrFn === 'function' ? valueOrFn(oldValue) : valueOrFn;
|
|
204
|
+
if (last === '') {
|
|
205
|
+
if (!Array.isArray(pointer)) {
|
|
206
|
+
throw new Error("Cannot push to non-array at \"".concat(pathOrSegments, "\""));
|
|
242
207
|
}
|
|
208
|
+
pointer.push(newValue);
|
|
209
|
+
} else {
|
|
210
|
+
pointer[last] = newValue;
|
|
243
211
|
}
|
|
244
|
-
return
|
|
212
|
+
return result;
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (options !== null && options !== void 0 && options.silent) {
|
|
215
|
+
return target;
|
|
216
|
+
}
|
|
217
|
+
throw err;
|
|
245
218
|
}
|
|
246
|
-
return false;
|
|
247
219
|
}
|
|
248
220
|
|
|
249
221
|
/**
|
|
250
|
-
*
|
|
251
|
-
* It may contains JSON primitives if the value is updated based on a form intent.
|
|
252
|
-
*/
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* The data of a form submission.
|
|
222
|
+
* Retrive the value from a target object by following the path segments.
|
|
256
223
|
*/
|
|
224
|
+
function getValueAtPath(target, pathOrSegments) {
|
|
225
|
+
var pointer = target;
|
|
226
|
+
var segments = typeof pathOrSegments === 'string' ? getPathSegments(pathOrSegments) : pathOrSegments;
|
|
227
|
+
for (var segment of segments) {
|
|
228
|
+
if (segment === '') {
|
|
229
|
+
throw new Error("Cannot access empty segment \"[]\" in \"".concat(pathOrSegments, "\""));
|
|
230
|
+
}
|
|
231
|
+
if (pointer == null || !Object.prototype.hasOwnProperty.call(pointer, segment)) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
pointer = pointer[segment];
|
|
235
|
+
}
|
|
236
|
+
return pointer;
|
|
237
|
+
}
|
|
257
238
|
|
|
258
239
|
/**
|
|
259
240
|
* Parse `FormData` or `URLSearchParams` into a submission object.
|
|
260
241
|
* This function structures the form values based on the naming convention.
|
|
261
|
-
* It also includes all the field names and the intent
|
|
242
|
+
* It also includes all the field names and extracts the intent from the submission.
|
|
262
243
|
*
|
|
244
|
+
* @see https://conform.guide/api/react/future/parseSubmission
|
|
263
245
|
* @example
|
|
264
246
|
* ```ts
|
|
265
247
|
* const formData = new FormData();
|
|
@@ -269,7 +251,7 @@ function deepEqual(left, right) {
|
|
|
269
251
|
*
|
|
270
252
|
* parseSubmission(formData)
|
|
271
253
|
* // {
|
|
272
|
-
* //
|
|
254
|
+
* // payload: { email: 'test@example.com', password: 'secret' },
|
|
273
255
|
* // fields: ['email', 'password'],
|
|
274
256
|
* // intent: null,
|
|
275
257
|
* // }
|
|
@@ -278,7 +260,7 @@ function deepEqual(left, right) {
|
|
|
278
260
|
* formData.append('intent', 'login');
|
|
279
261
|
* parseSubmission(formData, { intentName: 'intent' })
|
|
280
262
|
* // {
|
|
281
|
-
* //
|
|
263
|
+
* // payload: { email: 'test@example.com', password: 'secret' },
|
|
282
264
|
* // fields: ['email', 'password'],
|
|
283
265
|
* // intent: 'login',
|
|
284
266
|
* // }
|
|
@@ -286,43 +268,88 @@ function deepEqual(left, right) {
|
|
|
286
268
|
*/
|
|
287
269
|
function parseSubmission(formData, options) {
|
|
288
270
|
var _options$intentName;
|
|
289
|
-
var intentName = (_options$intentName = options === null || options === void 0 ? void 0 : options.intentName) !== null && _options$intentName !== void 0 ? _options$intentName :
|
|
290
|
-
var submission
|
|
291
|
-
|
|
271
|
+
var intentName = (_options$intentName = options === null || options === void 0 ? void 0 : options.intentName) !== null && _options$intentName !== void 0 ? _options$intentName : DEFAULT_INTENT_NAME;
|
|
272
|
+
var submission = {
|
|
273
|
+
payload: {},
|
|
292
274
|
fields: [],
|
|
293
275
|
intent: null
|
|
294
276
|
};
|
|
295
|
-
var
|
|
277
|
+
for (var _name of new Set(formData.keys())) {
|
|
296
278
|
var _options$skipEntry;
|
|
297
279
|
if (_name !== intentName && !(options !== null && options !== void 0 && (_options$skipEntry = options.skipEntry) !== null && _options$skipEntry !== void 0 && _options$skipEntry.call(options, _name))) {
|
|
298
|
-
var
|
|
299
|
-
|
|
300
|
-
|
|
280
|
+
var _value = formData.getAll(_name);
|
|
281
|
+
setValueAtPath(submission.payload, _name, _value.length > 1 ? _value : _value[0], {
|
|
282
|
+
silent: true // Avoid errors if the path is invalid
|
|
283
|
+
});
|
|
284
|
+
submission.fields.push(_name);
|
|
301
285
|
}
|
|
302
|
-
};
|
|
303
|
-
for (var _name of new Set(formData.keys())) {
|
|
304
|
-
_loop();
|
|
305
286
|
}
|
|
306
287
|
if (intentName) {
|
|
307
288
|
// We take the first value of the intent field if it exists.
|
|
308
289
|
var intent = formData.get(intentName);
|
|
309
290
|
if (typeof intent === 'string') {
|
|
310
|
-
submission
|
|
291
|
+
submission.intent = intent;
|
|
311
292
|
}
|
|
312
293
|
}
|
|
313
|
-
return submission
|
|
294
|
+
return submission;
|
|
314
295
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Creates a SubmissionResult object from a submission, adding validation results and intended values.
|
|
299
|
+
* This function will remove all files in the submission payload by default since
|
|
300
|
+
* file inputs cannot be initialized with files.
|
|
301
|
+
* You can specify `keepFiles: true` to keep the files if needed.
|
|
302
|
+
*
|
|
303
|
+
* @see https://conform.guide/api/react/future/report
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* // Report the submission with the field errors
|
|
307
|
+
* report(submission, {
|
|
308
|
+
* error: {
|
|
309
|
+
* fieldErrors: {
|
|
310
|
+
* email: ['Invalid email format'],
|
|
311
|
+
* password: ['Password is required'],
|
|
312
|
+
* },
|
|
313
|
+
* })
|
|
314
|
+
*
|
|
315
|
+
* // Report the submission with a form error
|
|
316
|
+
* report(submission, {
|
|
317
|
+
* error: {
|
|
318
|
+
* formErrors: ['Invalid credentials'],
|
|
319
|
+
* },
|
|
320
|
+
* })
|
|
321
|
+
*
|
|
322
|
+
* // Reset the form
|
|
323
|
+
* report(submission, {
|
|
324
|
+
* reset: true,
|
|
325
|
+
* })
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
function report(submission) {
|
|
330
|
+
var _options$error$formEr, _options$error$fieldE;
|
|
331
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
332
|
+
var intendedValue = options.reset ? null : typeof options.intendedValue === 'undefined' || submission.payload === options.intendedValue ? undefined : options.intendedValue && !options.keepFiles ? util.stripFiles(options.intendedValue) : options.intendedValue;
|
|
333
|
+
var error = !options.error ? options.error : {
|
|
334
|
+
formErrors: (_options$error$formEr = options.error.formErrors) !== null && _options$error$formEr !== void 0 ? _options$error$formEr : [],
|
|
335
|
+
fieldErrors: (_options$error$fieldE = options.error.fieldErrors) !== null && _options$error$fieldE !== void 0 ? _options$error$fieldE : {}
|
|
336
|
+
};
|
|
337
|
+
if (options.hideFields) {
|
|
338
|
+
for (var _name2 of options.hideFields) {
|
|
339
|
+
var path = getPathSegments(_name2);
|
|
340
|
+
setValueAtPath(submission.payload, path, undefined);
|
|
341
|
+
if (intendedValue) {
|
|
342
|
+
setValueAtPath(intendedValue, path, undefined);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
324
345
|
}
|
|
325
|
-
return
|
|
346
|
+
return {
|
|
347
|
+
submission: options.keepFiles ? submission : _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, submission), {}, {
|
|
348
|
+
payload: util.stripFiles(submission.payload)
|
|
349
|
+
}),
|
|
350
|
+
intendedValue,
|
|
351
|
+
error
|
|
352
|
+
};
|
|
326
353
|
}
|
|
327
354
|
|
|
328
355
|
/**
|
|
@@ -353,17 +380,37 @@ function isDirty(
|
|
|
353
380
|
* - A plain object that was parsed from form data (i.e. `submission.payload`)
|
|
354
381
|
*/
|
|
355
382
|
formData, options) {
|
|
356
|
-
var _options$serialize;
|
|
357
383
|
if (!formData) {
|
|
358
384
|
return;
|
|
359
385
|
}
|
|
360
386
|
var formValue = formData instanceof FormData || formData instanceof URLSearchParams ? parseSubmission(formData, {
|
|
361
387
|
intentName: options === null || options === void 0 ? void 0 : options.intentName,
|
|
362
388
|
skipEntry: options === null || options === void 0 ? void 0 : options.skipEntry
|
|
363
|
-
}).
|
|
389
|
+
}).payload : formData;
|
|
364
390
|
var defaultValue = options === null || options === void 0 ? void 0 : options.defaultValue;
|
|
365
|
-
var
|
|
366
|
-
|
|
391
|
+
var serializeData = value => {
|
|
392
|
+
if (options !== null && options !== void 0 && options.serialize) {
|
|
393
|
+
return options.serialize(value, serialize);
|
|
394
|
+
}
|
|
395
|
+
return serialize(value);
|
|
396
|
+
};
|
|
397
|
+
function normalize(data) {
|
|
398
|
+
var _serializeData;
|
|
399
|
+
var value = (_serializeData = serializeData(data)) !== null && _serializeData !== void 0 ? _serializeData : data;
|
|
400
|
+
|
|
401
|
+
// Removes empty strings, so that bpth empty string and undefined are treated as the same
|
|
402
|
+
if (value === '') {
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
if (dom.isGlobalInstance(value, 'File')) {
|
|
406
|
+
// Remove empty File as well, which happens if no File was selected
|
|
407
|
+
if (value.name === '' && value.size === 0) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// If the value is a File, no need to serialize it
|
|
412
|
+
return value;
|
|
413
|
+
}
|
|
367
414
|
if (Array.isArray(value)) {
|
|
368
415
|
if (value.length === 0) {
|
|
369
416
|
return undefined;
|
|
@@ -374,7 +421,7 @@ formData, options) {
|
|
|
374
421
|
}
|
|
375
422
|
return array;
|
|
376
423
|
}
|
|
377
|
-
if (isPlainObject(value)) {
|
|
424
|
+
if (util.isPlainObject(value)) {
|
|
378
425
|
var entries = Object.entries(value).reduce((list, _ref) => {
|
|
379
426
|
var [key, value] = _ref;
|
|
380
427
|
var normalizedValue = normalize(value);
|
|
@@ -388,39 +435,92 @@ formData, options) {
|
|
|
388
435
|
}
|
|
389
436
|
return Object.fromEntries(entries);
|
|
390
437
|
}
|
|
438
|
+
return value;
|
|
439
|
+
}
|
|
440
|
+
return !util.deepEqual(normalize(formValue), normalize(defaultValue));
|
|
441
|
+
}
|
|
391
442
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
443
|
+
/**
|
|
444
|
+
* Convert an unknown value into something acceptable for HTML form submission.
|
|
445
|
+
* Returns `undefined` when the value cannot be represented in form data.
|
|
446
|
+
*
|
|
447
|
+
* Input -> Output:
|
|
448
|
+
* - string -> string
|
|
449
|
+
* - null -> '' (empty string)
|
|
450
|
+
* - boolean -> 'on' | '' (checked semantics)
|
|
451
|
+
* - number | bigint -> value.toString()
|
|
452
|
+
* - Date -> value.toISOString()
|
|
453
|
+
* - File -> File
|
|
454
|
+
* - FileList -> File[]
|
|
455
|
+
* - Array -> string[] or File[] if all items serialize to the same kind; otherwise undefined
|
|
456
|
+
* - anything else -> undefined
|
|
457
|
+
*/
|
|
458
|
+
function serialize(value) {
|
|
459
|
+
function serializePrimitive(value) {
|
|
460
|
+
if (typeof value === 'string') {
|
|
461
|
+
return value;
|
|
395
462
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (typeof value === 'string' && value === '') {
|
|
399
|
-
return undefined;
|
|
463
|
+
if (value === null) {
|
|
464
|
+
return '';
|
|
400
465
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
466
|
+
if (typeof value === 'boolean') {
|
|
467
|
+
return value ? 'on' : '';
|
|
468
|
+
}
|
|
469
|
+
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
470
|
+
return value.toString();
|
|
471
|
+
}
|
|
472
|
+
if (value instanceof Date) {
|
|
473
|
+
return value.toISOString();
|
|
474
|
+
}
|
|
475
|
+
if (dom.isGlobalInstance(value, 'File')) {
|
|
476
|
+
return value;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (Array.isArray(value)) {
|
|
480
|
+
var _options = [];
|
|
481
|
+
var files = [];
|
|
482
|
+
for (var item of value) {
|
|
483
|
+
var serialized = serializePrimitive(item);
|
|
484
|
+
if (typeof serialized === 'undefined') {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (typeof serialized === 'string') {
|
|
488
|
+
if (files.length > 0) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
_options.push(serialized);
|
|
492
|
+
} else {
|
|
493
|
+
if (_options.length > 0) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
files.push(serialized);
|
|
497
|
+
}
|
|
405
498
|
}
|
|
406
|
-
|
|
499
|
+
if (_options.length === value.length) {
|
|
500
|
+
return _options;
|
|
501
|
+
}
|
|
502
|
+
if (files.length === value.length) {
|
|
503
|
+
return files;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// If not all items are strings or files, return nothing
|
|
507
|
+
}
|
|
508
|
+
if (dom.isGlobalInstance(value, 'FileList')) {
|
|
509
|
+
return Array.from(value);
|
|
407
510
|
}
|
|
408
|
-
return
|
|
511
|
+
return serializePrimitive(value);
|
|
409
512
|
}
|
|
410
513
|
|
|
411
|
-
exports.
|
|
412
|
-
exports.
|
|
413
|
-
exports.
|
|
414
|
-
exports.formatName = formatName;
|
|
415
|
-
exports.formatPaths = formatPaths;
|
|
416
|
-
exports.getChildPaths = getChildPaths;
|
|
514
|
+
exports.DEFAULT_INTENT_NAME = DEFAULT_INTENT_NAME;
|
|
515
|
+
exports.appendPathSegment = appendPathSegment;
|
|
516
|
+
exports.formatPathSegments = formatPathSegments;
|
|
417
517
|
exports.getFormData = getFormData;
|
|
418
|
-
exports.
|
|
419
|
-
exports.
|
|
518
|
+
exports.getPathSegments = getPathSegments;
|
|
519
|
+
exports.getRelativePath = getRelativePath;
|
|
520
|
+
exports.getValueAtPath = getValueAtPath;
|
|
420
521
|
exports.isDirty = isDirty;
|
|
421
|
-
exports.isGlobalInstance = isGlobalInstance;
|
|
422
|
-
exports.isPlainObject = isPlainObject;
|
|
423
522
|
exports.isPrefix = isPrefix;
|
|
424
|
-
exports.normalize = normalize;
|
|
425
523
|
exports.parseSubmission = parseSubmission;
|
|
426
|
-
exports.
|
|
524
|
+
exports.report = report;
|
|
525
|
+
exports.serialize = serialize;
|
|
526
|
+
exports.setValueAtPath = setValueAtPath;
|