@conform-to/react 1.17.1 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/future/dom.d.ts +4 -17
- package/dist/future/dom.js +75 -122
- package/dist/future/dom.mjs +75 -119
- package/dist/future/forms.js +2 -2
- package/dist/future/forms.mjs +2 -2
- package/dist/future/hooks.d.ts +38 -24
- package/dist/future/hooks.js +317 -93
- package/dist/future/hooks.mjs +320 -97
- package/dist/future/index.d.ts +2 -2
- package/dist/future/index.js +1 -0
- package/dist/future/index.mjs +1 -1
- package/dist/future/intent.js +23 -23
- package/dist/future/intent.mjs +25 -25
- package/dist/future/state.d.ts +5 -5
- package/dist/future/state.js +41 -48
- package/dist/future/state.mjs +42 -50
- package/dist/future/types.d.ts +142 -29
- package/dist/future/util.d.ts +2 -2
- package/dist/future/util.js +10 -10
- package/dist/future/util.mjs +10 -10
- package/package.json +4 -3
package/dist/future/state.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from '../_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
-
import {
|
|
3
|
-
import { when, generateUniqueKey, merge,
|
|
2
|
+
import { parsePath, getRelativePath, serialize, appendPath, deepEqual, getPathValue, normalize, formatPath } from '@conform-to/dom/future';
|
|
3
|
+
import { when, generateUniqueKey, merge, getPathArray } from './util.mjs';
|
|
4
4
|
|
|
5
5
|
function initializeState(options) {
|
|
6
6
|
var _options$resetKey, _options$defaultValue;
|
|
@@ -78,7 +78,7 @@ function updateState(state, action) {
|
|
|
78
78
|
function pruneListKeys(listKeys, targetValue) {
|
|
79
79
|
var result = listKeys;
|
|
80
80
|
for (var [name, keys] of Object.entries(listKeys)) {
|
|
81
|
-
var list =
|
|
81
|
+
var list = getPathArray(targetValue, name);
|
|
82
82
|
|
|
83
83
|
// Reset list keys only if the length has changed
|
|
84
84
|
// to minimize potential UI state loss due to key changes
|
|
@@ -94,10 +94,16 @@ function pruneListKeys(listKeys, targetValue) {
|
|
|
94
94
|
}
|
|
95
95
|
return result;
|
|
96
96
|
}
|
|
97
|
-
function
|
|
97
|
+
function getDefaultPayload(context, name) {
|
|
98
98
|
var _ref, _context$state$server;
|
|
99
99
|
var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
|
|
100
|
-
var value =
|
|
100
|
+
var value = getPathValue((_ref = (_context$state$server = context.state.serverValue) !== null && _context$state$server !== void 0 ? _context$state$server : context.state.targetValue) !== null && _ref !== void 0 ? _ref : context.state.defaultValue, name);
|
|
101
|
+
return normalize(value, serialize$1);
|
|
102
|
+
}
|
|
103
|
+
function getDefaultValue(context, name) {
|
|
104
|
+
var _ref2, _context$state$server2;
|
|
105
|
+
var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
|
|
106
|
+
var value = getPathValue((_ref2 = (_context$state$server2 = context.state.serverValue) !== null && _context$state$server2 !== void 0 ? _context$state$server2 : context.state.targetValue) !== null && _ref2 !== void 0 ? _ref2 : context.state.defaultValue, name);
|
|
101
107
|
var serializedValue = serialize$1(value);
|
|
102
108
|
if (typeof serializedValue === 'string') {
|
|
103
109
|
return serializedValue;
|
|
@@ -105,9 +111,9 @@ function getDefaultValue(context, name) {
|
|
|
105
111
|
return '';
|
|
106
112
|
}
|
|
107
113
|
function getDefaultOptions(context, name) {
|
|
108
|
-
var
|
|
114
|
+
var _ref3, _context$state$server3;
|
|
109
115
|
var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
|
|
110
|
-
var value =
|
|
116
|
+
var value = getPathValue((_ref3 = (_context$state$server3 = context.state.serverValue) !== null && _context$state$server3 !== void 0 ? _context$state$server3 : context.state.targetValue) !== null && _ref3 !== void 0 ? _ref3 : context.state.defaultValue, name);
|
|
111
117
|
var serializedValue = serialize$1(value);
|
|
112
118
|
if (Array.isArray(serializedValue) && serializedValue.every(item => typeof item === 'string')) {
|
|
113
119
|
return serializedValue;
|
|
@@ -118,12 +124,12 @@ function getDefaultOptions(context, name) {
|
|
|
118
124
|
return [];
|
|
119
125
|
}
|
|
120
126
|
function isDefaultChecked(context, name) {
|
|
121
|
-
var
|
|
127
|
+
var _ref4, _context$state$server4;
|
|
122
128
|
var serialize$1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : serialize;
|
|
123
|
-
var value =
|
|
129
|
+
var value = getPathValue((_ref4 = (_context$state$server4 = context.state.serverValue) !== null && _context$state$server4 !== void 0 ? _context$state$server4 : context.state.targetValue) !== null && _ref4 !== void 0 ? _ref4 : context.state.defaultValue, name);
|
|
124
130
|
var serializedValue = serialize$1(value);
|
|
125
131
|
if (typeof serializedValue === 'string') {
|
|
126
|
-
return serializedValue ===
|
|
132
|
+
return serializedValue === serialize$1(true);
|
|
127
133
|
}
|
|
128
134
|
return false;
|
|
129
135
|
}
|
|
@@ -139,15 +145,15 @@ function isTouched(state) {
|
|
|
139
145
|
if (state.touchedFields.includes(name)) {
|
|
140
146
|
return true;
|
|
141
147
|
}
|
|
142
|
-
var paths =
|
|
148
|
+
var paths = parsePath(name);
|
|
143
149
|
return state.touchedFields.some(field => field !== name && getRelativePath(field, paths) !== null);
|
|
144
150
|
}
|
|
145
151
|
function getDefaultListKey(prefix, initialValue, name) {
|
|
146
|
-
return
|
|
152
|
+
return getPathArray(initialValue, name).map((_, index) => "".concat(prefix, "-").concat(appendPath(name, index)));
|
|
147
153
|
}
|
|
148
154
|
function getListKey(context, name) {
|
|
149
|
-
var _context$state$listKe, _context$state$listKe2,
|
|
150
|
-
return (_context$state$listKe = (_context$state$listKe2 = context.state.listKeys) === null || _context$state$listKe2 === void 0 ? void 0 : _context$state$listKe2[name]) !== null && _context$state$listKe !== void 0 ? _context$state$listKe : getDefaultListKey(context.state.resetKey, (
|
|
155
|
+
var _context$state$listKe, _context$state$listKe2, _ref5, _context$state$server5;
|
|
156
|
+
return (_context$state$listKe = (_context$state$listKe2 = context.state.listKeys) === null || _context$state$listKe2 === void 0 ? void 0 : _context$state$listKe2[name]) !== null && _context$state$listKe !== void 0 ? _context$state$listKe : getDefaultListKey(context.state.resetKey, (_ref5 = (_context$state$server5 = context.state.serverValue) !== null && _context$state$server5 !== void 0 ? _context$state$server5 : context.state.targetValue) !== null && _ref5 !== void 0 ? _ref5 : context.state.defaultValue, name);
|
|
151
157
|
}
|
|
152
158
|
function getErrors(state, name) {
|
|
153
159
|
var _state$serverError;
|
|
@@ -165,7 +171,7 @@ function getFieldErrors(state, name) {
|
|
|
165
171
|
var result = {};
|
|
166
172
|
var error = (_state$serverError2 = state.serverError) !== null && _state$serverError2 !== void 0 ? _state$serverError2 : state.clientError;
|
|
167
173
|
if (error) {
|
|
168
|
-
var basePath =
|
|
174
|
+
var basePath = parsePath(name);
|
|
169
175
|
for (var field of Object.keys(error.fieldErrors)) {
|
|
170
176
|
var relativePath = getRelativePath(field, basePath);
|
|
171
177
|
|
|
@@ -175,12 +181,23 @@ function getFieldErrors(state, name) {
|
|
|
175
181
|
}
|
|
176
182
|
var _error = getErrors(state, field);
|
|
177
183
|
if (typeof _error !== 'undefined') {
|
|
178
|
-
result[
|
|
184
|
+
result[formatPath(relativePath)] = _error;
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
return result;
|
|
183
189
|
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Checks if fieldErrors contains any errors at the given name or any child path.
|
|
193
|
+
*/
|
|
194
|
+
function hasFieldError(error, name) {
|
|
195
|
+
var basePath = parsePath(name);
|
|
196
|
+
return Object.keys(error.fieldErrors).some(field => {
|
|
197
|
+
var _error$fieldErrors$fi;
|
|
198
|
+
return getRelativePath(field, basePath) !== null && ((_error$fieldErrors$fi = error.fieldErrors[field]) === null || _error$fieldErrors$fi === void 0 ? void 0 : _error$fieldErrors$fi.length);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
184
201
|
function isValid(state, name) {
|
|
185
202
|
var _state$serverError3;
|
|
186
203
|
var error = (_state$serverError3 = state.serverError) !== null && _state$serverError3 !== void 0 ? _state$serverError3 : state.clientError;
|
|
@@ -189,7 +206,7 @@ function isValid(state, name) {
|
|
|
189
206
|
if (!error) {
|
|
190
207
|
return true;
|
|
191
208
|
}
|
|
192
|
-
var basePath =
|
|
209
|
+
var basePath = parsePath(name);
|
|
193
210
|
for (var field of Object.keys(error.fieldErrors)) {
|
|
194
211
|
// When checking a specific field, only check that field and its children
|
|
195
212
|
if (name && !getRelativePath(field, basePath)) {
|
|
@@ -209,34 +226,6 @@ function isValid(state, name) {
|
|
|
209
226
|
}
|
|
210
227
|
return true;
|
|
211
228
|
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Gets validation constraint for a field, with fallback to parent array patterns.
|
|
215
|
-
* e.g. "array[0].key" falls back to "array[].key" if specific constraint not found.
|
|
216
|
-
*/
|
|
217
|
-
function getConstraint(context, name) {
|
|
218
|
-
var _context$constraint;
|
|
219
|
-
var constraint = (_context$constraint = context.constraint) === null || _context$constraint === void 0 ? void 0 : _context$constraint[name];
|
|
220
|
-
if (!constraint) {
|
|
221
|
-
var path = getPathSegments(name);
|
|
222
|
-
for (var i = path.length - 1; i >= 0; i--) {
|
|
223
|
-
var segment = path[i];
|
|
224
|
-
// Try searching a less specific path for the constraint
|
|
225
|
-
// e.g. `array[0].anotherArray[1].key` -> `array[0].anotherArray[].key` -> `array[].anotherArray[].key`
|
|
226
|
-
if (typeof segment === 'number') {
|
|
227
|
-
// This overrides the current number segment with an empty string
|
|
228
|
-
// which will be treated as an empty bracket
|
|
229
|
-
path[i] = '';
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
var alternative = formatPathSegments(path);
|
|
234
|
-
if (name !== alternative) {
|
|
235
|
-
constraint = getConstraint(context, alternative);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return constraint;
|
|
239
|
-
}
|
|
240
229
|
function getFormMetadata(context, options) {
|
|
241
230
|
var _options$extendFormMe, _options$extendFormMe2;
|
|
242
231
|
var metadata = {
|
|
@@ -297,7 +286,7 @@ function getFormMetadata(context, options) {
|
|
|
297
286
|
return extended;
|
|
298
287
|
}
|
|
299
288
|
function getField(context, options) {
|
|
300
|
-
var _extendFieldMetadata;
|
|
289
|
+
var _context$constraint, _extendFieldMetadata;
|
|
301
290
|
var {
|
|
302
291
|
key,
|
|
303
292
|
name,
|
|
@@ -309,7 +298,7 @@ function getField(context, options) {
|
|
|
309
298
|
})
|
|
310
299
|
} = options;
|
|
311
300
|
var id = "".concat(context.formId, "-field-").concat(name.replace(/[^a-zA-Z0-9._-]/g, '_'));
|
|
312
|
-
var constraint =
|
|
301
|
+
var constraint = (_context$constraint = context.constraint) === null || _context$constraint === void 0 ? void 0 : _context$constraint[name];
|
|
313
302
|
var metadata = {
|
|
314
303
|
key,
|
|
315
304
|
name,
|
|
@@ -335,6 +324,9 @@ function getField(context, options) {
|
|
|
335
324
|
get defaultChecked() {
|
|
336
325
|
return isDefaultChecked(context, name, serialize$1);
|
|
337
326
|
},
|
|
327
|
+
get defaultPayload() {
|
|
328
|
+
return getDefaultPayload(context, name, serialize$1);
|
|
329
|
+
},
|
|
338
330
|
get touched() {
|
|
339
331
|
return isTouched(context.state, name);
|
|
340
332
|
},
|
|
@@ -396,7 +388,7 @@ function getFieldset(context, options) {
|
|
|
396
388
|
extendFieldMetadata: options === null || options === void 0 ? void 0 : options.extendFieldMetadata
|
|
397
389
|
});
|
|
398
390
|
return getField(context, {
|
|
399
|
-
name:
|
|
391
|
+
name: appendPath(options === null || options === void 0 ? void 0 : options.name, name),
|
|
400
392
|
serialize: options.serialize,
|
|
401
393
|
extendFieldMetadata: options.extendFieldMetadata,
|
|
402
394
|
form: options.form
|
|
@@ -414,7 +406,7 @@ function getFieldList(context, options) {
|
|
|
414
406
|
var keys = getListKey(context, options.name);
|
|
415
407
|
return keys.map((key, index) => {
|
|
416
408
|
return getField(context, {
|
|
417
|
-
name:
|
|
409
|
+
name: appendPath(options.name, index),
|
|
418
410
|
serialize: options.serialize,
|
|
419
411
|
extendFieldMetadata: options.extendFieldMetadata,
|
|
420
412
|
key
|
|
@@ -422,4 +414,4 @@ function getFieldList(context, options) {
|
|
|
422
414
|
});
|
|
423
415
|
}
|
|
424
416
|
|
|
425
|
-
export {
|
|
417
|
+
export { getDefaultListKey, getDefaultOptions, getDefaultPayload, getDefaultValue, getErrors, getField, getFieldErrors, getFieldList, getFieldset, getFormMetadata, getListKey, hasFieldError, initializeState, isDefaultChecked, isTouched, isValid, pruneListKeys, updateState };
|
package/dist/future/types.d.ts
CHANGED
|
@@ -5,39 +5,48 @@ export type Prettify<T> = {
|
|
|
5
5
|
} & {};
|
|
6
6
|
/** Reference to a form element. Can be either a React ref object or a form ID string. */
|
|
7
7
|
export type FormRef = React.RefObject<HTMLFormElement | HTMLFieldSetElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement | null> | string;
|
|
8
|
-
export type
|
|
9
|
-
|
|
10
|
-
options?: string[] | undefined;
|
|
11
|
-
checked?: boolean | undefined;
|
|
12
|
-
files?: File[] | undefined;
|
|
13
|
-
};
|
|
14
|
-
export type Control = {
|
|
8
|
+
export type DefaultControlValue = string | string[] | File | File[] | FileList;
|
|
9
|
+
export type Control<Value = DefaultControlValue, DefaultValue = Value, Payload = unknown> = {
|
|
15
10
|
/**
|
|
16
|
-
* Current value
|
|
17
|
-
* is a multi-select, file input, or checkbox group.
|
|
11
|
+
* Current string value derived from the control payload.
|
|
18
12
|
*/
|
|
19
13
|
value: string | undefined;
|
|
20
14
|
/**
|
|
21
|
-
*
|
|
22
|
-
* is a multi-select or checkbox group.
|
|
15
|
+
* Checked state derived from the control payload.
|
|
23
16
|
*/
|
|
24
17
|
checked: boolean | undefined;
|
|
25
18
|
/**
|
|
26
|
-
*
|
|
27
|
-
* is a single checkbox or radio input.
|
|
19
|
+
* Current string array derived from the control payload.
|
|
28
20
|
*/
|
|
29
21
|
options: string[] | undefined;
|
|
30
22
|
/**
|
|
31
|
-
*
|
|
32
|
-
* is a file input.
|
|
23
|
+
* Current file array derived from the control payload.
|
|
33
24
|
*/
|
|
34
25
|
files: File[] | undefined;
|
|
35
26
|
/**
|
|
36
|
-
*
|
|
27
|
+
* The rendered payload used as the source for base control(s).
|
|
28
|
+
*
|
|
29
|
+
* For simple native controls, this mirrors `defaultValue` / `defaultChecked`.
|
|
30
|
+
* For structural controls (i.e. `<fieldset>`), this is the latest payload
|
|
31
|
+
* snapshot that drives which hidden inputs are rendered.
|
|
32
|
+
*/
|
|
33
|
+
defaultValue: DefaultValue | null | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Current payload snapshot derived from the registered base control(s).
|
|
36
|
+
*
|
|
37
|
+
* For structural controls (i.e. `<fieldset>`), this is reconstructed from
|
|
38
|
+
* descendant fields under the registered fieldset name.
|
|
37
39
|
*/
|
|
38
|
-
|
|
40
|
+
payload: Payload | null | undefined;
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
42
|
+
* Registers the base control element.
|
|
43
|
+
*
|
|
44
|
+
* Accepts `<input>`, `<select>`, `<textarea>`, `<fieldset>`,
|
|
45
|
+
* or a collection of checkbox / radio inputs with the same name.
|
|
46
|
+
*/
|
|
47
|
+
register: (element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLFieldSetElement | HTMLCollectionOf<HTMLInputElement> | NodeListOf<HTMLInputElement> | null | undefined) => void;
|
|
48
|
+
/**
|
|
49
|
+
* A ref object containing the form element associated with the registered base control.
|
|
41
50
|
* Use this with hooks like useFormData() and useIntent().
|
|
42
51
|
*/
|
|
43
52
|
formRef: React.RefObject<HTMLFormElement | null>;
|
|
@@ -46,21 +55,74 @@ export type Control = {
|
|
|
46
55
|
* both [change](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event) and
|
|
47
56
|
* [input](https://developer.mozilla.org/en-US/docs/Web/API/Element/input_event) events.
|
|
48
57
|
*/
|
|
49
|
-
change: (value:
|
|
50
|
-
/**
|
|
51
|
-
* Emits [blur](https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event) and
|
|
52
|
-
* [focusout](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event) events.
|
|
53
|
-
* Does not actually move focus.
|
|
54
|
-
*/
|
|
55
|
-
focus: () => void;
|
|
58
|
+
change: (value: Value | null) => void;
|
|
56
59
|
/**
|
|
57
60
|
* Emits [focus](https://developer.mozilla.org/en-US/docs/Web/API/Element/focus_event) and
|
|
58
61
|
* [focusin](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event) events.
|
|
59
|
-
*
|
|
62
|
+
*
|
|
63
|
+
* This does not move the actual keyboard focus to the input.
|
|
64
|
+
* Use [HTMLElement.focus()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)
|
|
60
65
|
* if you want to move focus to the input.
|
|
61
66
|
*/
|
|
67
|
+
focus: () => void;
|
|
68
|
+
/**
|
|
69
|
+
* Emits [blur](https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event) and
|
|
70
|
+
* [focusout](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event) events.
|
|
71
|
+
*
|
|
72
|
+
* This does not move the actual keyboard focus away from the input.
|
|
73
|
+
*/
|
|
62
74
|
blur: () => void;
|
|
63
75
|
};
|
|
76
|
+
export type StandardControlOptions<Value extends DefaultControlValue = DefaultControlValue> = {
|
|
77
|
+
/**
|
|
78
|
+
* The initial value of the base control.
|
|
79
|
+
*/
|
|
80
|
+
defaultValue?: Value | null | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* A callback function that is triggered when the base control is focused.
|
|
83
|
+
* Use this to delegate focus to a custom input.
|
|
84
|
+
*/
|
|
85
|
+
onFocus?: () => void;
|
|
86
|
+
};
|
|
87
|
+
export type CheckedControlOptions = {
|
|
88
|
+
/**
|
|
89
|
+
* Whether the base control should be checked by default.
|
|
90
|
+
*/
|
|
91
|
+
defaultChecked?: boolean | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* The value of a checkbox or radio control when checked.
|
|
94
|
+
*/
|
|
95
|
+
value?: string;
|
|
96
|
+
/**
|
|
97
|
+
* A callback function that is triggered when the base control is focused.
|
|
98
|
+
* Use this to delegate focus to a custom input.
|
|
99
|
+
*/
|
|
100
|
+
onFocus?: () => void;
|
|
101
|
+
};
|
|
102
|
+
export type CustomControlOptions<Value = unknown, DefaultValue = Value> = {
|
|
103
|
+
/**
|
|
104
|
+
* Initial value used to seed the control.
|
|
105
|
+
* For structural controls, this is the payload used to render hidden inputs.
|
|
106
|
+
*/
|
|
107
|
+
defaultValue?: DefaultValue | null | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Payload parser applied to the current payload snapshot.
|
|
110
|
+
*
|
|
111
|
+
* Use this to coerce unknown DOM-derived data into a typed shape.
|
|
112
|
+
* Any thrown error is surfaced to the caller.
|
|
113
|
+
*/
|
|
114
|
+
parse: (payload: unknown) => Value | null | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Optional serializer to convert the parsed payload back to a form value for populating the base control(s).
|
|
117
|
+
*/
|
|
118
|
+
serialize?: (value: Value) => FormValue;
|
|
119
|
+
/**
|
|
120
|
+
* A callback function that is triggered when the base control is focused.
|
|
121
|
+
* Use this to delegate focus to a custom input.
|
|
122
|
+
*/
|
|
123
|
+
onFocus?: () => void;
|
|
124
|
+
};
|
|
125
|
+
export type ControlOptions = StandardControlOptions | CheckedControlOptions | CustomControlOptions;
|
|
64
126
|
export type Selector<FormValue, Result> = (formData: FormValue, lastResult: Result | undefined) => Result;
|
|
65
127
|
export type UseFormDataOptions<Value = undefined> = {
|
|
66
128
|
/**
|
|
@@ -278,7 +340,9 @@ export type GlobalFormOptions = {
|
|
|
278
340
|
export type NonPartial<T> = {
|
|
279
341
|
[K in keyof Required<T>]: T[K];
|
|
280
342
|
};
|
|
281
|
-
export type RequireKey<T, K extends keyof T> = Prettify<T &
|
|
343
|
+
export type RequireKey<T, K extends keyof T> = Prettify<Omit<T, K> & {
|
|
344
|
+
[P in K]-?: Exclude<T[P], undefined>;
|
|
345
|
+
}>;
|
|
282
346
|
export type BaseSchemaType = StandardSchemaV1<any, any>;
|
|
283
347
|
/**
|
|
284
348
|
* Infer schema input type.
|
|
@@ -570,6 +634,13 @@ export type FieldMetadata<FieldShape, ErrorShape extends BaseErrorShape = Defaul
|
|
|
570
634
|
* For radio buttons, compare the field's `defaultValue` with the radio button's value attribute instead.
|
|
571
635
|
*/
|
|
572
636
|
defaultChecked: boolean;
|
|
637
|
+
/**
|
|
638
|
+
* The normalized default payload at this field path.
|
|
639
|
+
*
|
|
640
|
+
* This is useful for non-native field shapes that need to render a set of
|
|
641
|
+
* hidden inputs before user interaction.
|
|
642
|
+
*/
|
|
643
|
+
defaultPayload: unknown;
|
|
573
644
|
/** Whether this field has been touched (through intent.validate() or the shouldValidate option). */
|
|
574
645
|
touched: boolean;
|
|
575
646
|
/** Whether this field currently has no validation errors. */
|
|
@@ -697,12 +768,12 @@ export type ValidateHandler<ErrorShape, Value, SchemaValue = undefined> = (ctx:
|
|
|
697
768
|
] | undefined;
|
|
698
769
|
export interface FormInputEvent extends React.FormEvent<HTMLFormElement> {
|
|
699
770
|
currentTarget: EventTarget & HTMLFormElement;
|
|
700
|
-
target: EventTarget & (HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement);
|
|
771
|
+
target: EventTarget & (HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLFieldSetElement);
|
|
701
772
|
}
|
|
702
773
|
export interface FormFocusEvent extends React.FormEvent<HTMLFormElement> {
|
|
703
774
|
currentTarget: EventTarget & HTMLFormElement;
|
|
704
775
|
relatedTarget: EventTarget | null;
|
|
705
|
-
target: EventTarget & (HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement);
|
|
776
|
+
target: EventTarget & (HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLFieldSetElement);
|
|
706
777
|
}
|
|
707
778
|
export type ErrorContext<ErrorShape> = {
|
|
708
779
|
formElement: HTMLFormElement;
|
|
@@ -782,5 +853,47 @@ export type MakeConditional<T, ConditionalKeys extends Record<string, unknown>>
|
|
|
782
853
|
[K in keyof ConditionalKeys]: K extends keyof T ? ConditionalFieldMetadata<T[K], ConditionalKeys[K]> : never;
|
|
783
854
|
};
|
|
784
855
|
export type MaybePromise<T> = T | Promise<T>;
|
|
856
|
+
type BaseFieldsetProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'fieldset'>, 'children' | 'defaultValue'>, 'name'> & {
|
|
857
|
+
/**
|
|
858
|
+
* Renders a hidden `<fieldset>` base control with nested hidden `<input>` elements
|
|
859
|
+
* derived from `defaultValue`.
|
|
860
|
+
*/
|
|
861
|
+
type: 'fieldset';
|
|
862
|
+
/**
|
|
863
|
+
* Structured default value used to render nested hidden inputs.
|
|
864
|
+
*/
|
|
865
|
+
defaultValue: unknown;
|
|
866
|
+
};
|
|
867
|
+
type BaseSelectProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'select'>, 'children' | 'value'>, 'name' | 'defaultValue'> & {
|
|
868
|
+
/**
|
|
869
|
+
* Renders a hidden `<select>` base control.
|
|
870
|
+
*/
|
|
871
|
+
type: 'select';
|
|
872
|
+
};
|
|
873
|
+
type BaseTextareaProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'textarea'>, 'children' | 'value'>, 'name' | 'defaultValue'> & {
|
|
874
|
+
/**
|
|
875
|
+
* Renders a hidden `<textarea>` base control.
|
|
876
|
+
*/
|
|
877
|
+
type: 'textarea';
|
|
878
|
+
};
|
|
879
|
+
type BaseCheckedInputProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'input'>, 'children' | 'type' | 'checked'>, 'name' | 'defaultChecked'> & {
|
|
880
|
+
/**
|
|
881
|
+
* Renders a hidden checkbox or radio base control.
|
|
882
|
+
*/
|
|
883
|
+
type: 'checkbox' | 'radio';
|
|
884
|
+
};
|
|
885
|
+
type BaseFileInputProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'input'>, 'children' | 'type' | 'value' | 'checked'>, 'name'> & {
|
|
886
|
+
/**
|
|
887
|
+
* Renders a hidden `<input type="file">` base control.
|
|
888
|
+
*/
|
|
889
|
+
type: 'file';
|
|
890
|
+
};
|
|
891
|
+
type BaseInputProps = RequireKey<Omit<React.ComponentPropsWithoutRef<'input'>, 'children' | 'type' | 'value' | 'checked'>, 'name' | 'defaultValue'> & {
|
|
892
|
+
/**
|
|
893
|
+
* Renders a hidden `<input type="...">` base control.
|
|
894
|
+
*/
|
|
895
|
+
type?: 'color' | 'date' | 'datetime-local' | 'email' | 'hidden' | 'month' | 'number' | 'password' | 'range' | 'search' | 'tel' | 'text' | 'time' | 'url' | 'week';
|
|
896
|
+
};
|
|
897
|
+
export type BaseControlProps = BaseFieldsetProps | BaseSelectProps | BaseTextareaProps | BaseCheckedInputProps | BaseFileInputProps | BaseInputProps;
|
|
785
898
|
export {};
|
|
786
899
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/future/util.d.ts
CHANGED
|
@@ -6,12 +6,12 @@ export declare function isString(value: unknown): value is string;
|
|
|
6
6
|
export declare function isNumber(value: unknown): value is number;
|
|
7
7
|
export declare function isNullable<T>(value: unknown, typeGuard: (value: unknown) => value is T): value is T | null;
|
|
8
8
|
export declare function isOptional<T>(value: unknown, typeGuard: (value: unknown) => value is T): value is T | undefined;
|
|
9
|
-
export declare function
|
|
9
|
+
export declare function getPathArray<Type>(formValue: Record<string, Type> | null, name: string): Array<Type>;
|
|
10
10
|
/**
|
|
11
11
|
* Immutably updates a value at the specified path.
|
|
12
12
|
* Empty path replaces the entire object.
|
|
13
13
|
*/
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function updatePathValue<Data>(data: Record<string, Data>, name: string, value: Data | Record<string, Data>): Record<string, Data>;
|
|
15
15
|
/**
|
|
16
16
|
* Creates a function that updates array indices in field paths.
|
|
17
17
|
* Returns null to remove fields, or updated path with new index.
|
package/dist/future/util.js
CHANGED
|
@@ -19,9 +19,9 @@ function isNullable(value, typeGuard) {
|
|
|
19
19
|
function isOptional(value, typeGuard) {
|
|
20
20
|
return isUndefined(value) || typeGuard(value);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
23
|
-
var
|
|
24
|
-
var value = (
|
|
22
|
+
function getPathArray(formValue, name) {
|
|
23
|
+
var _getPathValue;
|
|
24
|
+
var value = (_getPathValue = future.getPathValue(formValue, name)) !== null && _getPathValue !== void 0 ? _getPathValue : [];
|
|
25
25
|
if (!Array.isArray(value)) {
|
|
26
26
|
throw new Error("The value of \"".concat(name, "\" is not an array"));
|
|
27
27
|
}
|
|
@@ -32,14 +32,14 @@ function getArrayAtPath(formValue, name) {
|
|
|
32
32
|
* Immutably updates a value at the specified path.
|
|
33
33
|
* Empty path replaces the entire object.
|
|
34
34
|
*/
|
|
35
|
-
function
|
|
35
|
+
function updatePathValue(data, name, value) {
|
|
36
36
|
if (name === '') {
|
|
37
37
|
if (!future.isPlainObject(value)) {
|
|
38
38
|
throw new Error('The value must be an object');
|
|
39
39
|
}
|
|
40
40
|
return value;
|
|
41
41
|
}
|
|
42
|
-
return future.
|
|
42
|
+
return future.setPathValue(data, future.parsePath(name), value, {
|
|
43
43
|
clone: true
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -49,9 +49,9 @@ function updateValueAtPath(data, name, value) {
|
|
|
49
49
|
* Returns null to remove fields, or updated path with new index.
|
|
50
50
|
*/
|
|
51
51
|
function createPathIndexUpdater(listName, update) {
|
|
52
|
-
var listPaths = future.
|
|
52
|
+
var listPaths = future.parsePath(listName);
|
|
53
53
|
return name => {
|
|
54
|
-
var paths = future.
|
|
54
|
+
var paths = future.parsePath(name);
|
|
55
55
|
if (paths.length > listPaths.length && listPaths.every((path, index) => paths[index] === path)) {
|
|
56
56
|
var currentIndex = paths[listPaths.length];
|
|
57
57
|
if (typeof currentIndex === 'number') {
|
|
@@ -63,7 +63,7 @@ function createPathIndexUpdater(listName, update) {
|
|
|
63
63
|
if (newIndex !== currentIndex) {
|
|
64
64
|
// Replace the index
|
|
65
65
|
paths.splice(listPaths.length, 1, newIndex);
|
|
66
|
-
return future.
|
|
66
|
+
return future.formatPath(paths);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -248,7 +248,7 @@ exports.appendUniqueItem = appendUniqueItem;
|
|
|
248
248
|
exports.compactMap = compactMap;
|
|
249
249
|
exports.createPathIndexUpdater = createPathIndexUpdater;
|
|
250
250
|
exports.generateUniqueKey = generateUniqueKey;
|
|
251
|
-
exports.
|
|
251
|
+
exports.getPathArray = getPathArray;
|
|
252
252
|
exports.isNullable = isNullable;
|
|
253
253
|
exports.isNumber = isNumber;
|
|
254
254
|
exports.isOptional = isOptional;
|
|
@@ -262,6 +262,6 @@ exports.resolveStandardSchemaResult = resolveStandardSchemaResult;
|
|
|
262
262
|
exports.resolveValidateResult = resolveValidateResult;
|
|
263
263
|
exports.shape = shape;
|
|
264
264
|
exports.transformKeys = transformKeys;
|
|
265
|
-
exports.
|
|
265
|
+
exports.updatePathValue = updatePathValue;
|
|
266
266
|
exports.validateStandardSchemaV1 = validateStandardSchemaV1;
|
|
267
267
|
exports.when = when;
|
package/dist/future/util.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatIssues,
|
|
1
|
+
import { formatIssues, getPathValue, isPlainObject, setPathValue, parsePath, formatPath } from '@conform-to/dom/future';
|
|
2
2
|
|
|
3
3
|
function isUndefined(value) {
|
|
4
4
|
return value === undefined;
|
|
@@ -15,9 +15,9 @@ function isNullable(value, typeGuard) {
|
|
|
15
15
|
function isOptional(value, typeGuard) {
|
|
16
16
|
return isUndefined(value) || typeGuard(value);
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
var
|
|
20
|
-
var value = (
|
|
18
|
+
function getPathArray(formValue, name) {
|
|
19
|
+
var _getPathValue;
|
|
20
|
+
var value = (_getPathValue = getPathValue(formValue, name)) !== null && _getPathValue !== void 0 ? _getPathValue : [];
|
|
21
21
|
if (!Array.isArray(value)) {
|
|
22
22
|
throw new Error("The value of \"".concat(name, "\" is not an array"));
|
|
23
23
|
}
|
|
@@ -28,14 +28,14 @@ function getArrayAtPath(formValue, name) {
|
|
|
28
28
|
* Immutably updates a value at the specified path.
|
|
29
29
|
* Empty path replaces the entire object.
|
|
30
30
|
*/
|
|
31
|
-
function
|
|
31
|
+
function updatePathValue(data, name, value) {
|
|
32
32
|
if (name === '') {
|
|
33
33
|
if (!isPlainObject(value)) {
|
|
34
34
|
throw new Error('The value must be an object');
|
|
35
35
|
}
|
|
36
36
|
return value;
|
|
37
37
|
}
|
|
38
|
-
return
|
|
38
|
+
return setPathValue(data, parsePath(name), value, {
|
|
39
39
|
clone: true
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -45,9 +45,9 @@ function updateValueAtPath(data, name, value) {
|
|
|
45
45
|
* Returns null to remove fields, or updated path with new index.
|
|
46
46
|
*/
|
|
47
47
|
function createPathIndexUpdater(listName, update) {
|
|
48
|
-
var listPaths =
|
|
48
|
+
var listPaths = parsePath(listName);
|
|
49
49
|
return name => {
|
|
50
|
-
var paths =
|
|
50
|
+
var paths = parsePath(name);
|
|
51
51
|
if (paths.length > listPaths.length && listPaths.every((path, index) => paths[index] === path)) {
|
|
52
52
|
var currentIndex = paths[listPaths.length];
|
|
53
53
|
if (typeof currentIndex === 'number') {
|
|
@@ -59,7 +59,7 @@ function createPathIndexUpdater(listName, update) {
|
|
|
59
59
|
if (newIndex !== currentIndex) {
|
|
60
60
|
// Replace the index
|
|
61
61
|
paths.splice(listPaths.length, 1, newIndex);
|
|
62
|
-
return
|
|
62
|
+
return formatPath(paths);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -240,4 +240,4 @@ function validateStandardSchemaV1(schema, payload) {
|
|
|
240
240
|
return resolveStandardSchemaResult(result);
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
export { appendUniqueItem, compactMap, createPathIndexUpdater, generateUniqueKey,
|
|
243
|
+
export { appendUniqueItem, compactMap, createPathIndexUpdater, generateUniqueKey, getPathArray, isNullable, isNumber, isOptional, isStandardSchemaV1, isString, isUndefined, merge, normalizeFormError, normalizeValidateResult, resolveStandardSchemaResult, resolveValidateResult, shape, transformKeys, updatePathValue, validateStandardSchemaV1, when };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Conform view adapter for react",
|
|
4
4
|
"homepage": "https://conform.guide",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.18.0",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"module": "./dist/index.mjs",
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"url": "https://github.com/edmundhung/conform/issues"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@conform-to/dom": "1.
|
|
44
|
+
"@conform-to/dom": "1.18.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@babel/core": "^7.17.8",
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
"vitest-browser-react": "^1.0.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"react": ">=18"
|
|
63
|
+
"react": ">=18",
|
|
64
|
+
"react-dom": ">=18"
|
|
64
65
|
},
|
|
65
66
|
"keywords": [
|
|
66
67
|
"constraint-validation",
|