@conform-to/react 0.6.0-pre.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -133
- package/helpers.d.ts +17 -20
- package/helpers.js +50 -65
- package/hooks.d.ts +31 -24
- package/hooks.js +121 -140
- package/index.d.ts +2 -2
- package/index.js +2 -6
- package/module/helpers.js +48 -66
- package/module/hooks.js +123 -142
- package/module/index.js +1 -1
- package/package.json +7 -3
- package/base.d.ts +0 -17
- package/base.js +0 -112
- package/module/base.js +0 -107
package/README.md
CHANGED
|
@@ -11,13 +11,12 @@
|
|
|
11
11
|
- [useFieldList](#usefieldlist)
|
|
12
12
|
- [useInputEvent](#useinputevent)
|
|
13
13
|
- [conform](#conform)
|
|
14
|
+
- [parse](#parse)
|
|
15
|
+
- [validateConstraint](#validateconstraint)
|
|
14
16
|
- [list](#list)
|
|
15
17
|
- [validate](#validate)
|
|
16
18
|
- [requestIntent](#requestintent)
|
|
17
|
-
- [
|
|
18
|
-
- [hasError](#haserror)
|
|
19
|
-
- [parse](#parse)
|
|
20
|
-
- [shouldValidate](#shouldvalidate)
|
|
19
|
+
- [isFieldElement](#isfieldelement)
|
|
21
20
|
|
|
22
21
|
<!-- /aside -->
|
|
23
22
|
|
|
@@ -27,9 +26,9 @@ By default, the browser calls the [reportValidity()](https://developer.mozilla.o
|
|
|
27
26
|
|
|
28
27
|
This hook enhances the form validation behaviour by:
|
|
29
28
|
|
|
30
|
-
- Enabling customizing
|
|
31
|
-
- Capturing
|
|
32
|
-
- Preparing all properties required to configure the
|
|
29
|
+
- Enabling customizing validation logic.
|
|
30
|
+
- Capturing error message and removes the error bubbles.
|
|
31
|
+
- Preparing all properties required to configure the form elements.
|
|
33
32
|
|
|
34
33
|
```tsx
|
|
35
34
|
import { useForm } from '@conform-to/react';
|
|
@@ -43,27 +42,35 @@ function LoginForm() {
|
|
|
43
42
|
id: undefined,
|
|
44
43
|
|
|
45
44
|
/**
|
|
46
|
-
* Define when
|
|
45
|
+
* Define when conform should start validation.
|
|
47
46
|
* Support "onSubmit", "onChange", "onBlur".
|
|
48
47
|
*
|
|
49
48
|
* Default to `onSubmit`.
|
|
50
49
|
*/
|
|
51
|
-
|
|
50
|
+
shouldValidate: 'onSubmit',
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Define when conform should revalidate again.
|
|
54
|
+
* Support "onSubmit", "onChange", "onBlur".
|
|
55
|
+
*
|
|
56
|
+
* Default to `onInput`.
|
|
57
|
+
*/
|
|
58
|
+
shouldRevalidate: 'onInput',
|
|
52
59
|
|
|
53
60
|
/**
|
|
54
61
|
* An object representing the initial value of the form.
|
|
55
62
|
*/
|
|
56
|
-
defaultValue: undefined
|
|
63
|
+
defaultValue: undefined,
|
|
57
64
|
|
|
58
65
|
/**
|
|
59
|
-
*
|
|
66
|
+
* The last submission result from the server
|
|
60
67
|
*/
|
|
61
|
-
|
|
68
|
+
lastSubmission: undefined,
|
|
62
69
|
|
|
63
70
|
/**
|
|
64
71
|
* An object describing the constraint of each field
|
|
65
72
|
*/
|
|
66
|
-
constraint: undefined
|
|
73
|
+
constraint: undefined,
|
|
67
74
|
|
|
68
75
|
/**
|
|
69
76
|
* Enable native validation before hydation.
|
|
@@ -90,7 +97,7 @@ function LoginForm() {
|
|
|
90
97
|
/**
|
|
91
98
|
* The submit event handler of the form.
|
|
92
99
|
*/
|
|
93
|
-
onSubmit(event, { formData, submission }) {
|
|
100
|
+
onSubmit(event, { formData, submission, action, encType, method }) {
|
|
94
101
|
// ...
|
|
95
102
|
},
|
|
96
103
|
});
|
|
@@ -165,20 +172,20 @@ function Example() {
|
|
|
165
172
|
const [form, { address }] = useForm<{ address: Address }>();
|
|
166
173
|
const { city, zipcode, street, country } = useFieldset(
|
|
167
174
|
form.ref,
|
|
168
|
-
address
|
|
175
|
+
address,
|
|
169
176
|
);
|
|
170
177
|
|
|
171
178
|
return (
|
|
172
179
|
<form {...form.props}>
|
|
173
180
|
<fieldset>
|
|
174
181
|
<legned>Address</legend>
|
|
175
|
-
<input {...conform.input(street
|
|
182
|
+
<input {...conform.input(street)} />
|
|
176
183
|
<div>{street.error}</div>
|
|
177
|
-
<input {...conform.input(zipcode
|
|
184
|
+
<input {...conform.input(zipcode)} />
|
|
178
185
|
<div>{zipcode.error}</div>
|
|
179
|
-
<input {...conform.input(city
|
|
186
|
+
<input {...conform.input(city)} />
|
|
180
187
|
<div>{city.error}</div>
|
|
181
|
-
<input {...conform.input(country
|
|
188
|
+
<input {...conform.input(country)} />
|
|
182
189
|
<div>{country.error}</div>
|
|
183
190
|
</fieldset>
|
|
184
191
|
<button>Submit</button>
|
|
@@ -204,7 +211,7 @@ function Fieldset(config: FieldConfig<Address>) {
|
|
|
204
211
|
<details>
|
|
205
212
|
<summary>Why does `useFieldset` require a ref object of the form or fieldset?</summary>
|
|
206
213
|
|
|
207
|
-
**conform** utilises the DOM as its context provider / input registry, which maintains a link between each input / button / fieldset with the form through the [form property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#properties). The ref object allows it to restrict the scope to elements associated to the same form only.
|
|
214
|
+
**conform** utilises the DOM as its context provider / input registry, which maintains a link between each input / button / fieldset with the form through the [form property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#properties). The ref object allows it to restrict the scope to form elements associated to the same form only.
|
|
208
215
|
|
|
209
216
|
```tsx
|
|
210
217
|
function ExampleForm() {
|
|
@@ -231,7 +238,7 @@ function ExampleForm() {
|
|
|
231
238
|
|
|
232
239
|
### useFieldList
|
|
233
240
|
|
|
234
|
-
This hook enables you to work with [array](/docs/configuration.md#array) and support [list](#list)
|
|
241
|
+
This hook enables you to work with [array](/docs/configuration.md#array) and support the [list](#list) intent button builder to modify a list. It can also be used with [useFieldset](#usefieldset) for [nested list](/docs/configuration.md#nested-list) at the same time.
|
|
235
242
|
|
|
236
243
|
```tsx
|
|
237
244
|
import { useForm, useFieldList, list } from '@conform-to/react';
|
|
@@ -245,27 +252,25 @@ type Schema = {
|
|
|
245
252
|
|
|
246
253
|
function Example() {
|
|
247
254
|
const [form, { items }] = useForm<Schema>();
|
|
248
|
-
const
|
|
255
|
+
const itemsList = useFieldList(form.ref, items);
|
|
249
256
|
|
|
250
257
|
return (
|
|
251
258
|
<fieldset ref={ref}>
|
|
252
|
-
{
|
|
259
|
+
{itemsList.map((item, index) => (
|
|
253
260
|
<div key={item.key}>
|
|
254
261
|
{/* Setup an input per item */}
|
|
255
|
-
<input {...conform.input(item
|
|
262
|
+
<input {...conform.input(item)} />
|
|
256
263
|
|
|
257
264
|
{/* Error of each item */}
|
|
258
265
|
<span>{item.error}</span>
|
|
259
266
|
|
|
260
267
|
{/* Setup a delete button (Note: It is `items` not `item`) */}
|
|
261
|
-
<button {...list.remove(items.
|
|
268
|
+
<button {...list.remove(items.name, { index })}>Delete</button>
|
|
262
269
|
</div>
|
|
263
270
|
))}
|
|
264
271
|
|
|
265
272
|
{/* Setup a button that can append a new row with optional default value */}
|
|
266
|
-
<button {...list.append(items.
|
|
267
|
-
add
|
|
268
|
-
</button>
|
|
273
|
+
<button {...list.append(items.name, { defaultValue: '' })}>add</button>
|
|
269
274
|
</fieldset>
|
|
270
275
|
);
|
|
271
276
|
}
|
|
@@ -284,9 +289,9 @@ import { useState, useRef } from 'react';
|
|
|
284
289
|
|
|
285
290
|
function MuiForm() {
|
|
286
291
|
const [form, { category }] = useForm();
|
|
287
|
-
const [value, setValue] = useState(category.
|
|
292
|
+
const [value, setValue] = useState(category.defaultValue ?? '');
|
|
288
293
|
const [ref, control] = useInputEvent({
|
|
289
|
-
onReset: () => setValue(category.
|
|
294
|
+
onReset: () => setValue(category.defaultValue ?? ''),
|
|
290
295
|
});
|
|
291
296
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
292
297
|
|
|
@@ -295,7 +300,7 @@ function MuiForm() {
|
|
|
295
300
|
{/* Render a shadow input somewhere */}
|
|
296
301
|
<input
|
|
297
302
|
ref={ref}
|
|
298
|
-
{...conform.input(category
|
|
303
|
+
{...conform.input(category, { hidden: true })}
|
|
299
304
|
onChange={(e) => setValue(e.target.value)}
|
|
300
305
|
onFocus={() => inputRef.current?.focus()}
|
|
301
306
|
/>
|
|
@@ -323,9 +328,9 @@ function MuiForm() {
|
|
|
323
328
|
|
|
324
329
|
### conform
|
|
325
330
|
|
|
326
|
-
It provides several helpers to remove the boilerplate when configuring a form control.
|
|
331
|
+
It provides several helpers to remove the boilerplate when configuring a form control and derives attributes for [accessibility](/docs/accessibility.md#configuration) concerns and helps [focus management](/docs/focus-management.md#focusing-before-javascript-is-loaded).
|
|
327
332
|
|
|
328
|
-
You
|
|
333
|
+
You can also create a wrapper on top if you need to integrate with custom input component.
|
|
329
334
|
|
|
330
335
|
Before:
|
|
331
336
|
|
|
@@ -339,31 +344,31 @@ function Example() {
|
|
|
339
344
|
<form {...form.props}>
|
|
340
345
|
<input
|
|
341
346
|
type="text"
|
|
342
|
-
name={title.
|
|
343
|
-
form={title.
|
|
344
|
-
defaultValue={title.
|
|
345
|
-
requried={title.
|
|
346
|
-
minLength={title.
|
|
347
|
-
maxLength={title.
|
|
348
|
-
min={title.
|
|
349
|
-
max={title.
|
|
350
|
-
multiple={title.
|
|
351
|
-
pattern={title.
|
|
347
|
+
name={title.name}
|
|
348
|
+
form={title.form}
|
|
349
|
+
defaultValue={title.defaultValue}
|
|
350
|
+
requried={title.required}
|
|
351
|
+
minLength={title.minLength}
|
|
352
|
+
maxLength={title.maxLength}
|
|
353
|
+
min={title.min}
|
|
354
|
+
max={title.max}
|
|
355
|
+
multiple={title.multiple}
|
|
356
|
+
pattern={title.pattern}
|
|
352
357
|
/>
|
|
353
358
|
<textarea
|
|
354
|
-
name={description.
|
|
355
|
-
form={description.
|
|
356
|
-
defaultValue={description.
|
|
357
|
-
requried={description.
|
|
358
|
-
minLength={description.
|
|
359
|
-
maxLength={description.
|
|
359
|
+
name={description.name}
|
|
360
|
+
form={description.form}
|
|
361
|
+
defaultValue={description.defaultValue}
|
|
362
|
+
requried={description.required}
|
|
363
|
+
minLength={description.minLength}
|
|
364
|
+
maxLength={description.maxLength}
|
|
360
365
|
/>
|
|
361
366
|
<select
|
|
362
|
-
name={category.
|
|
363
|
-
form={category.
|
|
364
|
-
defaultValue={category.
|
|
365
|
-
requried={category.
|
|
366
|
-
multiple={category.
|
|
367
|
+
name={category.name}
|
|
368
|
+
form={category.form}
|
|
369
|
+
defaultValue={category.defaultValue}
|
|
370
|
+
requried={category.required}
|
|
371
|
+
multiple={category.multiple}
|
|
367
372
|
>
|
|
368
373
|
{/* ... */}
|
|
369
374
|
</select>
|
|
@@ -382,9 +387,9 @@ function Example() {
|
|
|
382
387
|
|
|
383
388
|
return (
|
|
384
389
|
<form {...form.props}>
|
|
385
|
-
<input {...conform.input(title
|
|
386
|
-
<textarea {...conform.textarea(description
|
|
387
|
-
<select {...conform.select(category
|
|
390
|
+
<input {...conform.input(title, { type: 'text' })} />
|
|
391
|
+
<textarea {...conform.textarea(description)} />
|
|
392
|
+
<select {...conform.select(category)}>{/* ... */}</select>
|
|
388
393
|
</form>
|
|
389
394
|
);
|
|
390
395
|
}
|
|
@@ -392,9 +397,117 @@ function Example() {
|
|
|
392
397
|
|
|
393
398
|
---
|
|
394
399
|
|
|
400
|
+
### parse
|
|
401
|
+
|
|
402
|
+
It parses the formData based on the [naming convention](/docs/configuration.md#naming-convention) with the validation result from the resolver.
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
import { parse } from '@conform-to/react';
|
|
406
|
+
|
|
407
|
+
const formData = new FormData();
|
|
408
|
+
const submission = parse(formData, {
|
|
409
|
+
resolve({ email, password }) {
|
|
410
|
+
const error: Record<string, string> = {};
|
|
411
|
+
|
|
412
|
+
if (typeof email !== 'string') {
|
|
413
|
+
error.email = 'Email is required';
|
|
414
|
+
} else if (!/^[^@]+@[^@]+$/.test(email)) {
|
|
415
|
+
error.email = 'Email is invalid';
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (typeof password !== 'string') {
|
|
419
|
+
error.password = 'Password is required';
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (error.email || error.password) {
|
|
423
|
+
return { error };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
value: { email, password },
|
|
428
|
+
};
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
### validateConstraint
|
|
436
|
+
|
|
437
|
+
This enable Constraint Validation with ability to enable custom constraint using data-attribute and customizing error messages. By default, the error message would be the attribute that triggered the error (e.g. `required` / `type` / 'minLength' etc).
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import { useForm, validateConstraint } from '@conform-to/react';
|
|
441
|
+
import { Form } from 'react-router-dom';
|
|
442
|
+
|
|
443
|
+
export default function SignupForm() {
|
|
444
|
+
const [form, { email, password, confirmPassword }] = useForm({
|
|
445
|
+
onValidate(context) {
|
|
446
|
+
// This enables validating each field based on the validity state and custom cosntraint if defined
|
|
447
|
+
return validateConstraint(
|
|
448
|
+
...context,
|
|
449
|
+
constraint: {
|
|
450
|
+
// Define custom constraint
|
|
451
|
+
match(value, { formData, attributeValue }) {
|
|
452
|
+
// Check if the value of the field match the value of another field
|
|
453
|
+
return value === formData.get(attributeValue);
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<Form method="post" {...form.props}>
|
|
461
|
+
<div>
|
|
462
|
+
<label>Email</label>
|
|
463
|
+
<input
|
|
464
|
+
name="email"
|
|
465
|
+
type="email"
|
|
466
|
+
required
|
|
467
|
+
pattern="[^@]+@[^@]+\\.[^@]+"
|
|
468
|
+
/>
|
|
469
|
+
{email.error === 'required' ? (
|
|
470
|
+
<div>Email is required</div>
|
|
471
|
+
) : email.error === 'type' ? (
|
|
472
|
+
<div>Email is invalid</div>
|
|
473
|
+
) : null}
|
|
474
|
+
</div>
|
|
475
|
+
<div>
|
|
476
|
+
<label>Password</label>
|
|
477
|
+
<input
|
|
478
|
+
name="password"
|
|
479
|
+
type="password"
|
|
480
|
+
required
|
|
481
|
+
/>
|
|
482
|
+
{password.error === 'required' ? (
|
|
483
|
+
<div>Password is required</div>
|
|
484
|
+
) : null}
|
|
485
|
+
</div>
|
|
486
|
+
<div>
|
|
487
|
+
<label>Confirm Password</label>
|
|
488
|
+
<input
|
|
489
|
+
name="confirmPassword"
|
|
490
|
+
type="password"
|
|
491
|
+
required
|
|
492
|
+
data-constraint-match="password"
|
|
493
|
+
/>
|
|
494
|
+
{confirmPassword.error === 'required' ? (
|
|
495
|
+
<div>Confirm Password is required</div>
|
|
496
|
+
) : confirmPassword.error === 'match' ? (
|
|
497
|
+
<div>Password does not match</div>
|
|
498
|
+
) : null}
|
|
499
|
+
</div>
|
|
500
|
+
<button>Signup</button>
|
|
501
|
+
</Form>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
395
508
|
### list
|
|
396
509
|
|
|
397
|
-
It provides serveral helpers to configure
|
|
510
|
+
It provides serveral helpers to configure an intent button for [modifying a list](/docs/commands.md#modifying-a-list).
|
|
398
511
|
|
|
399
512
|
```tsx
|
|
400
513
|
import { list } from '@conform-to/react';
|
|
@@ -427,7 +540,7 @@ function Example() {
|
|
|
427
540
|
|
|
428
541
|
### validate
|
|
429
542
|
|
|
430
|
-
It returns the properties required to configure
|
|
543
|
+
It returns the properties required to configure an intent button for [validation](/docs/commands.md#validation).
|
|
431
544
|
|
|
432
545
|
```tsx
|
|
433
546
|
import { validate } from '@conform-to/react';
|
|
@@ -463,7 +576,7 @@ import DragAndDrop from 'awesome-dnd-example';
|
|
|
463
576
|
|
|
464
577
|
export default function Todos() {
|
|
465
578
|
const [form, { tasks }] = useForm();
|
|
466
|
-
const taskList = useFieldList(form.ref, tasks
|
|
579
|
+
const taskList = useFieldList(form.ref, tasks);
|
|
467
580
|
|
|
468
581
|
const handleDrop = (from, to) =>
|
|
469
582
|
requestIntent(form.ref.current, list.reorder({ from, to }));
|
|
@@ -473,7 +586,7 @@ export default function Todos() {
|
|
|
473
586
|
<DragAndDrop onDrop={handleDrop}>
|
|
474
587
|
{taskList.map((task, index) => (
|
|
475
588
|
<div key={task.key}>
|
|
476
|
-
<input {...conform.input(task
|
|
589
|
+
<input {...conform.input(task)} />
|
|
477
590
|
</div>
|
|
478
591
|
))}
|
|
479
592
|
</DragAndDrop>
|
|
@@ -485,81 +598,22 @@ export default function Todos() {
|
|
|
485
598
|
|
|
486
599
|
---
|
|
487
600
|
|
|
488
|
-
###
|
|
601
|
+
### isFieldElement
|
|
489
602
|
|
|
490
|
-
|
|
603
|
+
This is an utility for checking if the provided element is a form element (_input_ / _select_ / _textarea_ or _button_) which also works as a type guard.
|
|
491
604
|
|
|
492
605
|
```tsx
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
for (const element of getFormElements(form)) {
|
|
501
|
-
switch (element.name) {
|
|
502
|
-
case 'email': {
|
|
503
|
-
if (element.validity.valueMissing) {
|
|
504
|
-
submission.error.push([element.name, 'Email is required']);
|
|
505
|
-
} else if (element.validity.typeMismatch) {
|
|
506
|
-
submission.error.push([element.name, 'Email is invalid']);
|
|
507
|
-
}
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
case 'password': {
|
|
511
|
-
if (element.validity.valueMissing) {
|
|
512
|
-
submission.error.push([element.name, 'Password is required']);
|
|
513
|
-
}
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
606
|
+
function Example() {
|
|
607
|
+
return (
|
|
608
|
+
<form
|
|
609
|
+
onFocus={(event) => {
|
|
610
|
+
if (isFieldElement(event.target)) {
|
|
611
|
+
// event.target is now considered one of the form elements type
|
|
516
612
|
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
// ....
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
// ...
|
|
613
|
+
}}
|
|
614
|
+
>
|
|
615
|
+
{/* ... */}
|
|
616
|
+
</form>
|
|
617
|
+
);
|
|
526
618
|
}
|
|
527
619
|
```
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
### parse
|
|
532
|
-
|
|
533
|
-
It parses the formData based on the [naming convention](/docs/submission).
|
|
534
|
-
|
|
535
|
-
```tsx
|
|
536
|
-
import { parse } from '@conform-to/react';
|
|
537
|
-
|
|
538
|
-
const formData = new FormData();
|
|
539
|
-
const submission = parse(formData);
|
|
540
|
-
|
|
541
|
-
console.log(submission);
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
---
|
|
545
|
-
|
|
546
|
-
### shouldValidate
|
|
547
|
-
|
|
548
|
-
This helper checks if the scope of validation includes a specific field by checking the submission:
|
|
549
|
-
|
|
550
|
-
```tsx
|
|
551
|
-
import { shouldValidate } from '@conform-to/react';
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* The submission intent give us hint on what should be valdiated.
|
|
555
|
-
* If the intent is 'validate/:field', only the field with name matching must be validated.
|
|
556
|
-
* If the intent is undefined, everything should be validated (Default submission)
|
|
557
|
-
*/
|
|
558
|
-
const intent = 'validate/email';
|
|
559
|
-
|
|
560
|
-
// This will log 'true'
|
|
561
|
-
console.log(shouldValidate(intent, 'email'));
|
|
562
|
-
|
|
563
|
-
// This will log 'false'
|
|
564
|
-
console.log(shouldValidate(intent, 'password'));
|
|
565
|
-
```
|
package/helpers.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type FieldConfig,
|
|
1
|
+
import { type FieldConfig, type Primitive, VALIDATION_UNDEFINED, VALIDATION_SKIPPED, INTENT } from '@conform-to/dom';
|
|
2
2
|
import type { CSSProperties, HTMLInputTypeAttribute } from 'react';
|
|
3
|
-
interface
|
|
3
|
+
interface FormControlProps {
|
|
4
4
|
id?: string;
|
|
5
5
|
name: string;
|
|
6
6
|
form?: string;
|
|
@@ -8,11 +8,11 @@ interface FieldProps {
|
|
|
8
8
|
autoFocus?: boolean;
|
|
9
9
|
tabIndex?: number;
|
|
10
10
|
style?: CSSProperties;
|
|
11
|
-
'aria-invalid': boolean;
|
|
12
11
|
'aria-describedby'?: string;
|
|
12
|
+
'aria-invalid'?: boolean;
|
|
13
13
|
'aria-hidden'?: boolean;
|
|
14
14
|
}
|
|
15
|
-
interface InputProps<Schema> extends
|
|
15
|
+
interface InputProps<Schema> extends FormControlProps {
|
|
16
16
|
type?: HTMLInputTypeAttribute;
|
|
17
17
|
minLength?: number;
|
|
18
18
|
maxLength?: number;
|
|
@@ -25,33 +25,30 @@ interface InputProps<Schema> extends FieldProps {
|
|
|
25
25
|
defaultChecked?: boolean;
|
|
26
26
|
defaultValue?: string;
|
|
27
27
|
}
|
|
28
|
-
interface SelectProps extends
|
|
28
|
+
interface SelectProps extends FormControlProps {
|
|
29
29
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
30
30
|
multiple?: boolean;
|
|
31
31
|
}
|
|
32
|
-
interface TextareaProps extends
|
|
32
|
+
interface TextareaProps extends FormControlProps {
|
|
33
33
|
minLength?: number;
|
|
34
34
|
maxLength?: number;
|
|
35
35
|
defaultValue?: string;
|
|
36
36
|
}
|
|
37
|
-
type
|
|
38
|
-
|
|
37
|
+
type BaseOptions = {
|
|
38
|
+
description?: boolean;
|
|
39
39
|
hidden?: boolean;
|
|
40
|
+
};
|
|
41
|
+
type InputOptions = BaseOptions & ({
|
|
42
|
+
type: 'checkbox' | 'radio';
|
|
40
43
|
value?: string;
|
|
41
44
|
} | {
|
|
42
45
|
type?: Exclude<HTMLInputTypeAttribute, 'button' | 'submit' | 'hidden'>;
|
|
43
|
-
hidden?: boolean;
|
|
44
46
|
value?: never;
|
|
45
|
-
};
|
|
46
|
-
export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: {
|
|
47
|
+
});
|
|
48
|
+
export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: InputOptions & {
|
|
47
49
|
type: 'file';
|
|
48
50
|
}): InputProps<Schema>;
|
|
49
|
-
export declare function input<Schema extends
|
|
50
|
-
export declare function select
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
export declare function textarea<Schema>(config: FieldConfig<Schema>, options?: {
|
|
54
|
-
hidden?: boolean;
|
|
55
|
-
}): TextareaProps;
|
|
56
|
-
export declare const intent = "__intent__";
|
|
57
|
-
export { VALIDATION_UNDEFINED, VALIDATION_SKIPPED };
|
|
51
|
+
export declare function input<Schema extends Primitive>(config: FieldConfig<Schema>, options?: InputOptions): InputProps<Schema>;
|
|
52
|
+
export declare function select(config: FieldConfig<Primitive | Primitive[]>, options?: BaseOptions): SelectProps;
|
|
53
|
+
export declare function textarea(config: FieldConfig<Primitive>, options?: BaseOptions): TextareaProps;
|
|
54
|
+
export { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED };
|