@conform-to/react 0.1.1 → 0.2.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 +460 -6
- package/helpers.d.ts +4 -4
- package/helpers.js +29 -30
- package/hooks.d.ts +13 -13
- package/hooks.js +129 -87
- package/index.d.ts +1 -1
- package/module/helpers.js +29 -30
- package/module/hooks.js +130 -88
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,21 +1,475 @@
|
|
|
1
1
|
# @conform-to/react
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> [React](https://github.com/facebook/react) adapter for [conform](https://github.com/edmundhung/conform)
|
|
4
4
|
|
|
5
5
|
## API Reference
|
|
6
6
|
|
|
7
|
-
- [conform](#conform)
|
|
8
|
-
- [useControlledInput](#useControlledInput)
|
|
9
7
|
- [useForm](#useForm)
|
|
10
8
|
- [useFieldset](#useFieldset)
|
|
11
9
|
- [useFieldList](#useFieldList)
|
|
10
|
+
- [useControlledInput](#useControlledInput)
|
|
11
|
+
- [conform](#conform)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### useControlledInput
|
|
13
|
+
---
|
|
16
14
|
|
|
17
15
|
### useForm
|
|
18
16
|
|
|
17
|
+
By default, the browser calls [reportValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reportValidity) on the form element when you submit the form. This checks the validity of all the fields in it and reports if there are errors through the bubbles.
|
|
18
|
+
|
|
19
|
+
This hook enhances this behaviour by allowing the developers to decide the best timing to start reporting errors using the `initialReport` option. This could start as earliest as the user typing or as late as the user submit the form.
|
|
20
|
+
|
|
21
|
+
But, setting `initialReport` to `onSubmit` still works different from the native browser behaviour, which basically calls `reportValidity()` only at the time a submit event is received. The `useForm` hook introduces a **touched** state to each fields. It will eagerly report the validity of the field once it is touched. Any errors reported later will be updated as soon as new errors are found.
|
|
22
|
+
|
|
23
|
+
Feel free to **SKIP** this if the native browser behaviour fullfills your need.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useForm } from '@conform-to/react';
|
|
27
|
+
|
|
28
|
+
function RandomForm() {
|
|
29
|
+
const formProps = useForm({
|
|
30
|
+
/**
|
|
31
|
+
* Decide when the error should be reported initially.
|
|
32
|
+
* The options are `onSubmit`, `onBlur` or `onChange`.
|
|
33
|
+
* Default to `onSubmit`
|
|
34
|
+
*/
|
|
35
|
+
initialReport: 'onBlur',
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Native browser report will be enabled before hydation
|
|
39
|
+
* if this is set to `true`. Default to `false`.
|
|
40
|
+
*/
|
|
41
|
+
fallbackNative: true,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The form could be submitted regardless of the validity
|
|
45
|
+
* of the form if this is set to `true`. Default to
|
|
46
|
+
* `false`.
|
|
47
|
+
*/
|
|
48
|
+
noValidate: false,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Form submit handler
|
|
52
|
+
*
|
|
53
|
+
* It will NOT be called if
|
|
54
|
+
* (1) one of the fields is invalid, and
|
|
55
|
+
* (2) noValidate is set to false
|
|
56
|
+
*/
|
|
57
|
+
onSubmit(e) {
|
|
58
|
+
// ...
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Form reset handler
|
|
63
|
+
*/
|
|
64
|
+
onReset(e) {
|
|
65
|
+
// ...
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return <form {...formProps}>{/* ... */}</form>;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>What is `formProps`?</summary>
|
|
75
|
+
|
|
76
|
+
It is a group of properties required to setup the form. They can also be set explicitly as shown below:
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<form
|
|
80
|
+
ref={formProps.ref}
|
|
81
|
+
onSubmit={formProps.onSubmit}
|
|
82
|
+
onReset={formProps.onReset}
|
|
83
|
+
noValidate={formProps.noValidate}
|
|
84
|
+
>
|
|
85
|
+
{/* ... */}
|
|
86
|
+
</form>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
19
93
|
### useFieldset
|
|
20
94
|
|
|
95
|
+
This hook prepares all the config you need to setup the fieldset based on the provided schema.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { useFieldset } from '@conform-to/react';
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Schema of the fieldset
|
|
102
|
+
*
|
|
103
|
+
* Defining a schema manually could be error-prone. It
|
|
104
|
+
* is strongly recommended to use a schema validation
|
|
105
|
+
* library with a schema resolver.
|
|
106
|
+
*
|
|
107
|
+
* Currently only Zod is supported and Yup support is
|
|
108
|
+
* coming soon. Please check the corresponding package
|
|
109
|
+
* for the setup required
|
|
110
|
+
*/
|
|
111
|
+
const schema = /*
|
|
112
|
+
Assuming this to be a schema for book and it looks like this:
|
|
113
|
+
|
|
114
|
+
type Book = {
|
|
115
|
+
name: string;
|
|
116
|
+
isbn: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
function BookFieldset() {
|
|
122
|
+
const [
|
|
123
|
+
fieldsetProps,
|
|
124
|
+
/**
|
|
125
|
+
* The variables `name` and `isbn` are FieldProps objects
|
|
126
|
+
* They are used to configure the field (input, select, textarea)
|
|
127
|
+
*
|
|
128
|
+
* Please check the docs of the `conform` helpers for how to
|
|
129
|
+
* use them together
|
|
130
|
+
*/
|
|
131
|
+
{
|
|
132
|
+
name,
|
|
133
|
+
isbn,
|
|
134
|
+
},
|
|
135
|
+
] = useFieldset(schema, {
|
|
136
|
+
/**
|
|
137
|
+
* Name of the fieldset
|
|
138
|
+
* Required only for nested fieldset.
|
|
139
|
+
*/
|
|
140
|
+
name: 'book',
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Id of the form
|
|
144
|
+
* Required only if the fieldset is placed out of the form
|
|
145
|
+
*/
|
|
146
|
+
form: 'random-form-id',
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Default value of the fieldset
|
|
150
|
+
*/
|
|
151
|
+
defaultValue: {
|
|
152
|
+
isbn: '0340013818',
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Error reported by the server
|
|
157
|
+
*/
|
|
158
|
+
error: {
|
|
159
|
+
isbn: 'Invalid ISBN',
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const {
|
|
164
|
+
/**
|
|
165
|
+
* This would be `book.isbn` instead of `isbn`
|
|
166
|
+
* if the `name` option is provided
|
|
167
|
+
*/
|
|
168
|
+
name,
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* This would be `random-form-id`
|
|
172
|
+
* because of the `form` option provided
|
|
173
|
+
*/
|
|
174
|
+
form,
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* This would be `0340013818` if specified
|
|
178
|
+
* on the `initalValue` option
|
|
179
|
+
*/
|
|
180
|
+
defaultValue,
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Current error message
|
|
184
|
+
* This would be 'Invalid ISBN' initially if specified
|
|
185
|
+
* on the `error` option
|
|
186
|
+
*/
|
|
187
|
+
error,
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Constraint of the field (required, minLength etc)
|
|
191
|
+
*
|
|
192
|
+
* For example, the constraint of the isbn field could be:
|
|
193
|
+
* {
|
|
194
|
+
* required: true,
|
|
195
|
+
* pattern: '[0-9]{10,13}'
|
|
196
|
+
* }
|
|
197
|
+
*/
|
|
198
|
+
...constraint,
|
|
199
|
+
} = isbn;
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<fieldset {...fieldsetProps}>
|
|
203
|
+
{/* ... */}
|
|
204
|
+
</fieldset>)
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
<details>
|
|
210
|
+
<summary>What is `fieldsetProps`?</summary>
|
|
211
|
+
|
|
212
|
+
It is a group of properties required to setup the fieldset. They can also be set explicitly as shown below:
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<fieldset
|
|
216
|
+
ref={fieldsetProps.ref}
|
|
217
|
+
name={fieldsetProps.name}
|
|
218
|
+
form={fieldsetProps.form}
|
|
219
|
+
onInput={fieldsetProps.onInput}
|
|
220
|
+
onInvalid={fieldsetProps.onInvalid}
|
|
221
|
+
>
|
|
222
|
+
{/* ... */}
|
|
223
|
+
</fieldset>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
<details>
|
|
229
|
+
<summary>How is a schema looks like?</summary>
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import type { Schema } from '@conform-to/react';
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Defining a schema manually
|
|
236
|
+
*/
|
|
237
|
+
const bookSchema: Schema<{
|
|
238
|
+
name: string;
|
|
239
|
+
isbn: string;
|
|
240
|
+
quantity?: number;
|
|
241
|
+
}> = {
|
|
242
|
+
/**
|
|
243
|
+
* Define the fields with its constraint together
|
|
244
|
+
*/
|
|
245
|
+
fields: {
|
|
246
|
+
name: {
|
|
247
|
+
required: true,
|
|
248
|
+
},
|
|
249
|
+
isbn: {
|
|
250
|
+
required: true,
|
|
251
|
+
minLength: 10,
|
|
252
|
+
maxLength: 13,
|
|
253
|
+
pattern: '[0-9]{10,13}',
|
|
254
|
+
},
|
|
255
|
+
quantity: {
|
|
256
|
+
min: '0',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Customise validation behaviour
|
|
262
|
+
* Fallbacks to native browser validation if not specified
|
|
263
|
+
*/
|
|
264
|
+
validate(fieldset) {
|
|
265
|
+
/**
|
|
266
|
+
* Lookup the field elements using the fieldset element
|
|
267
|
+
*/
|
|
268
|
+
const [name] = getFieldElements(fieldset, 'name');
|
|
269
|
+
|
|
270
|
+
if (name.validity.valueMissing) {
|
|
271
|
+
/**
|
|
272
|
+
* Setting error message based on validity
|
|
273
|
+
*/
|
|
274
|
+
name.setCustomValidity('Required');
|
|
275
|
+
} else if (name.value === 'something') {
|
|
276
|
+
/**
|
|
277
|
+
* Setting error message based on custom constraint
|
|
278
|
+
*/
|
|
279
|
+
name.setCustomValidity('Please enter a valid name');
|
|
280
|
+
} else {
|
|
281
|
+
/**
|
|
282
|
+
* Clearing the error message (Important!)
|
|
283
|
+
*/
|
|
284
|
+
name.setCustomValidity('');
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
21
294
|
### useFieldList
|
|
295
|
+
|
|
296
|
+
This hook is used in combination with `useFieldset` to handle array structure:
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
import { useFieldset, useFieldList } from '@conform-to/react';
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Consider the schema as follow:
|
|
303
|
+
*
|
|
304
|
+
* type Collection = {
|
|
305
|
+
* books: Array<{ name: string; isbn: string; }>
|
|
306
|
+
* }
|
|
307
|
+
*/
|
|
308
|
+
|
|
309
|
+
function CollectionForm() {
|
|
310
|
+
const [fieldsetProps, { books }] = useFieldset(collectionSchema);
|
|
311
|
+
const [bookList, control] = useFieldList(books);
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<fieldset {...fieldsetProps}>
|
|
315
|
+
{bookList.map((book, index) => (
|
|
316
|
+
<div key={book.key}>
|
|
317
|
+
{/* `book.props` is a FieldProps object similar to `books` */}
|
|
318
|
+
<BookFieldset {...book.props}>
|
|
319
|
+
|
|
320
|
+
{/* To setup a delete button */}
|
|
321
|
+
<button {...control.remove(index)}>Delete</button>
|
|
322
|
+
</div>
|
|
323
|
+
))}
|
|
324
|
+
|
|
325
|
+
{/* To setup a button that can append a new row */}
|
|
326
|
+
<button {...control.append()}>add</button>
|
|
327
|
+
</fieldset>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* This is basically the BookFieldset component from
|
|
333
|
+
* the `useFieldset` example, but setting all the
|
|
334
|
+
* options with the component props instead
|
|
335
|
+
*/
|
|
336
|
+
function BookFieldset({ name, form, defaultValue, error }) {
|
|
337
|
+
const [fieldsetProps, { name, isbn }] = useFieldset(bookSchema, {
|
|
338
|
+
name,
|
|
339
|
+
form,
|
|
340
|
+
defaultValue,
|
|
341
|
+
error,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<fieldset {...fieldsetProps}>
|
|
346
|
+
{/* ... */}
|
|
347
|
+
</fieldset>
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
<details>
|
|
353
|
+
<summary>What can I do with `controls`?</summary>
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
// To append a new row with optional defaultValue
|
|
357
|
+
<button {...controls.append(defaultValue)}>Append</button>;
|
|
358
|
+
|
|
359
|
+
// To prepend a new row with optional defaultValue
|
|
360
|
+
<button {...controls.prepend(defaultValue)}>Prepend</button>;
|
|
361
|
+
|
|
362
|
+
// To remove a row by index
|
|
363
|
+
<button {...controls.remove(index)}>Remove</button>;
|
|
364
|
+
|
|
365
|
+
// To replace a row with another defaultValue
|
|
366
|
+
<button {...controls.replace(index, defaultValue)}>Replace</button>;
|
|
367
|
+
|
|
368
|
+
// To reorder a particular row to an another index
|
|
369
|
+
<button {...controls.reorder(fromIndex, toIndex)}>Reorder</button>;
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
</details>
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### useControlledInput
|
|
377
|
+
|
|
378
|
+
This hooks creates a shadow input that would be used to validate against the schema. Mainly used to get around problem integrating with controlled component.
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
import { useControlledInput } from '@conform-to/react';
|
|
382
|
+
import { Select, MenuItem } from '@mui/material';
|
|
383
|
+
|
|
384
|
+
function RandomFieldset() {
|
|
385
|
+
const [fieldsetProps, { category }] = useFieldset(schema);
|
|
386
|
+
const [input, control] = useControlledInput(category);
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<fieldset {...fieldsetProps}>
|
|
390
|
+
{/* Render the shadow input somewhere within the fieldset */}
|
|
391
|
+
{input}
|
|
392
|
+
|
|
393
|
+
{/* MUI Select is a controlled component */}
|
|
394
|
+
<Select
|
|
395
|
+
label="Category"
|
|
396
|
+
value={control.value ?? ''}
|
|
397
|
+
onChange={(e) => control.onChange(e.target.value)}
|
|
398
|
+
onBlur={() => control.onBlur()}
|
|
399
|
+
error={Boolean(category.error)}
|
|
400
|
+
helperText={category.error}
|
|
401
|
+
>
|
|
402
|
+
<MenuItem value="">Please select</MenuItem>
|
|
403
|
+
<MenuItem value="a">Category A</MenuItem>
|
|
404
|
+
<MenuItem value="b">Category B</MenuItem>
|
|
405
|
+
<MenuItem value="c">Category C</MenuItem>
|
|
406
|
+
</TextField>
|
|
407
|
+
</fieldset>
|
|
408
|
+
)
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### conform
|
|
415
|
+
|
|
416
|
+
It provides several helpers to setup a native input field quickly:
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
import { conform } from '@conform-to/react';
|
|
420
|
+
|
|
421
|
+
function RandomForm() {
|
|
422
|
+
const [setupFieldset, { cateogry }] = useFieldset(/* ... */);
|
|
423
|
+
|
|
424
|
+
return (
|
|
425
|
+
<fieldset {...setupFieldset}>
|
|
426
|
+
<input {...conform.input(cateogry, { type: 'text' })} />
|
|
427
|
+
<textarea {...conform.textarea(cateogry)} />
|
|
428
|
+
<select {...conform.select(cateogry)}>{/* ... */}</select>
|
|
429
|
+
</fieldset>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
This is equivalent to:
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
function RandomForm() {
|
|
438
|
+
const [setupFieldset, { cateogry }] = useFieldset(/* ... */);
|
|
439
|
+
|
|
440
|
+
return (
|
|
441
|
+
<fieldset {...setupFieldset}>
|
|
442
|
+
<input
|
|
443
|
+
type="text"
|
|
444
|
+
name={cateogry.name}
|
|
445
|
+
form={cateogry.form}
|
|
446
|
+
defaultValue={cateogry.defaultValue}
|
|
447
|
+
requried={cateogry.required}
|
|
448
|
+
minLength={cateogry.minLength}
|
|
449
|
+
maxLength={cateogry.maxLength}
|
|
450
|
+
min={cateogry.min}
|
|
451
|
+
max={cateogry.max}
|
|
452
|
+
multiple={cateogry.multiple}
|
|
453
|
+
pattern={cateogry.pattern}
|
|
454
|
+
>
|
|
455
|
+
<textarea
|
|
456
|
+
name={cateogry.name}
|
|
457
|
+
form={cateogry.form}
|
|
458
|
+
defaultValue={cateogry.defaultValue}
|
|
459
|
+
requried={cateogry.required}
|
|
460
|
+
minLength={cateogry.minLength}
|
|
461
|
+
maxLength={cateogry.maxLength}
|
|
462
|
+
/>
|
|
463
|
+
<select
|
|
464
|
+
name={cateogry.name}
|
|
465
|
+
form={cateogry.form}
|
|
466
|
+
defaultValue={cateogry.defaultValue}
|
|
467
|
+
requried={cateogry.required}
|
|
468
|
+
multiple={cateogry.multiple}
|
|
469
|
+
>
|
|
470
|
+
{/* ... */}
|
|
471
|
+
</select>
|
|
472
|
+
</fieldset>
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
```
|
package/helpers.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type FieldProps } from '@conform-to/dom';
|
|
2
2
|
import { type InputHTMLAttributes, type SelectHTMLAttributes, type TextareaHTMLAttributes } from 'react';
|
|
3
|
-
export declare function input<Type extends string | number | Date | boolean | undefined>(
|
|
3
|
+
export declare function input<Type extends string | number | Date | boolean | undefined>(props: FieldProps<Type>, { type, value }?: {
|
|
4
4
|
type?: string;
|
|
5
5
|
value?: string;
|
|
6
6
|
}): InputHTMLAttributes<HTMLInputElement>;
|
|
7
|
-
export declare function select<T extends any>(
|
|
8
|
-
export declare function textarea<T extends string | undefined>(
|
|
7
|
+
export declare function select<T extends any>(props: FieldProps<T>): SelectHTMLAttributes<HTMLSelectElement>;
|
|
8
|
+
export declare function textarea<T extends string | undefined>(props: FieldProps<T>): TextareaHTMLAttributes<HTMLTextAreaElement>;
|
package/helpers.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
function input(
|
|
6
|
-
var _config$constraint, _config$constraint2, _config$constraint3, _config$constraint4, _config$constraint5, _config$constraint6, _config$constraint7;
|
|
7
|
-
|
|
5
|
+
function input(props) {
|
|
8
6
|
var {
|
|
9
7
|
type,
|
|
10
8
|
value
|
|
@@ -12,49 +10,50 @@ function input(config) {
|
|
|
12
10
|
var isCheckboxOrRadio = type === 'checkbox' || type === 'radio';
|
|
13
11
|
var attributes = {
|
|
14
12
|
type,
|
|
15
|
-
name:
|
|
16
|
-
form:
|
|
17
|
-
required:
|
|
18
|
-
minLength:
|
|
19
|
-
maxLength:
|
|
20
|
-
min:
|
|
21
|
-
max:
|
|
22
|
-
step:
|
|
23
|
-
pattern:
|
|
13
|
+
name: props.name,
|
|
14
|
+
form: props.form,
|
|
15
|
+
required: props.required,
|
|
16
|
+
minLength: props.minLength,
|
|
17
|
+
maxLength: props.maxLength,
|
|
18
|
+
min: props.min,
|
|
19
|
+
max: props.max,
|
|
20
|
+
step: props.step,
|
|
21
|
+
pattern: props.pattern,
|
|
22
|
+
multiple: props.multiple
|
|
24
23
|
};
|
|
25
24
|
|
|
26
25
|
if (isCheckboxOrRadio) {
|
|
27
26
|
attributes.value = value !== null && value !== void 0 ? value : 'on';
|
|
28
|
-
attributes.defaultChecked =
|
|
27
|
+
attributes.defaultChecked = props.defaultValue === attributes.value;
|
|
29
28
|
} else {
|
|
30
|
-
var
|
|
29
|
+
var _props$defaultValue;
|
|
31
30
|
|
|
32
|
-
attributes.defaultValue = "".concat((
|
|
31
|
+
attributes.defaultValue = "".concat((_props$defaultValue = props.defaultValue) !== null && _props$defaultValue !== void 0 ? _props$defaultValue : '');
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
return attributes;
|
|
36
35
|
}
|
|
37
|
-
function select(
|
|
38
|
-
var
|
|
36
|
+
function select(props) {
|
|
37
|
+
var _props$defaultValue2;
|
|
39
38
|
|
|
40
39
|
return {
|
|
41
|
-
name:
|
|
42
|
-
form:
|
|
43
|
-
defaultValue: "".concat((
|
|
44
|
-
required:
|
|
45
|
-
multiple:
|
|
40
|
+
name: props.name,
|
|
41
|
+
form: props.form,
|
|
42
|
+
defaultValue: props.multiple ? Array.isArray(props.defaultValue) ? props.defaultValue : [] : "".concat((_props$defaultValue2 = props.defaultValue) !== null && _props$defaultValue2 !== void 0 ? _props$defaultValue2 : ''),
|
|
43
|
+
required: props.required,
|
|
44
|
+
multiple: props.multiple
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
|
-
function textarea(
|
|
49
|
-
var
|
|
47
|
+
function textarea(props) {
|
|
48
|
+
var _props$defaultValue3;
|
|
50
49
|
|
|
51
50
|
return {
|
|
52
|
-
name:
|
|
53
|
-
form:
|
|
54
|
-
defaultValue: "".concat((
|
|
55
|
-
required:
|
|
56
|
-
minLength:
|
|
57
|
-
maxLength:
|
|
51
|
+
name: props.name,
|
|
52
|
+
form: props.form,
|
|
53
|
+
defaultValue: "".concat((_props$defaultValue3 = props.defaultValue) !== null && _props$defaultValue3 !== void 0 ? _props$defaultValue3 : ''),
|
|
54
|
+
required: props.required,
|
|
55
|
+
minLength: props.minLength,
|
|
56
|
+
maxLength: props.maxLength
|
|
58
57
|
};
|
|
59
58
|
}
|
|
60
59
|
|
package/hooks.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type FieldProps, type Schema, type FieldsetData } from '@conform-to/dom';
|
|
2
2
|
import { type ButtonHTMLAttributes, type FormEventHandler, type FormHTMLAttributes, type RefObject, type ReactElement } from 'react';
|
|
3
|
-
interface FormConfig {
|
|
3
|
+
export interface FormConfig {
|
|
4
4
|
/**
|
|
5
5
|
* Decide when the error should be reported initially.
|
|
6
6
|
* Default to `onSubmit`
|
|
@@ -30,35 +30,35 @@ interface FormProps {
|
|
|
30
30
|
noValidate: Required<FormHTMLAttributes<HTMLFormElement>>['noValidate'];
|
|
31
31
|
}
|
|
32
32
|
export declare function useForm({ onReset, onSubmit, noValidate, fallbackNative, initialReport, }?: FormConfig): FormProps;
|
|
33
|
-
|
|
34
|
-
}
|
|
33
|
+
export declare type FieldsetConfig<Type> = Partial<Pick<FieldProps<Type>, 'name' | 'form' | 'defaultValue' | 'error'>>;
|
|
35
34
|
interface FieldsetProps {
|
|
36
35
|
ref: RefObject<HTMLFieldSetElement>;
|
|
37
36
|
name?: string;
|
|
38
37
|
form?: string;
|
|
39
38
|
onInput: FormEventHandler<HTMLFieldSetElement>;
|
|
40
|
-
onReset: FormEventHandler<HTMLFieldSetElement>;
|
|
41
39
|
onInvalid: FormEventHandler<HTMLFieldSetElement>;
|
|
42
40
|
}
|
|
43
41
|
export declare function useFieldset<Type extends Record<string, any>>(schema: Schema<Type>, config?: FieldsetConfig<Type>): [FieldsetProps, {
|
|
44
|
-
[Key in keyof Type]-?:
|
|
42
|
+
[Key in keyof Type]-?: FieldProps<Type[Key]>;
|
|
45
43
|
}];
|
|
46
|
-
interface FieldListControl {
|
|
47
|
-
prepend(): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
48
|
-
append(): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
44
|
+
interface FieldListControl<T> {
|
|
45
|
+
prepend(defaultValue?: FieldsetData<T, string>): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
46
|
+
append(defaultValue?: FieldsetData<T, string>): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
47
|
+
replace(index: number, defaultValue: FieldsetData<T, string>): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
49
48
|
remove(index: number): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
49
|
+
reorder(fromIndex: number, toIndex: number): ButtonHTMLAttributes<HTMLButtonElement>;
|
|
50
50
|
}
|
|
51
|
-
export declare function useFieldList<
|
|
51
|
+
export declare function useFieldList<Payload>(props: FieldProps<Array<Payload>>): [
|
|
52
52
|
Array<{
|
|
53
53
|
key: string;
|
|
54
|
-
|
|
54
|
+
props: FieldProps<Payload>;
|
|
55
55
|
}>,
|
|
56
|
-
FieldListControl
|
|
56
|
+
FieldListControl<Payload>
|
|
57
57
|
];
|
|
58
58
|
interface InputControl {
|
|
59
59
|
value: string;
|
|
60
60
|
onChange: (value: string) => void;
|
|
61
61
|
onBlur: () => void;
|
|
62
62
|
}
|
|
63
|
-
export declare function useControlledInput<T extends string | number | Date | undefined>(field:
|
|
63
|
+
export declare function useControlledInput<T extends string | number | Date | undefined>(field: FieldProps<T>): [ReactElement, InputControl];
|
|
64
64
|
export {};
|