@conform-to/dom 1.1.2 → 1.1.4
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 +1 -1
- package/form.js +7 -3
- package/form.mjs +8 -4
- package/formdata.d.ts +2 -2
- package/formdata.js +13 -35
- package/formdata.mjs +13 -35
- package/intent.d.ts +82 -0
- package/intent.js +136 -0
- package/intent.mjs +126 -0
- package/package.json +58 -41
- package/parse.d.ts +30 -0
- package/parse.js +43 -0
- package/parse.mjs +37 -0
- package/rollup.config.js +100 -0
- package/submission.d.ts +7 -7
- package/submission.js +23 -21
- package/submission.mjs +23 -21
- package/types.d.ts +20 -0
package/README
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
Version 1.1.
|
|
11
|
+
Version 1.1.3 / License MIT / Copyright (c) 2024 Edmund Hung
|
|
12
12
|
|
|
13
13
|
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.
|
|
14
14
|
|
package/form.js
CHANGED
|
@@ -51,6 +51,7 @@ function setFieldsValidated(meta, fields) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
function handleIntent(meta, intent, fields, initialized) {
|
|
54
|
+
var _fields$filter;
|
|
54
55
|
if (!intent) {
|
|
55
56
|
setFieldsValidated(meta, fields);
|
|
56
57
|
return;
|
|
@@ -73,7 +74,7 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
73
74
|
} = intent.payload;
|
|
74
75
|
var _name2 = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
75
76
|
if (typeof value !== 'undefined') {
|
|
76
|
-
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '',
|
|
77
|
+
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', value);
|
|
77
78
|
}
|
|
78
79
|
if (typeof validated !== 'undefined') {
|
|
79
80
|
// Clean up previous validated state
|
|
@@ -133,9 +134,10 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
133
134
|
break;
|
|
134
135
|
}
|
|
135
136
|
}
|
|
137
|
+
var validatedFields = (_fields$filter = fields === null || fields === void 0 ? void 0 : fields.filter(name => meta.validated[name])) !== null && _fields$filter !== void 0 ? _fields$filter : [];
|
|
136
138
|
meta.error = Object.entries(meta.error).reduce((result, _ref3) => {
|
|
137
139
|
var [name, error] = _ref3;
|
|
138
|
-
if (meta.validated[name]) {
|
|
140
|
+
if (meta.validated[name] || validatedFields.some(field => formdata.isPrefix(name, field))) {
|
|
139
141
|
result[name] = error;
|
|
140
142
|
}
|
|
141
143
|
return result;
|
|
@@ -145,7 +147,9 @@ function updateValue(meta, name, value) {
|
|
|
145
147
|
if (name === '') {
|
|
146
148
|
meta.initialValue = value;
|
|
147
149
|
meta.value = value;
|
|
148
|
-
meta.key = getDefaultKey(value)
|
|
150
|
+
meta.key = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getDefaultKey(value)), {}, {
|
|
151
|
+
'': util.generateId()
|
|
152
|
+
});
|
|
149
153
|
return;
|
|
150
154
|
}
|
|
151
155
|
meta.initialValue = util.clone(meta.initialValue);
|
package/form.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
-
import { flatten, formatName, getValue, isPlainObject, setValue, normalize, getFormData, getPaths, formatPaths
|
|
2
|
+
import { flatten, formatName, getValue, isPlainObject, isPrefix, setValue, normalize, getFormData, getPaths, formatPaths } from './formdata.mjs';
|
|
3
3
|
import { getFormAction, getFormEncType, getFormMethod, isFieldElement, requestSubmit } from './dom.mjs';
|
|
4
4
|
import { generateId, clone, invariant } from './util.mjs';
|
|
5
5
|
import { serialize, setListState, setListValue, setState, INTENT, serializeIntent, root, getSubmissionContext } from './submission.mjs';
|
|
@@ -47,6 +47,7 @@ function setFieldsValidated(meta, fields) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
function handleIntent(meta, intent, fields, initialized) {
|
|
50
|
+
var _fields$filter;
|
|
50
51
|
if (!intent) {
|
|
51
52
|
setFieldsValidated(meta, fields);
|
|
52
53
|
return;
|
|
@@ -69,7 +70,7 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
69
70
|
} = intent.payload;
|
|
70
71
|
var _name2 = formatName(intent.payload.name, intent.payload.index);
|
|
71
72
|
if (typeof value !== 'undefined') {
|
|
72
|
-
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '',
|
|
73
|
+
updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', value);
|
|
73
74
|
}
|
|
74
75
|
if (typeof validated !== 'undefined') {
|
|
75
76
|
// Clean up previous validated state
|
|
@@ -129,9 +130,10 @@ function handleIntent(meta, intent, fields, initialized) {
|
|
|
129
130
|
break;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
133
|
+
var validatedFields = (_fields$filter = fields === null || fields === void 0 ? void 0 : fields.filter(name => meta.validated[name])) !== null && _fields$filter !== void 0 ? _fields$filter : [];
|
|
132
134
|
meta.error = Object.entries(meta.error).reduce((result, _ref3) => {
|
|
133
135
|
var [name, error] = _ref3;
|
|
134
|
-
if (meta.validated[name]) {
|
|
136
|
+
if (meta.validated[name] || validatedFields.some(field => isPrefix(name, field))) {
|
|
135
137
|
result[name] = error;
|
|
136
138
|
}
|
|
137
139
|
return result;
|
|
@@ -141,7 +143,9 @@ function updateValue(meta, name, value) {
|
|
|
141
143
|
if (name === '') {
|
|
142
144
|
meta.initialValue = value;
|
|
143
145
|
meta.value = value;
|
|
144
|
-
meta.key = getDefaultKey(value)
|
|
146
|
+
meta.key = _objectSpread2(_objectSpread2({}, getDefaultKey(value)), {}, {
|
|
147
|
+
'': generateId()
|
|
148
|
+
});
|
|
145
149
|
return;
|
|
146
150
|
}
|
|
147
151
|
meta.initialValue = clone(meta.initialValue);
|
package/formdata.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export declare function normalize(value: unknown, acceptFile?: boolean): unknown
|
|
|
55
55
|
/**
|
|
56
56
|
* Flatten a tree into a dictionary
|
|
57
57
|
*/
|
|
58
|
-
export declare function flatten(data:
|
|
59
|
-
resolve?: (data: unknown) => unknown
|
|
58
|
+
export declare function flatten(data: unknown, options?: {
|
|
59
|
+
resolve?: (data: unknown) => unknown;
|
|
60
60
|
prefix?: string;
|
|
61
61
|
}): Record<string, unknown>;
|
package/formdata.js
CHANGED
|
@@ -93,7 +93,7 @@ function setValue(target, name, valueFn) {
|
|
|
93
93
|
while (pointer != null && ++index < length) {
|
|
94
94
|
var key = paths[index];
|
|
95
95
|
var nextKey = paths[index + 1];
|
|
96
|
-
var newValue = index != lastIndex ? Object.prototype.hasOwnProperty.call(pointer, key) ? pointer[key] : typeof nextKey === 'number' ? [] : {} : valueFn(pointer[key]);
|
|
96
|
+
var newValue = index != lastIndex ? Object.prototype.hasOwnProperty.call(pointer, key) && pointer[key] !== null ? pointer[key] : typeof nextKey === 'number' ? [] : {} : valueFn(pointer[key]);
|
|
97
97
|
pointer[key] = newValue;
|
|
98
98
|
pointer = pointer[key];
|
|
99
99
|
}
|
|
@@ -174,51 +174,29 @@ function normalize(value) {
|
|
|
174
174
|
/**
|
|
175
175
|
* Flatten a tree into a dictionary
|
|
176
176
|
*/
|
|
177
|
-
function flatten(data
|
|
177
|
+
function flatten(data) {
|
|
178
178
|
var _options$resolve;
|
|
179
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
179
180
|
var result = {};
|
|
180
|
-
var resolve = (_options$resolve = options
|
|
181
|
-
function
|
|
181
|
+
var resolve = (_options$resolve = options.resolve) !== null && _options$resolve !== void 0 ? _options$resolve : data => data;
|
|
182
|
+
function process(data, prefix) {
|
|
182
183
|
var value = normalize(resolve(data));
|
|
183
184
|
if (typeof value !== 'undefined') {
|
|
184
|
-
result[
|
|
185
|
+
result[prefix] = value;
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
for (var [key, _value] of Object.entries(obj)) {
|
|
190
|
-
var name = prefix ? "".concat(prefix, ".").concat(key) : key;
|
|
191
|
-
if (Array.isArray(_value)) {
|
|
192
|
-
processArray(_value, name);
|
|
193
|
-
} else if (_value && isPlainObject(_value)) {
|
|
194
|
-
processObject(_value, name);
|
|
195
|
-
} else {
|
|
196
|
-
setResult(_value, name);
|
|
187
|
+
if (Array.isArray(data)) {
|
|
188
|
+
for (var i = 0; i < data.length; i++) {
|
|
189
|
+
process(data[i], "".concat(prefix, "[").concat(i, "]"));
|
|
197
190
|
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
setResult(array, prefix);
|
|
202
|
-
for (var i = 0; i < array.length; i++) {
|
|
203
|
-
var item = array[i];
|
|
204
|
-
var name = "".concat(prefix, "[").concat(i, "]");
|
|
205
|
-
if (Array.isArray(item)) {
|
|
206
|
-
processArray(item, name);
|
|
207
|
-
} else if (item && isPlainObject(item)) {
|
|
208
|
-
processObject(item, name);
|
|
209
|
-
} else {
|
|
210
|
-
setResult(item, name);
|
|
191
|
+
} else if (isPlainObject(data)) {
|
|
192
|
+
for (var [key, _value] of Object.entries(data)) {
|
|
193
|
+
process(_value, prefix ? "".concat(prefix, ".").concat(key) : key);
|
|
211
194
|
}
|
|
212
195
|
}
|
|
213
196
|
}
|
|
214
197
|
if (data) {
|
|
215
198
|
var _options$prefix;
|
|
216
|
-
|
|
217
|
-
if (Array.isArray(data)) {
|
|
218
|
-
processArray(data, prefix);
|
|
219
|
-
} else {
|
|
220
|
-
processObject(data, prefix);
|
|
221
|
-
}
|
|
199
|
+
process(data, (_options$prefix = options.prefix) !== null && _options$prefix !== void 0 ? _options$prefix : '');
|
|
222
200
|
}
|
|
223
201
|
return result;
|
|
224
202
|
}
|
package/formdata.mjs
CHANGED
|
@@ -89,7 +89,7 @@ function setValue(target, name, valueFn) {
|
|
|
89
89
|
while (pointer != null && ++index < length) {
|
|
90
90
|
var key = paths[index];
|
|
91
91
|
var nextKey = paths[index + 1];
|
|
92
|
-
var newValue = index != lastIndex ? Object.prototype.hasOwnProperty.call(pointer, key) ? pointer[key] : typeof nextKey === 'number' ? [] : {} : valueFn(pointer[key]);
|
|
92
|
+
var newValue = index != lastIndex ? Object.prototype.hasOwnProperty.call(pointer, key) && pointer[key] !== null ? pointer[key] : typeof nextKey === 'number' ? [] : {} : valueFn(pointer[key]);
|
|
93
93
|
pointer[key] = newValue;
|
|
94
94
|
pointer = pointer[key];
|
|
95
95
|
}
|
|
@@ -170,51 +170,29 @@ function normalize(value) {
|
|
|
170
170
|
/**
|
|
171
171
|
* Flatten a tree into a dictionary
|
|
172
172
|
*/
|
|
173
|
-
function flatten(data
|
|
173
|
+
function flatten(data) {
|
|
174
174
|
var _options$resolve;
|
|
175
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
175
176
|
var result = {};
|
|
176
|
-
var resolve = (_options$resolve = options
|
|
177
|
-
function
|
|
177
|
+
var resolve = (_options$resolve = options.resolve) !== null && _options$resolve !== void 0 ? _options$resolve : data => data;
|
|
178
|
+
function process(data, prefix) {
|
|
178
179
|
var value = normalize(resolve(data));
|
|
179
180
|
if (typeof value !== 'undefined') {
|
|
180
|
-
result[
|
|
181
|
+
result[prefix] = value;
|
|
181
182
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
for (var [key, _value] of Object.entries(obj)) {
|
|
186
|
-
var name = prefix ? "".concat(prefix, ".").concat(key) : key;
|
|
187
|
-
if (Array.isArray(_value)) {
|
|
188
|
-
processArray(_value, name);
|
|
189
|
-
} else if (_value && isPlainObject(_value)) {
|
|
190
|
-
processObject(_value, name);
|
|
191
|
-
} else {
|
|
192
|
-
setResult(_value, name);
|
|
183
|
+
if (Array.isArray(data)) {
|
|
184
|
+
for (var i = 0; i < data.length; i++) {
|
|
185
|
+
process(data[i], "".concat(prefix, "[").concat(i, "]"));
|
|
193
186
|
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
setResult(array, prefix);
|
|
198
|
-
for (var i = 0; i < array.length; i++) {
|
|
199
|
-
var item = array[i];
|
|
200
|
-
var name = "".concat(prefix, "[").concat(i, "]");
|
|
201
|
-
if (Array.isArray(item)) {
|
|
202
|
-
processArray(item, name);
|
|
203
|
-
} else if (item && isPlainObject(item)) {
|
|
204
|
-
processObject(item, name);
|
|
205
|
-
} else {
|
|
206
|
-
setResult(item, name);
|
|
187
|
+
} else if (isPlainObject(data)) {
|
|
188
|
+
for (var [key, _value] of Object.entries(data)) {
|
|
189
|
+
process(_value, prefix ? "".concat(prefix, ".").concat(key) : key);
|
|
207
190
|
}
|
|
208
191
|
}
|
|
209
192
|
}
|
|
210
193
|
if (data) {
|
|
211
194
|
var _options$prefix;
|
|
212
|
-
|
|
213
|
-
if (Array.isArray(data)) {
|
|
214
|
-
processArray(data, prefix);
|
|
215
|
-
} else {
|
|
216
|
-
processObject(data, prefix);
|
|
217
|
-
}
|
|
195
|
+
process(data, (_options$prefix = options.prefix) !== null && _options$prefix !== void 0 ? _options$prefix : '');
|
|
218
196
|
}
|
|
219
197
|
return result;
|
|
220
198
|
}
|
package/intent.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type Pretty } from './types.js';
|
|
2
|
+
export interface IntentButtonProps {
|
|
3
|
+
name: typeof INTENT;
|
|
4
|
+
value: string;
|
|
5
|
+
formNoValidate?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type ListIntentPayload<Schema = unknown> = {
|
|
8
|
+
name: string;
|
|
9
|
+
operation: 'insert';
|
|
10
|
+
defaultValue?: Schema;
|
|
11
|
+
index?: number;
|
|
12
|
+
} | {
|
|
13
|
+
name: string;
|
|
14
|
+
operation: 'prepend';
|
|
15
|
+
defaultValue?: Schema;
|
|
16
|
+
} | {
|
|
17
|
+
name: string;
|
|
18
|
+
operation: 'append';
|
|
19
|
+
defaultValue?: Schema;
|
|
20
|
+
} | {
|
|
21
|
+
name: string;
|
|
22
|
+
operation: 'replace';
|
|
23
|
+
defaultValue: Schema;
|
|
24
|
+
index: number;
|
|
25
|
+
} | {
|
|
26
|
+
name: string;
|
|
27
|
+
operation: 'remove';
|
|
28
|
+
index: number;
|
|
29
|
+
} | {
|
|
30
|
+
name: string;
|
|
31
|
+
operation: 'reorder';
|
|
32
|
+
from: number;
|
|
33
|
+
to: number;
|
|
34
|
+
};
|
|
35
|
+
type ExtractListIntentPayload<Operation, Schema = unknown> = Pretty<Omit<Extract<ListIntentPayload<Schema>, {
|
|
36
|
+
operation: Operation;
|
|
37
|
+
}>, 'name' | 'operation'>>;
|
|
38
|
+
type ListIntent<Operation> = {} extends ExtractListIntentPayload<Operation> ? <Schema>(name: string, payload?: ExtractListIntentPayload<Operation, Schema>) => IntentButtonProps : <Schema>(name: string, payload: ExtractListIntentPayload<Operation, Schema>) => IntentButtonProps;
|
|
39
|
+
/**
|
|
40
|
+
* Helpers to configure an intent button for modifying a list
|
|
41
|
+
*
|
|
42
|
+
* @see https://conform.guide/api/react#list
|
|
43
|
+
*/
|
|
44
|
+
export declare const list: {
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated You can use `insert` without specifying an index instead
|
|
47
|
+
*/
|
|
48
|
+
append: ListIntent<'append'>;
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated You can use `insert` with zero index instead
|
|
51
|
+
*/
|
|
52
|
+
prepend: ListIntent<'prepend'>;
|
|
53
|
+
insert: ListIntent<'insert'>;
|
|
54
|
+
replace: ListIntent<'replace'>;
|
|
55
|
+
remove: ListIntent<'remove'>;
|
|
56
|
+
reorder: ListIntent<'reorder'>;
|
|
57
|
+
};
|
|
58
|
+
export declare const INTENT = "__intent__";
|
|
59
|
+
/**
|
|
60
|
+
* Returns the intent from the form data or search params.
|
|
61
|
+
* It throws an error if multiple intent is set.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getIntent(payload: FormData | URLSearchParams): string;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the properties required to configure an intent button for validation
|
|
66
|
+
*
|
|
67
|
+
* @see https://conform.guide/api/react#validate
|
|
68
|
+
*/
|
|
69
|
+
export declare function validate(field: string): IntentButtonProps;
|
|
70
|
+
export declare function requestIntent(form: HTMLFormElement | null | undefined, buttonProps: {
|
|
71
|
+
value: string;
|
|
72
|
+
formNoValidate?: boolean;
|
|
73
|
+
}): void;
|
|
74
|
+
export declare function parseIntent<Schema>(intent: string): {
|
|
75
|
+
type: 'validate';
|
|
76
|
+
payload: string;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'list';
|
|
79
|
+
payload: ListIntentPayload<Schema>;
|
|
80
|
+
} | null;
|
|
81
|
+
export declare function updateList<Schema>(list: Array<Schema>, payload: ListIntentPayload<Schema>): Array<Schema>;
|
|
82
|
+
export {};
|
package/intent.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var dom = require('./dom.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Helpers to configure an intent button for modifying a list
|
|
10
|
+
*
|
|
11
|
+
* @see https://conform.guide/api/react#list
|
|
12
|
+
*/
|
|
13
|
+
var list = new Proxy({}, {
|
|
14
|
+
get(_target, operation) {
|
|
15
|
+
return function (name) {
|
|
16
|
+
var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
17
|
+
return {
|
|
18
|
+
name: INTENT,
|
|
19
|
+
value: "list/".concat(JSON.stringify(_rollupPluginBabelHelpers.objectSpread2({
|
|
20
|
+
name,
|
|
21
|
+
operation
|
|
22
|
+
}, payload))),
|
|
23
|
+
formNoValidate: true
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
var INTENT = '__intent__';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the intent from the form data or search params.
|
|
32
|
+
* It throws an error if multiple intent is set.
|
|
33
|
+
*/
|
|
34
|
+
function getIntent(payload) {
|
|
35
|
+
if (!payload.has(INTENT)) {
|
|
36
|
+
return 'submit';
|
|
37
|
+
}
|
|
38
|
+
var [intent, secondIntent, ...rest] = payload.getAll(INTENT);
|
|
39
|
+
|
|
40
|
+
// The submitter value is included in the formData directly on Safari 15.6.
|
|
41
|
+
// This causes the intent to be duplicated in the payload.
|
|
42
|
+
// We will ignore the second intent if it is the same as the first one.
|
|
43
|
+
if (typeof intent !== 'string' || secondIntent && intent !== secondIntent || rest.length > 0) {
|
|
44
|
+
throw new Error('The intent could only be set on a button');
|
|
45
|
+
}
|
|
46
|
+
return intent;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the properties required to configure an intent button for validation
|
|
51
|
+
*
|
|
52
|
+
* @see https://conform.guide/api/react#validate
|
|
53
|
+
*/
|
|
54
|
+
function validate(field) {
|
|
55
|
+
return {
|
|
56
|
+
name: INTENT,
|
|
57
|
+
value: "validate/".concat(field),
|
|
58
|
+
formNoValidate: true
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function requestIntent(form, buttonProps) {
|
|
62
|
+
if (!form) {
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.warn('No form element is provided');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
var submitter = dom.createSubmitter({
|
|
68
|
+
name: INTENT,
|
|
69
|
+
value: buttonProps.value,
|
|
70
|
+
hidden: true,
|
|
71
|
+
formNoValidate: buttonProps.formNoValidate
|
|
72
|
+
});
|
|
73
|
+
dom.requestSubmit(form, submitter);
|
|
74
|
+
}
|
|
75
|
+
function parseIntent(intent) {
|
|
76
|
+
var seperatorIndex = intent.indexOf('/');
|
|
77
|
+
if (seperatorIndex > -1) {
|
|
78
|
+
var type = intent.slice(0, seperatorIndex);
|
|
79
|
+
var _payload = intent.slice(seperatorIndex + 1);
|
|
80
|
+
if (typeof _payload !== 'undefined') {
|
|
81
|
+
try {
|
|
82
|
+
switch (type) {
|
|
83
|
+
case 'validate':
|
|
84
|
+
return {
|
|
85
|
+
type,
|
|
86
|
+
payload: _payload
|
|
87
|
+
};
|
|
88
|
+
case 'list':
|
|
89
|
+
return {
|
|
90
|
+
type,
|
|
91
|
+
payload: JSON.parse(_payload)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
throw new Error("Failed parsing intent: ".concat(intent), {
|
|
96
|
+
cause: error
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
function updateList(list, payload) {
|
|
104
|
+
var _payload$index;
|
|
105
|
+
switch (payload.operation) {
|
|
106
|
+
case 'prepend':
|
|
107
|
+
list.unshift(payload.defaultValue);
|
|
108
|
+
break;
|
|
109
|
+
case 'append':
|
|
110
|
+
list.push(payload.defaultValue);
|
|
111
|
+
break;
|
|
112
|
+
case 'insert':
|
|
113
|
+
list.splice((_payload$index = payload.index) !== null && _payload$index !== void 0 ? _payload$index : list.length, 0, payload.defaultValue);
|
|
114
|
+
break;
|
|
115
|
+
case 'replace':
|
|
116
|
+
list.splice(payload.index, 1, payload.defaultValue);
|
|
117
|
+
break;
|
|
118
|
+
case 'remove':
|
|
119
|
+
list.splice(payload.index, 1);
|
|
120
|
+
break;
|
|
121
|
+
case 'reorder':
|
|
122
|
+
list.splice(payload.to, 0, ...list.splice(payload.from, 1));
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
throw new Error('Unknown list intent received');
|
|
126
|
+
}
|
|
127
|
+
return list;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
exports.INTENT = INTENT;
|
|
131
|
+
exports.getIntent = getIntent;
|
|
132
|
+
exports.list = list;
|
|
133
|
+
exports.parseIntent = parseIntent;
|
|
134
|
+
exports.requestIntent = requestIntent;
|
|
135
|
+
exports.updateList = updateList;
|
|
136
|
+
exports.validate = validate;
|
package/intent.mjs
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
+
import { createSubmitter, requestSubmit } from './dom.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Helpers to configure an intent button for modifying a list
|
|
6
|
+
*
|
|
7
|
+
* @see https://conform.guide/api/react#list
|
|
8
|
+
*/
|
|
9
|
+
var list = new Proxy({}, {
|
|
10
|
+
get(_target, operation) {
|
|
11
|
+
return function (name) {
|
|
12
|
+
var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
13
|
+
return {
|
|
14
|
+
name: INTENT,
|
|
15
|
+
value: "list/".concat(JSON.stringify(_objectSpread2({
|
|
16
|
+
name,
|
|
17
|
+
operation
|
|
18
|
+
}, payload))),
|
|
19
|
+
formNoValidate: true
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
var INTENT = '__intent__';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the intent from the form data or search params.
|
|
28
|
+
* It throws an error if multiple intent is set.
|
|
29
|
+
*/
|
|
30
|
+
function getIntent(payload) {
|
|
31
|
+
if (!payload.has(INTENT)) {
|
|
32
|
+
return 'submit';
|
|
33
|
+
}
|
|
34
|
+
var [intent, secondIntent, ...rest] = payload.getAll(INTENT);
|
|
35
|
+
|
|
36
|
+
// The submitter value is included in the formData directly on Safari 15.6.
|
|
37
|
+
// This causes the intent to be duplicated in the payload.
|
|
38
|
+
// We will ignore the second intent if it is the same as the first one.
|
|
39
|
+
if (typeof intent !== 'string' || secondIntent && intent !== secondIntent || rest.length > 0) {
|
|
40
|
+
throw new Error('The intent could only be set on a button');
|
|
41
|
+
}
|
|
42
|
+
return intent;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns the properties required to configure an intent button for validation
|
|
47
|
+
*
|
|
48
|
+
* @see https://conform.guide/api/react#validate
|
|
49
|
+
*/
|
|
50
|
+
function validate(field) {
|
|
51
|
+
return {
|
|
52
|
+
name: INTENT,
|
|
53
|
+
value: "validate/".concat(field),
|
|
54
|
+
formNoValidate: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function requestIntent(form, buttonProps) {
|
|
58
|
+
if (!form) {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.warn('No form element is provided');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
var submitter = createSubmitter({
|
|
64
|
+
name: INTENT,
|
|
65
|
+
value: buttonProps.value,
|
|
66
|
+
hidden: true,
|
|
67
|
+
formNoValidate: buttonProps.formNoValidate
|
|
68
|
+
});
|
|
69
|
+
requestSubmit(form, submitter);
|
|
70
|
+
}
|
|
71
|
+
function parseIntent(intent) {
|
|
72
|
+
var seperatorIndex = intent.indexOf('/');
|
|
73
|
+
if (seperatorIndex > -1) {
|
|
74
|
+
var type = intent.slice(0, seperatorIndex);
|
|
75
|
+
var _payload = intent.slice(seperatorIndex + 1);
|
|
76
|
+
if (typeof _payload !== 'undefined') {
|
|
77
|
+
try {
|
|
78
|
+
switch (type) {
|
|
79
|
+
case 'validate':
|
|
80
|
+
return {
|
|
81
|
+
type,
|
|
82
|
+
payload: _payload
|
|
83
|
+
};
|
|
84
|
+
case 'list':
|
|
85
|
+
return {
|
|
86
|
+
type,
|
|
87
|
+
payload: JSON.parse(_payload)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error("Failed parsing intent: ".concat(intent), {
|
|
92
|
+
cause: error
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function updateList(list, payload) {
|
|
100
|
+
var _payload$index;
|
|
101
|
+
switch (payload.operation) {
|
|
102
|
+
case 'prepend':
|
|
103
|
+
list.unshift(payload.defaultValue);
|
|
104
|
+
break;
|
|
105
|
+
case 'append':
|
|
106
|
+
list.push(payload.defaultValue);
|
|
107
|
+
break;
|
|
108
|
+
case 'insert':
|
|
109
|
+
list.splice((_payload$index = payload.index) !== null && _payload$index !== void 0 ? _payload$index : list.length, 0, payload.defaultValue);
|
|
110
|
+
break;
|
|
111
|
+
case 'replace':
|
|
112
|
+
list.splice(payload.index, 1, payload.defaultValue);
|
|
113
|
+
break;
|
|
114
|
+
case 'remove':
|
|
115
|
+
list.splice(payload.index, 1);
|
|
116
|
+
break;
|
|
117
|
+
case 'reorder':
|
|
118
|
+
list.splice(payload.to, 0, ...list.splice(payload.from, 1));
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
throw new Error('Unknown list intent received');
|
|
122
|
+
}
|
|
123
|
+
return list;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { INTENT, getIntent, list, parseIntent, requestIntent, updateList, validate };
|
package/package.json
CHANGED
|
@@ -1,42 +1,59 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
2
|
+
"name": "@conform-to/dom",
|
|
3
|
+
"description": "A set of opinionated helpers built on top of the Constraint Validation API",
|
|
4
|
+
"homepage": "https://conform.guide",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"version": "1.1.4",
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"module": "index.mjs",
|
|
9
|
+
"types": "index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"module": "./index.mjs",
|
|
14
|
+
"import": "./index.mjs",
|
|
15
|
+
"require": "./index.js",
|
|
16
|
+
"default": "./index.mjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/edmundhung/conform",
|
|
22
|
+
"directory": "packages/conform-dom"
|
|
23
|
+
},
|
|
24
|
+
"author": {
|
|
25
|
+
"name": "Edmund Hung",
|
|
26
|
+
"email": "me@edmund.dev",
|
|
27
|
+
"url": "https://edmund.dev"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/edmundhung/conform/issues"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"constraint-validation",
|
|
34
|
+
"form",
|
|
35
|
+
"form-validation",
|
|
36
|
+
"html",
|
|
37
|
+
"progressive-enhancement",
|
|
38
|
+
"validation",
|
|
39
|
+
"dom"
|
|
40
|
+
],
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@babel/core": "^7.17.8",
|
|
44
|
+
"@babel/preset-env": "^7.20.2",
|
|
45
|
+
"@babel/preset-typescript": "^7.20.2",
|
|
46
|
+
"@rollup/plugin-babel": "^5.3.1",
|
|
47
|
+
"@rollup/plugin-node-resolve": "^13.3.0",
|
|
48
|
+
"rollup-plugin-copy": "^3.4.0",
|
|
49
|
+
"rollup": "^2.79.1"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build:js": "rollup -c",
|
|
53
|
+
"build:ts": "tsc",
|
|
54
|
+
"build": "pnpm run \"/^build:.*/\"",
|
|
55
|
+
"dev:js": "pnpm run build:js --watch",
|
|
56
|
+
"dev:ts": "pnpm run build:ts --watch",
|
|
57
|
+
"dev": "pnpm run \"/^dev:.*/\""
|
|
58
|
+
}
|
|
59
|
+
}
|
package/parse.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type Submission<Schema = any> = {
|
|
2
|
+
intent: string;
|
|
3
|
+
payload: Record<string, unknown>;
|
|
4
|
+
error: Record<string, string[]>;
|
|
5
|
+
value?: Schema | null;
|
|
6
|
+
};
|
|
7
|
+
export declare const VALIDATION_UNDEFINED = "__undefined__";
|
|
8
|
+
export declare const VALIDATION_SKIPPED = "__skipped__";
|
|
9
|
+
export declare function parse(payload: FormData | URLSearchParams): Submission;
|
|
10
|
+
export declare function parse<Schema>(payload: FormData | URLSearchParams, options?: {
|
|
11
|
+
resolve?: (payload: Record<string, any>, intent: string) => {
|
|
12
|
+
value?: Schema;
|
|
13
|
+
error?: Record<string, string[]>;
|
|
14
|
+
};
|
|
15
|
+
}): Submission<Schema>;
|
|
16
|
+
export declare function parse<Schema>(payload: FormData | URLSearchParams, options?: {
|
|
17
|
+
resolve?: (payload: Record<string, any>, intent: string) => Promise<{
|
|
18
|
+
value?: Schema;
|
|
19
|
+
error?: Record<string, string[]>;
|
|
20
|
+
}>;
|
|
21
|
+
}): Promise<Submission<Schema>>;
|
|
22
|
+
export declare function parse<Schema>(payload: FormData | URLSearchParams, options?: {
|
|
23
|
+
resolve?: (payload: Record<string, any>, intent: string) => {
|
|
24
|
+
value?: Schema;
|
|
25
|
+
error?: Record<string, string[]>;
|
|
26
|
+
} | Promise<{
|
|
27
|
+
value?: Schema;
|
|
28
|
+
error?: Record<string, string[]>;
|
|
29
|
+
}>;
|
|
30
|
+
}): Submission<Schema> | Promise<Submission<Schema>>;
|
package/parse.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var formdata = require('./formdata.js');
|
|
7
|
+
var intent = require('./intent.js');
|
|
8
|
+
|
|
9
|
+
var VALIDATION_UNDEFINED = '__undefined__';
|
|
10
|
+
var VALIDATION_SKIPPED = '__skipped__';
|
|
11
|
+
function parse(payload, options) {
|
|
12
|
+
var submission = {
|
|
13
|
+
intent: intent.getIntent(payload),
|
|
14
|
+
payload: formdata.resolve(payload, {
|
|
15
|
+
ignoreKeys: [intent.INTENT]
|
|
16
|
+
}),
|
|
17
|
+
error: {}
|
|
18
|
+
};
|
|
19
|
+
var intent$1 = intent.parseIntent(submission.intent);
|
|
20
|
+
if (intent$1 && intent$1.type === 'list') {
|
|
21
|
+
formdata.setValue(submission.payload, intent$1.payload.name, list => {
|
|
22
|
+
if (typeof list !== 'undefined' && !Array.isArray(list)) {
|
|
23
|
+
throw new Error('The list intent can only be applied to a list');
|
|
24
|
+
}
|
|
25
|
+
return intent.updateList(list !== null && list !== void 0 ? list : [], intent$1.payload);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (typeof (options === null || options === void 0 ? void 0 : options.resolve) === 'undefined') {
|
|
29
|
+
return submission;
|
|
30
|
+
}
|
|
31
|
+
var result = options.resolve(submission.payload, submission.intent);
|
|
32
|
+
var mergeResolveResult = resolved => {
|
|
33
|
+
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, submission), resolved);
|
|
34
|
+
};
|
|
35
|
+
if (result instanceof Promise) {
|
|
36
|
+
return result.then(mergeResolveResult);
|
|
37
|
+
}
|
|
38
|
+
return mergeResolveResult(result);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.VALIDATION_SKIPPED = VALIDATION_SKIPPED;
|
|
42
|
+
exports.VALIDATION_UNDEFINED = VALIDATION_UNDEFINED;
|
|
43
|
+
exports.parse = parse;
|
package/parse.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
+
import { resolve, setValue } from './formdata.mjs';
|
|
3
|
+
import { getIntent, parseIntent, updateList, INTENT } from './intent.mjs';
|
|
4
|
+
|
|
5
|
+
var VALIDATION_UNDEFINED = '__undefined__';
|
|
6
|
+
var VALIDATION_SKIPPED = '__skipped__';
|
|
7
|
+
function parse(payload, options) {
|
|
8
|
+
var submission = {
|
|
9
|
+
intent: getIntent(payload),
|
|
10
|
+
payload: resolve(payload, {
|
|
11
|
+
ignoreKeys: [INTENT]
|
|
12
|
+
}),
|
|
13
|
+
error: {}
|
|
14
|
+
};
|
|
15
|
+
var intent = parseIntent(submission.intent);
|
|
16
|
+
if (intent && intent.type === 'list') {
|
|
17
|
+
setValue(submission.payload, intent.payload.name, list => {
|
|
18
|
+
if (typeof list !== 'undefined' && !Array.isArray(list)) {
|
|
19
|
+
throw new Error('The list intent can only be applied to a list');
|
|
20
|
+
}
|
|
21
|
+
return updateList(list !== null && list !== void 0 ? list : [], intent.payload);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (typeof (options === null || options === void 0 ? void 0 : options.resolve) === 'undefined') {
|
|
25
|
+
return submission;
|
|
26
|
+
}
|
|
27
|
+
var result = options.resolve(submission.payload, submission.intent);
|
|
28
|
+
var mergeResolveResult = resolved => {
|
|
29
|
+
return _objectSpread2(_objectSpread2({}, submission), resolved);
|
|
30
|
+
};
|
|
31
|
+
if (result instanceof Promise) {
|
|
32
|
+
return result.then(mergeResolveResult);
|
|
33
|
+
}
|
|
34
|
+
return mergeResolveResult(result);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { VALIDATION_SKIPPED, VALIDATION_UNDEFINED, parse };
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import babel from '@rollup/plugin-babel';
|
|
3
|
+
import nodeResolve from '@rollup/plugin-node-resolve';
|
|
4
|
+
import copy from 'rollup-plugin-copy';
|
|
5
|
+
|
|
6
|
+
/** @returns {import("rollup").RollupOptions[]} */
|
|
7
|
+
function configurePackage() {
|
|
8
|
+
let sourceDir = '.';
|
|
9
|
+
let outputDir = sourceDir;
|
|
10
|
+
|
|
11
|
+
/** @type {import("rollup").RollupOptions} */
|
|
12
|
+
let ESM = {
|
|
13
|
+
external(id) {
|
|
14
|
+
return !id.startsWith('.') && !path.isAbsolute(id);
|
|
15
|
+
},
|
|
16
|
+
input: `${sourceDir}/index.ts`,
|
|
17
|
+
output: {
|
|
18
|
+
dir: outputDir,
|
|
19
|
+
format: 'esm',
|
|
20
|
+
preserveModules: true,
|
|
21
|
+
entryFileNames: '[name].mjs',
|
|
22
|
+
},
|
|
23
|
+
plugins: [
|
|
24
|
+
babel({
|
|
25
|
+
babelrc: false,
|
|
26
|
+
configFile: false,
|
|
27
|
+
presets: [
|
|
28
|
+
[
|
|
29
|
+
'@babel/preset-env',
|
|
30
|
+
{
|
|
31
|
+
targets: {
|
|
32
|
+
node: '16',
|
|
33
|
+
esmodules: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
'@babel/preset-typescript',
|
|
38
|
+
],
|
|
39
|
+
plugins: [],
|
|
40
|
+
babelHelpers: 'bundled',
|
|
41
|
+
exclude: /node_modules/,
|
|
42
|
+
extensions: ['.ts', '.tsx'],
|
|
43
|
+
}),
|
|
44
|
+
nodeResolve({
|
|
45
|
+
extensions: ['.ts', '.tsx'],
|
|
46
|
+
}),
|
|
47
|
+
copy({
|
|
48
|
+
targets: [
|
|
49
|
+
{ src: `../../README`, dest: sourceDir },
|
|
50
|
+
{ src: `../../LICENSE`, dest: sourceDir },
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** @type {import("rollup").RollupOptions} */
|
|
57
|
+
let CJS = {
|
|
58
|
+
external(id) {
|
|
59
|
+
return !id.startsWith('.') && !path.isAbsolute(id);
|
|
60
|
+
},
|
|
61
|
+
input: `${sourceDir}/index.ts`,
|
|
62
|
+
output: {
|
|
63
|
+
dir: outputDir,
|
|
64
|
+
format: 'cjs',
|
|
65
|
+
preserveModules: true,
|
|
66
|
+
exports: 'auto',
|
|
67
|
+
},
|
|
68
|
+
plugins: [
|
|
69
|
+
babel({
|
|
70
|
+
babelrc: false,
|
|
71
|
+
configFile: false,
|
|
72
|
+
presets: [
|
|
73
|
+
[
|
|
74
|
+
'@babel/preset-env',
|
|
75
|
+
{
|
|
76
|
+
targets: {
|
|
77
|
+
node: '16',
|
|
78
|
+
esmodules: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
'@babel/preset-typescript',
|
|
83
|
+
],
|
|
84
|
+
plugins: [],
|
|
85
|
+
babelHelpers: 'bundled',
|
|
86
|
+
exclude: /node_modules/,
|
|
87
|
+
extensions: ['.ts', '.tsx'],
|
|
88
|
+
}),
|
|
89
|
+
nodeResolve({
|
|
90
|
+
extensions: ['.ts', '.tsx'],
|
|
91
|
+
}),
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return [ESM, CJS];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default function rollup() {
|
|
99
|
+
return configurePackage();
|
|
100
|
+
}
|
package/submission.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ export type ResetIntent<Schema = any> = {
|
|
|
84
84
|
index: Schema extends Array<unknown> ? number : never;
|
|
85
85
|
};
|
|
86
86
|
};
|
|
87
|
-
export type UpdateIntent<Schema =
|
|
87
|
+
export type UpdateIntent<Schema = any> = {
|
|
88
88
|
type: 'update';
|
|
89
89
|
payload: {
|
|
90
90
|
name?: FieldName<Schema>;
|
|
@@ -94,18 +94,18 @@ export type UpdateIntent<Schema = unknown> = {
|
|
|
94
94
|
} | {
|
|
95
95
|
name: FieldName<Schema>;
|
|
96
96
|
index: Schema extends Array<unknown> ? number : never;
|
|
97
|
-
value?:
|
|
97
|
+
value?: Schema extends Array<infer Item> ? NonNullable<DefaultValue<Item>> : never;
|
|
98
98
|
validated?: boolean;
|
|
99
99
|
};
|
|
100
100
|
};
|
|
101
|
-
export type RemoveIntent<Schema
|
|
101
|
+
export type RemoveIntent<Schema = any> = {
|
|
102
102
|
type: 'remove';
|
|
103
103
|
payload: {
|
|
104
104
|
name: FieldName<Schema>;
|
|
105
105
|
index: number;
|
|
106
106
|
};
|
|
107
107
|
};
|
|
108
|
-
export type InsertIntent<Schema
|
|
108
|
+
export type InsertIntent<Schema = any> = {
|
|
109
109
|
type: 'insert';
|
|
110
110
|
payload: {
|
|
111
111
|
name: FieldName<Schema>;
|
|
@@ -113,7 +113,7 @@ export type InsertIntent<Schema extends Array<any> = any> = {
|
|
|
113
113
|
index?: number;
|
|
114
114
|
};
|
|
115
115
|
};
|
|
116
|
-
export type ReorderIntent<Schema
|
|
116
|
+
export type ReorderIntent<Schema = any> = {
|
|
117
117
|
type: 'reorder';
|
|
118
118
|
payload: {
|
|
119
119
|
name: FieldName<Schema>;
|
|
@@ -121,7 +121,7 @@ export type ReorderIntent<Schema extends Array<any> = any> = {
|
|
|
121
121
|
to: number;
|
|
122
122
|
};
|
|
123
123
|
};
|
|
124
|
-
export type Intent<Schema =
|
|
124
|
+
export type Intent<Schema = any> = ValidateIntent<Schema> | ResetIntent<Schema> | UpdateIntent<Schema> | ReorderIntent<Schema> | RemoveIntent<Schema> | InsertIntent<Schema>;
|
|
125
125
|
export declare function getIntent(serializedIntent: string | null | undefined): Intent | null;
|
|
126
126
|
export declare function serializeIntent<Schema>(intent: Intent<Schema>): string;
|
|
127
127
|
export declare function updateList(list: unknown, intent: InsertIntent | RemoveIntent | ReorderIntent): void;
|
|
@@ -132,4 +132,4 @@ export declare function setListValue(data: Record<string, unknown>, intent: Inse
|
|
|
132
132
|
export declare const root: unique symbol;
|
|
133
133
|
export declare function setState(state: Record<string, unknown>, name: string, valueFn: (value: unknown) => unknown): void;
|
|
134
134
|
export declare function setListState(state: Record<string, unknown>, intent: InsertIntent | RemoveIntent | ReorderIntent, getDefaultValue?: (defaultValue: any) => any): void;
|
|
135
|
-
export declare function serialize<Schema>(defaultValue:
|
|
135
|
+
export declare function serialize<Schema>(defaultValue: Schema): FormValue<Schema>;
|
package/submission.js
CHANGED
|
@@ -55,12 +55,11 @@ function parse(payload, options) {
|
|
|
55
55
|
case 'update':
|
|
56
56
|
{
|
|
57
57
|
var name = formdata.formatName(intent.payload.name, intent.payload.index);
|
|
58
|
-
var _value =
|
|
59
|
-
if (typeof
|
|
58
|
+
var _value = intent.payload.value;
|
|
59
|
+
if (typeof intent.payload.value !== 'undefined') {
|
|
60
60
|
if (name) {
|
|
61
61
|
formdata.setValue(context.payload, name, () => _value);
|
|
62
62
|
} else {
|
|
63
|
-
// @ts-expect-error FIXME - it must be an object if there is no name
|
|
64
63
|
context.payload = _value;
|
|
65
64
|
}
|
|
66
65
|
}
|
|
@@ -77,15 +76,6 @@ function parse(payload, options) {
|
|
|
77
76
|
break;
|
|
78
77
|
}
|
|
79
78
|
case 'insert':
|
|
80
|
-
{
|
|
81
|
-
setListValue(context.payload, {
|
|
82
|
-
type: intent.type,
|
|
83
|
-
payload: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, intent.payload), {}, {
|
|
84
|
-
defaultValue: serialize(intent.payload.defaultValue)
|
|
85
|
-
})
|
|
86
|
-
});
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
79
|
case 'remove':
|
|
90
80
|
case 'reorder':
|
|
91
81
|
{
|
|
@@ -166,7 +156,24 @@ function getIntent(serializedIntent) {
|
|
|
166
156
|
return control;
|
|
167
157
|
}
|
|
168
158
|
function serializeIntent(intent) {
|
|
169
|
-
|
|
159
|
+
switch (intent.type) {
|
|
160
|
+
case 'insert':
|
|
161
|
+
return JSON.stringify({
|
|
162
|
+
type: intent.type,
|
|
163
|
+
payload: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, intent.payload), {}, {
|
|
164
|
+
defaultValue: serialize(intent.payload.defaultValue)
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
case 'update':
|
|
168
|
+
return JSON.stringify({
|
|
169
|
+
type: intent.type,
|
|
170
|
+
payload: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, intent.payload), {}, {
|
|
171
|
+
value: serialize(intent.payload.value)
|
|
172
|
+
})
|
|
173
|
+
});
|
|
174
|
+
default:
|
|
175
|
+
return JSON.stringify(intent);
|
|
176
|
+
}
|
|
170
177
|
}
|
|
171
178
|
function updateList(list, intent) {
|
|
172
179
|
var _intent$payload$index;
|
|
@@ -225,9 +232,7 @@ function setState(state, name, valueFn) {
|
|
|
225
232
|
_loop2();
|
|
226
233
|
}
|
|
227
234
|
var result = valueFn(formdata.getValue(target, name));
|
|
228
|
-
Object.assign(state,
|
|
229
|
-
// @ts-expect-error FIXME flatten should be more flexible
|
|
230
|
-
formdata.flatten(result, {
|
|
235
|
+
Object.assign(state, formdata.flatten(result, {
|
|
231
236
|
resolve(data) {
|
|
232
237
|
if (formdata.isPlainObject(data) || Array.isArray(data)) {
|
|
233
238
|
var _data$root;
|
|
@@ -263,22 +268,19 @@ function serialize(defaultValue) {
|
|
|
263
268
|
// @ts-expect-error FIXME
|
|
264
269
|
return Object.entries(defaultValue).reduce((result, _ref) => {
|
|
265
270
|
var [key, value] = _ref;
|
|
266
|
-
// @ts-ignore-error FIXME
|
|
267
271
|
result[key] = serialize(value);
|
|
268
272
|
return result;
|
|
269
273
|
}, {});
|
|
270
274
|
} else if (Array.isArray(defaultValue)) {
|
|
271
275
|
// @ts-expect-error FIXME
|
|
272
276
|
return defaultValue.map(serialize);
|
|
273
|
-
} else if (
|
|
274
|
-
// @ts-ignore-error FIXME
|
|
275
|
-
defaultValue instanceof Date) {
|
|
277
|
+
} else if (defaultValue instanceof Date) {
|
|
276
278
|
// @ts-expect-error FIXME
|
|
277
279
|
return defaultValue.toISOString();
|
|
278
280
|
} else if (typeof defaultValue === 'boolean') {
|
|
279
281
|
// @ts-expect-error FIXME
|
|
280
282
|
return defaultValue ? 'on' : undefined;
|
|
281
|
-
} else if (typeof defaultValue === 'number') {
|
|
283
|
+
} else if (typeof defaultValue === 'number' || typeof defaultValue === 'bigint') {
|
|
282
284
|
// @ts-expect-error FIXME
|
|
283
285
|
return defaultValue.toString();
|
|
284
286
|
} else {
|
package/submission.mjs
CHANGED
|
@@ -51,12 +51,11 @@ function parse(payload, options) {
|
|
|
51
51
|
case 'update':
|
|
52
52
|
{
|
|
53
53
|
var name = formatName(intent.payload.name, intent.payload.index);
|
|
54
|
-
var _value =
|
|
55
|
-
if (typeof
|
|
54
|
+
var _value = intent.payload.value;
|
|
55
|
+
if (typeof intent.payload.value !== 'undefined') {
|
|
56
56
|
if (name) {
|
|
57
57
|
setValue(context.payload, name, () => _value);
|
|
58
58
|
} else {
|
|
59
|
-
// @ts-expect-error FIXME - it must be an object if there is no name
|
|
60
59
|
context.payload = _value;
|
|
61
60
|
}
|
|
62
61
|
}
|
|
@@ -73,15 +72,6 @@ function parse(payload, options) {
|
|
|
73
72
|
break;
|
|
74
73
|
}
|
|
75
74
|
case 'insert':
|
|
76
|
-
{
|
|
77
|
-
setListValue(context.payload, {
|
|
78
|
-
type: intent.type,
|
|
79
|
-
payload: _objectSpread2(_objectSpread2({}, intent.payload), {}, {
|
|
80
|
-
defaultValue: serialize(intent.payload.defaultValue)
|
|
81
|
-
})
|
|
82
|
-
});
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
75
|
case 'remove':
|
|
86
76
|
case 'reorder':
|
|
87
77
|
{
|
|
@@ -162,7 +152,24 @@ function getIntent(serializedIntent) {
|
|
|
162
152
|
return control;
|
|
163
153
|
}
|
|
164
154
|
function serializeIntent(intent) {
|
|
165
|
-
|
|
155
|
+
switch (intent.type) {
|
|
156
|
+
case 'insert':
|
|
157
|
+
return JSON.stringify({
|
|
158
|
+
type: intent.type,
|
|
159
|
+
payload: _objectSpread2(_objectSpread2({}, intent.payload), {}, {
|
|
160
|
+
defaultValue: serialize(intent.payload.defaultValue)
|
|
161
|
+
})
|
|
162
|
+
});
|
|
163
|
+
case 'update':
|
|
164
|
+
return JSON.stringify({
|
|
165
|
+
type: intent.type,
|
|
166
|
+
payload: _objectSpread2(_objectSpread2({}, intent.payload), {}, {
|
|
167
|
+
value: serialize(intent.payload.value)
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
default:
|
|
171
|
+
return JSON.stringify(intent);
|
|
172
|
+
}
|
|
166
173
|
}
|
|
167
174
|
function updateList(list, intent) {
|
|
168
175
|
var _intent$payload$index;
|
|
@@ -221,9 +228,7 @@ function setState(state, name, valueFn) {
|
|
|
221
228
|
_loop2();
|
|
222
229
|
}
|
|
223
230
|
var result = valueFn(getValue(target, name));
|
|
224
|
-
Object.assign(state,
|
|
225
|
-
// @ts-expect-error FIXME flatten should be more flexible
|
|
226
|
-
flatten(result, {
|
|
231
|
+
Object.assign(state, flatten(result, {
|
|
227
232
|
resolve(data) {
|
|
228
233
|
if (isPlainObject(data) || Array.isArray(data)) {
|
|
229
234
|
var _data$root;
|
|
@@ -259,22 +264,19 @@ function serialize(defaultValue) {
|
|
|
259
264
|
// @ts-expect-error FIXME
|
|
260
265
|
return Object.entries(defaultValue).reduce((result, _ref) => {
|
|
261
266
|
var [key, value] = _ref;
|
|
262
|
-
// @ts-ignore-error FIXME
|
|
263
267
|
result[key] = serialize(value);
|
|
264
268
|
return result;
|
|
265
269
|
}, {});
|
|
266
270
|
} else if (Array.isArray(defaultValue)) {
|
|
267
271
|
// @ts-expect-error FIXME
|
|
268
272
|
return defaultValue.map(serialize);
|
|
269
|
-
} else if (
|
|
270
|
-
// @ts-ignore-error FIXME
|
|
271
|
-
defaultValue instanceof Date) {
|
|
273
|
+
} else if (defaultValue instanceof Date) {
|
|
272
274
|
// @ts-expect-error FIXME
|
|
273
275
|
return defaultValue.toISOString();
|
|
274
276
|
} else if (typeof defaultValue === 'boolean') {
|
|
275
277
|
// @ts-expect-error FIXME
|
|
276
278
|
return defaultValue ? 'on' : undefined;
|
|
277
|
-
} else if (typeof defaultValue === 'number') {
|
|
279
|
+
} else if (typeof defaultValue === 'number' || typeof defaultValue === 'bigint') {
|
|
278
280
|
// @ts-expect-error FIXME
|
|
279
281
|
return defaultValue.toString();
|
|
280
282
|
} else {
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Pretty<T> = {
|
|
2
|
+
[K in keyof T]: T[K];
|
|
3
|
+
} & {};
|
|
4
|
+
export type FieldConstraint<Schema = any> = {
|
|
5
|
+
required?: boolean;
|
|
6
|
+
minLength?: number;
|
|
7
|
+
maxLength?: number;
|
|
8
|
+
min?: Schema extends number ? number : string | number;
|
|
9
|
+
max?: Schema extends number ? number : string | number;
|
|
10
|
+
step?: Schema extends number ? number : string | number;
|
|
11
|
+
multiple?: boolean;
|
|
12
|
+
pattern?: string;
|
|
13
|
+
};
|
|
14
|
+
export type KeysOf<T> = T extends any ? keyof T : never;
|
|
15
|
+
export type ResolveType<T, K extends KeysOf<T>> = T extends {
|
|
16
|
+
[k in K]?: any;
|
|
17
|
+
} ? T[K] : undefined;
|
|
18
|
+
export type FieldsetConstraint<Schema extends Record<string, any> | undefined> = {
|
|
19
|
+
[Key in KeysOf<Schema>]?: FieldConstraint<ResolveType<Schema, Key>>;
|
|
20
|
+
};
|