@conform-to/react 0.4.0-pre.1 → 0.4.0-pre.3
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 +156 -111
- package/hooks.d.ts +23 -26
- package/hooks.js +63 -40
- package/index.d.ts +1 -1
- package/index.js +4 -8
- package/module/hooks.js +64 -41
- package/module/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
- [useFieldset](#usefieldset)
|
|
11
11
|
- [useFieldList](#usefieldlist)
|
|
12
12
|
- [useControlledInput](#usecontrolledinput)
|
|
13
|
-
- [createValidate](#createvalidate)
|
|
14
13
|
- [conform](#conform)
|
|
14
|
+
- [getFormElements](#getformelements)
|
|
15
|
+
- [hasError](#haserror)
|
|
16
|
+
- [parse](#parse)
|
|
17
|
+
- [shouldValidate](#shouldvalidate)
|
|
15
18
|
|
|
16
19
|
<!-- /aside -->
|
|
17
20
|
|
|
@@ -21,15 +24,23 @@ By default, the browser calls the [reportValidity()](https://developer.mozilla.o
|
|
|
21
24
|
|
|
22
25
|
This hook enhances the form validation behaviour in 3 parts:
|
|
23
26
|
|
|
24
|
-
1. It
|
|
25
|
-
2. It
|
|
27
|
+
1. It enhances form validation with custom rules by subscribing to different DOM events and reporting the errors only when it is configured to do so.
|
|
28
|
+
2. It unifies client and server validation in one place.
|
|
26
29
|
3. It exposes the state of each field in the form of [data attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*), such as `data-conform-touched`, allowing flexible styling across your form without the need to manipulate the class names.
|
|
27
30
|
|
|
28
31
|
```tsx
|
|
29
32
|
import { useForm } from '@conform-to/react';
|
|
30
33
|
|
|
31
34
|
function LoginForm() {
|
|
32
|
-
const
|
|
35
|
+
const form = useForm({
|
|
36
|
+
/**
|
|
37
|
+
* Validation mode.
|
|
38
|
+
* Support "client-only" or "server-validation".
|
|
39
|
+
*
|
|
40
|
+
* Default to `client-only`.
|
|
41
|
+
*/
|
|
42
|
+
mode: 'client-only',
|
|
43
|
+
|
|
33
44
|
/**
|
|
34
45
|
* Define when the error should be reported initially.
|
|
35
46
|
* Support "onSubmit", "onChange", "onBlur".
|
|
@@ -38,6 +49,16 @@ function LoginForm() {
|
|
|
38
49
|
*/
|
|
39
50
|
initialReport: 'onBlur',
|
|
40
51
|
|
|
52
|
+
/**
|
|
53
|
+
* An object representing the initial value of the form.
|
|
54
|
+
*/
|
|
55
|
+
defaultValue: undefined;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* An object describing the state from the last submission
|
|
59
|
+
*/
|
|
60
|
+
state: undefined;
|
|
61
|
+
|
|
41
62
|
/**
|
|
42
63
|
* Enable native validation before hydation.
|
|
43
64
|
*
|
|
@@ -54,43 +75,38 @@ function LoginForm() {
|
|
|
54
75
|
|
|
55
76
|
/**
|
|
56
77
|
* A function to be called when the form should be (re)validated.
|
|
78
|
+
* Only sync validation is supported
|
|
57
79
|
*/
|
|
58
|
-
|
|
80
|
+
onValidate({ form, formData, submission }) {
|
|
59
81
|
// ...
|
|
60
82
|
},
|
|
61
83
|
|
|
62
84
|
/**
|
|
63
85
|
* The submit event handler of the form.
|
|
64
86
|
*/
|
|
65
|
-
onSubmit(event) {
|
|
87
|
+
onSubmit(event, { form, formData, submission }) {
|
|
66
88
|
// ...
|
|
67
89
|
},
|
|
68
90
|
});
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
<form {...formProps}>
|
|
72
|
-
<input type="email" name="email" required />
|
|
73
|
-
<input type="password" name="password" required />
|
|
74
|
-
<button type="submit">Login</button>
|
|
75
|
-
</form>
|
|
76
|
-
);
|
|
92
|
+
// ...
|
|
77
93
|
}
|
|
78
94
|
```
|
|
79
95
|
|
|
80
96
|
<details>
|
|
81
|
-
<summary>What is `
|
|
97
|
+
<summary>What is `form.props`?</summary>
|
|
82
98
|
|
|
83
99
|
It is a group of properties properties required to hook into form events. They can also be set explicitly as shown below:
|
|
84
100
|
|
|
85
101
|
```tsx
|
|
86
102
|
function RandomForm() {
|
|
87
|
-
const
|
|
103
|
+
const form = useForm();
|
|
88
104
|
|
|
89
105
|
return (
|
|
90
106
|
<form
|
|
91
|
-
ref={
|
|
92
|
-
onSubmit={
|
|
93
|
-
noValidate={
|
|
107
|
+
ref={form.props.ref}
|
|
108
|
+
onSubmit={form.props.onSubmit}
|
|
109
|
+
noValidate={form.props.noValidate}
|
|
94
110
|
>
|
|
95
111
|
{/* ... */}
|
|
96
112
|
</form>
|
|
@@ -103,17 +119,17 @@ function RandomForm() {
|
|
|
103
119
|
<details>
|
|
104
120
|
<summary>Does it work with custom form component like Remix Form?</summary>
|
|
105
121
|
|
|
106
|
-
Yes! It will fallback to native form submission
|
|
122
|
+
Yes! It will fallback to native form submission as long as the submit event is not default prevented.
|
|
107
123
|
|
|
108
124
|
```tsx
|
|
109
125
|
import { useFrom } from '@conform-to/react';
|
|
110
126
|
import { Form } from '@remix-run/react';
|
|
111
127
|
|
|
112
128
|
function LoginForm() {
|
|
113
|
-
const
|
|
129
|
+
const form = useForm();
|
|
114
130
|
|
|
115
131
|
return (
|
|
116
|
-
<Form method="post" action="/login" {...
|
|
132
|
+
<Form method="post" action="/login" {...form.props}>
|
|
117
133
|
{/* ... */}
|
|
118
134
|
</Form>
|
|
119
135
|
);
|
|
@@ -123,9 +139,9 @@ function LoginForm() {
|
|
|
123
139
|
</details>
|
|
124
140
|
|
|
125
141
|
<details>
|
|
126
|
-
<summary>Is the `
|
|
142
|
+
<summary>Is the `onValidate` function required?</summary>
|
|
127
143
|
|
|
128
|
-
The `
|
|
144
|
+
The `onValidate` function is not required if the validation logic can be fully covered by the [native constraints](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation#validation-related_attributes), e.g. **required** / **min** / **pattern** etc.
|
|
129
145
|
|
|
130
146
|
```tsx
|
|
131
147
|
import { useForm, useFieldset } from '@conform-to/react';
|
|
@@ -156,10 +172,10 @@ function LoginForm() {
|
|
|
156
172
|
|
|
157
173
|
### useFieldset
|
|
158
174
|
|
|
159
|
-
This hook can be used to monitor the state of each field and help
|
|
175
|
+
This hook can be used to monitor the state of each field and help configuration. It lets you:
|
|
160
176
|
|
|
161
177
|
1. Capturing errors at the form/fieldset level, removing the need to setup invalid handler on each field.
|
|
162
|
-
2. Defining config in one central place. e.g. name, default value and constraint, then distributing it to each field
|
|
178
|
+
2. Defining config in one central place. e.g. name, default value and constraint, then distributing it to each field with the [conform](#conform) helpers.
|
|
163
179
|
|
|
164
180
|
```tsx
|
|
165
181
|
import { useForm, useFieldset } from '@conform-to/react';
|
|
@@ -278,33 +294,6 @@ function Fieldset() {
|
|
|
278
294
|
}
|
|
279
295
|
```
|
|
280
296
|
|
|
281
|
-
<details>
|
|
282
|
-
<summary>Is it required to provide the FieldsetConfig to `useFieldset`?</summary>
|
|
283
|
-
|
|
284
|
-
No. The only thing required is the ref object. All the config is optional. You can always pass them to each fields manually.
|
|
285
|
-
|
|
286
|
-
```tsx
|
|
287
|
-
import { useForm, useFieldset } from '@conform-to/react';
|
|
288
|
-
|
|
289
|
-
function SubscriptionForm() {
|
|
290
|
-
const formProps = useForm();
|
|
291
|
-
const { email } = useFieldset(formProps.ref);
|
|
292
|
-
|
|
293
|
-
return (
|
|
294
|
-
<form {...formProps}>
|
|
295
|
-
<input
|
|
296
|
-
type="email"
|
|
297
|
-
name={email.config.name}
|
|
298
|
-
defaultValue="support@conform.dev"
|
|
299
|
-
required
|
|
300
|
-
/>
|
|
301
|
-
</form>
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
</details>
|
|
307
|
-
|
|
308
297
|
<details>
|
|
309
298
|
<summary>Why does `useFieldset` require a ref object of the form or fieldset?</summary>
|
|
310
299
|
|
|
@@ -335,7 +324,7 @@ function ExampleForm() {
|
|
|
335
324
|
|
|
336
325
|
### useFieldList
|
|
337
326
|
|
|
338
|
-
It returns a list of key and config, with
|
|
327
|
+
It returns a list of key and config, with helpers to configure command buttons with [list command](/docs/submission.md#list-command).
|
|
339
328
|
|
|
340
329
|
```tsx
|
|
341
330
|
import { useFieldset, useFieldList } from '@conform-to/react';
|
|
@@ -356,7 +345,7 @@ type Collection = {
|
|
|
356
345
|
function CollectionFieldset() {
|
|
357
346
|
const ref = useRef();
|
|
358
347
|
const { books } = useFieldset<Collection>(ref);
|
|
359
|
-
const [bookList,
|
|
348
|
+
const [bookList, command] = useFieldList(ref, books.config);
|
|
360
349
|
|
|
361
350
|
return (
|
|
362
351
|
<fieldset ref={ref}>
|
|
@@ -373,12 +362,12 @@ function CollectionFieldset() {
|
|
|
373
362
|
/>
|
|
374
363
|
|
|
375
364
|
{/* To setup a delete button */}
|
|
376
|
-
<button {...
|
|
365
|
+
<button {...command.remove({ index })}>Delete</button>
|
|
377
366
|
</div>
|
|
378
367
|
))}
|
|
379
368
|
|
|
380
369
|
{/* To setup a button that can append a new row with optional default value */}
|
|
381
|
-
<button {...
|
|
370
|
+
<button {...command.append({ defaultValue: { name: '', isbn: '' } })}>
|
|
382
371
|
add
|
|
383
372
|
</button>
|
|
384
373
|
</fieldset>
|
|
@@ -395,7 +384,7 @@ import { useRef } from 'react';
|
|
|
395
384
|
function CollectionFieldset() {
|
|
396
385
|
const ref = useRef();
|
|
397
386
|
const { books } = useFieldset<Collection>(ref);
|
|
398
|
-
const [bookList,
|
|
387
|
+
const [bookList, command] = useFieldList(ref, books.config);
|
|
399
388
|
|
|
400
389
|
return (
|
|
401
390
|
<fieldset ref={ref}>
|
|
@@ -405,12 +394,12 @@ function CollectionFieldset() {
|
|
|
405
394
|
<BookFieldset {...book.config} />
|
|
406
395
|
|
|
407
396
|
{/* To setup a delete button */}
|
|
408
|
-
<button {...
|
|
397
|
+
<button {...command.remove({ index })}>Delete</button>
|
|
409
398
|
</div>
|
|
410
399
|
))}
|
|
411
400
|
|
|
412
401
|
{/* To setup a button that can append a new row */}
|
|
413
|
-
<button {...
|
|
402
|
+
<button {...command.append()}>add</button>
|
|
414
403
|
</fieldset>
|
|
415
404
|
);
|
|
416
405
|
}
|
|
@@ -493,58 +482,7 @@ function MuiForm() {
|
|
|
493
482
|
<MenuItem value="c">Category C</MenuItem>
|
|
494
483
|
</TextField>
|
|
495
484
|
</fieldset>
|
|
496
|
-
)
|
|
497
|
-
}
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
---
|
|
501
|
-
|
|
502
|
-
### createValidate
|
|
503
|
-
|
|
504
|
-
This help you configure a validate function to check the validity of each fields and setup custom messages using the Constraint Validation APIs.
|
|
505
|
-
|
|
506
|
-
```tsx
|
|
507
|
-
import { useForm, createValidate } from '@conform-to/react';
|
|
508
|
-
|
|
509
|
-
export default function SignupForm() {
|
|
510
|
-
const formProps = useForm({
|
|
511
|
-
validate: createValidate((field, formData) => {
|
|
512
|
-
switch (field.name) {
|
|
513
|
-
case 'email':
|
|
514
|
-
if (field.validity.valueMissing) {
|
|
515
|
-
field.setCustomValidity('Email is required');
|
|
516
|
-
} else if (field.validity.typeMismatch) {
|
|
517
|
-
field.setCustomValidity('Please enter a valid email');
|
|
518
|
-
} else {
|
|
519
|
-
field.setCustomValidity('');
|
|
520
|
-
}
|
|
521
|
-
break;
|
|
522
|
-
case 'password':
|
|
523
|
-
if (field.validity.valueMissing) {
|
|
524
|
-
field.setCustomValidity('Password is required');
|
|
525
|
-
} else if (field.validity.tooShort) {
|
|
526
|
-
field.setCustomValidity(
|
|
527
|
-
'The password should be at least 10 characters long',
|
|
528
|
-
);
|
|
529
|
-
} else {
|
|
530
|
-
field.setCustomValidity('');
|
|
531
|
-
}
|
|
532
|
-
break;
|
|
533
|
-
case 'confirm-password': {
|
|
534
|
-
if (field.validity.valueMissing) {
|
|
535
|
-
field.setCustomValidity('Confirm Password is required');
|
|
536
|
-
} else if (field.value !== formData.get('password')) {
|
|
537
|
-
field.setCustomValidity('The password does not match');
|
|
538
|
-
} else {
|
|
539
|
-
field.setCustomValidity('');
|
|
540
|
-
}
|
|
541
|
-
break;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}),
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
return <form {...formProps}>{/* ... */}</form>;
|
|
485
|
+
);
|
|
548
486
|
}
|
|
549
487
|
```
|
|
550
488
|
|
|
@@ -615,3 +553,110 @@ function RandomForm() {
|
|
|
615
553
|
);
|
|
616
554
|
}
|
|
617
555
|
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
### getFormElements
|
|
560
|
+
|
|
561
|
+
It returns all _input_ / _select_ / _textarea_ or _button_ in the forms. Useful when looping through the form elements to validate each field.
|
|
562
|
+
|
|
563
|
+
```tsx
|
|
564
|
+
import { useForm, parse, getFormElements } from '@conform-to/react';
|
|
565
|
+
|
|
566
|
+
export default function LoginForm() {
|
|
567
|
+
const form = useForm({
|
|
568
|
+
onValidate({ form, formData }) {
|
|
569
|
+
const submission = parse(formData);
|
|
570
|
+
|
|
571
|
+
for (const element of getFormElements(form)) {
|
|
572
|
+
switch (element.name) {
|
|
573
|
+
case 'email': {
|
|
574
|
+
if (element.validity.valueMissing) {
|
|
575
|
+
submission.error.push([element.name, 'Email is required']);
|
|
576
|
+
} else if (element.validity.typeMismatch) {
|
|
577
|
+
submission.error.push([element.name, 'Email is invalid']);
|
|
578
|
+
}
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
case 'password': {
|
|
582
|
+
if (element.validity.valueMissing) {
|
|
583
|
+
submission.error.push([element.name, 'Password is required']);
|
|
584
|
+
}
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return submission;
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
// ....
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// ...
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
### hasError
|
|
603
|
+
|
|
604
|
+
This helper checks if there is any message defined in error array with the provided name.
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
import { hasError } from '@conform-to/react';
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Assume the error looks like this:
|
|
611
|
+
*/
|
|
612
|
+
const error = [['email', 'Email is required']];
|
|
613
|
+
|
|
614
|
+
// This will log `true`
|
|
615
|
+
console.log(hasError(error, 'email'));
|
|
616
|
+
|
|
617
|
+
// This will log `false`
|
|
618
|
+
console.log(hasError(error, 'password'));
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
### parse
|
|
624
|
+
|
|
625
|
+
It parses the formData based on the [naming convention](/docs/submission).
|
|
626
|
+
|
|
627
|
+
```tsx
|
|
628
|
+
import { parse } from '@conform-to/react';
|
|
629
|
+
|
|
630
|
+
const formData = new FormData();
|
|
631
|
+
const submission = parse(formData);
|
|
632
|
+
|
|
633
|
+
console.log(submission);
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
### shouldValidate
|
|
639
|
+
|
|
640
|
+
This helper checks if the scope of validation includes a specific field by checking the submission:
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
import { shouldValidate } from '@conform-to/react';
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* The submission type and intent give us hint on what should be valdiated.
|
|
647
|
+
* If the type is 'validate', only the field with name matching the metadata must be validated.
|
|
648
|
+
* If the type is 'submit', everything should be validated (Default submission)
|
|
649
|
+
*/
|
|
650
|
+
const submission = {
|
|
651
|
+
context: 'validate',
|
|
652
|
+
intent: 'email',
|
|
653
|
+
value: {},
|
|
654
|
+
error: [],
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
// This will log 'true'
|
|
658
|
+
console.log(shouldValidate(submission, 'email'));
|
|
659
|
+
|
|
660
|
+
// This will log 'false'
|
|
661
|
+
console.log(shouldValidate(submission, 'password'));
|
|
662
|
+
```
|
package/hooks.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type ListCommand, type Primitive, type Submission } from '@conform-to/dom';
|
|
2
2
|
import { type InputHTMLAttributes, type FormEvent, type RefObject } from 'react';
|
|
3
|
-
interface FormContext<Schema extends Record<string, any>> {
|
|
4
|
-
form: HTMLFormElement;
|
|
5
|
-
formData: FormData;
|
|
6
|
-
submission: Submission<Schema>;
|
|
7
|
-
}
|
|
8
3
|
export interface FormConfig<Schema extends Record<string, any>> {
|
|
9
4
|
/**
|
|
10
5
|
* Validation mode. Default to `client-only`.
|
|
@@ -40,12 +35,18 @@ export interface FormConfig<Schema extends Record<string, any>> {
|
|
|
40
35
|
/**
|
|
41
36
|
* A function to be called when the form should be (re)validated.
|
|
42
37
|
*/
|
|
43
|
-
onValidate?: (
|
|
38
|
+
onValidate?: ({ form, formData, }: {
|
|
39
|
+
form: HTMLFormElement;
|
|
40
|
+
formData: FormData;
|
|
41
|
+
}) => Submission<Schema>;
|
|
44
42
|
/**
|
|
45
43
|
* The submit event handler of the form. It will be called
|
|
46
44
|
* only when the form is considered valid.
|
|
47
45
|
*/
|
|
48
|
-
onSubmit?: (event: FormEvent<HTMLFormElement>, context:
|
|
46
|
+
onSubmit?: (event: FormEvent<HTMLFormElement>, context: {
|
|
47
|
+
formData: FormData;
|
|
48
|
+
submission: Submission<Schema>;
|
|
49
|
+
}) => void;
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
52
|
* Properties to be applied to the form element
|
|
@@ -65,7 +66,7 @@ interface Form<Schema extends Record<string, any>> {
|
|
|
65
66
|
* Returns properties required to hook into form events.
|
|
66
67
|
* Applied custom validation and define when error should be reported.
|
|
67
68
|
*
|
|
68
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
69
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform
|
|
69
70
|
*/
|
|
70
71
|
export declare function useForm<Schema extends Record<string, any>>(config?: FormConfig<Schema>): Form<Schema>;
|
|
71
72
|
/**
|
|
@@ -106,41 +107,37 @@ export interface FieldsetConfig<Schema extends Record<string, any>> {
|
|
|
106
107
|
/**
|
|
107
108
|
* Returns all the information about the fieldset.
|
|
108
109
|
*
|
|
109
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
110
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldset
|
|
110
111
|
*/
|
|
111
|
-
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config
|
|
112
|
-
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config
|
|
113
|
-
interface
|
|
112
|
+
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldsetConfig<Schema>): Fieldset<Schema>;
|
|
113
|
+
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Schema>): Fieldset<Schema>;
|
|
114
|
+
interface CommandButtonProps {
|
|
114
115
|
name?: string;
|
|
115
116
|
value?: string;
|
|
116
117
|
form?: string;
|
|
117
118
|
formNoValidate: true;
|
|
118
119
|
}
|
|
119
|
-
declare type
|
|
120
|
+
declare type ListCommandPayload<Schema, Type extends ListCommand<FieldValue<Schema>>['type']> = Extract<ListCommand<FieldValue<Schema>>, {
|
|
120
121
|
type: Type;
|
|
121
122
|
}>['payload'];
|
|
122
|
-
/**
|
|
123
|
-
* A group of helpers for configuring a list control button
|
|
124
|
-
*/
|
|
125
|
-
interface ListControl<Schema> {
|
|
126
|
-
prepend(payload?: CommandPayload<Schema, 'prepend'>): ControlButtonProps;
|
|
127
|
-
append(payload?: CommandPayload<Schema, 'append'>): ControlButtonProps;
|
|
128
|
-
replace(payload: CommandPayload<Schema, 'replace'>): ControlButtonProps;
|
|
129
|
-
remove(payload: CommandPayload<Schema, 'remove'>): ControlButtonProps;
|
|
130
|
-
reorder(payload: CommandPayload<Schema, 'reorder'>): ControlButtonProps;
|
|
131
|
-
}
|
|
132
123
|
/**
|
|
133
124
|
* Returns a list of key and config, with a group of helpers
|
|
134
125
|
* configuring buttons for list manipulation
|
|
135
126
|
*
|
|
136
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
127
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist
|
|
137
128
|
*/
|
|
138
129
|
export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Array<Payload>>): [
|
|
139
130
|
Array<{
|
|
140
131
|
key: string;
|
|
141
132
|
config: FieldConfig<Payload>;
|
|
142
133
|
}>,
|
|
143
|
-
|
|
134
|
+
{
|
|
135
|
+
prepend(payload?: ListCommandPayload<Payload, 'prepend'>): CommandButtonProps;
|
|
136
|
+
append(payload?: ListCommandPayload<Payload, 'append'>): CommandButtonProps;
|
|
137
|
+
replace(payload: ListCommandPayload<Payload, 'replace'>): CommandButtonProps;
|
|
138
|
+
remove(payload: ListCommandPayload<Payload, 'remove'>): CommandButtonProps;
|
|
139
|
+
reorder(payload: ListCommandPayload<Payload, 'reorder'>): CommandButtonProps;
|
|
140
|
+
}
|
|
144
141
|
];
|
|
145
142
|
interface ShadowInputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
146
143
|
ref: RefObject<HTMLInputElement>;
|
|
@@ -163,7 +160,7 @@ interface InputControl<Element extends {
|
|
|
163
160
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
164
161
|
* introduces custom input mode.
|
|
165
162
|
*
|
|
166
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
163
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput
|
|
167
164
|
*/
|
|
168
165
|
export declare function useControlledInput<Element extends {
|
|
169
166
|
focus: () => void;
|
package/hooks.js
CHANGED
|
@@ -11,7 +11,7 @@ var helpers = require('./helpers.js');
|
|
|
11
11
|
* Returns properties required to hook into form events.
|
|
12
12
|
* Applied custom validation and define when error should be reported.
|
|
13
13
|
*
|
|
14
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
14
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform
|
|
15
15
|
*/
|
|
16
16
|
function useForm() {
|
|
17
17
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -182,48 +182,70 @@ function useForm() {
|
|
|
182
182
|
return;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
var formData = dom.getFormData(form, submitter);
|
|
186
|
-
var submission = dom.parse(formData);
|
|
187
|
-
var context = {
|
|
188
|
-
form,
|
|
189
|
-
formData,
|
|
190
|
-
submission
|
|
191
|
-
}; // Touch all fields only if the submitter is not a command button
|
|
192
|
-
|
|
193
|
-
if (!submission.type) {
|
|
194
|
-
for (var field of form.elements) {
|
|
195
|
-
if (dom.isFieldElement(field)) {
|
|
196
|
-
// Mark the field as touched
|
|
197
|
-
field.dataset.conformTouched = 'true';
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
185
|
try {
|
|
203
|
-
|
|
204
|
-
|
|
186
|
+
var submission;
|
|
187
|
+
var formData = dom.getFormData(form, submitter);
|
|
205
188
|
|
|
206
|
-
|
|
189
|
+
if (typeof config.onValidate === 'function') {
|
|
190
|
+
submission = config.onValidate({
|
|
191
|
+
form,
|
|
192
|
+
formData
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
submission = dom.parse(formData);
|
|
196
|
+
|
|
197
|
+
if (config.mode !== 'server-validation') {
|
|
198
|
+
/**
|
|
199
|
+
* As there is no custom logic defined,
|
|
200
|
+
* removing the custom validity state will allow us
|
|
201
|
+
* finding the latest validation message.
|
|
202
|
+
*
|
|
203
|
+
* This is mainly used to showcase the constraint validation API.
|
|
204
|
+
*/
|
|
205
|
+
dom.setFormError(form, {
|
|
206
|
+
type: 'submit',
|
|
207
|
+
value: {},
|
|
208
|
+
error: []
|
|
209
|
+
});
|
|
207
210
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
for (var _element of form.elements) {
|
|
212
|
+
if (dom.isFieldElement(_element) && _element.willValidate) {
|
|
213
|
+
submission.error.push([_element.name, _element.validationMessage]);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} // Touch all fields only if the submitter is not a command button
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if (submission.type === 'submit') {
|
|
221
|
+
for (var field of form.elements) {
|
|
222
|
+
if (dom.isFieldElement(field)) {
|
|
223
|
+
// Mark the field as touched
|
|
224
|
+
field.dataset.conformTouched = 'true';
|
|
225
|
+
}
|
|
211
226
|
}
|
|
212
227
|
}
|
|
213
|
-
} catch (e) {
|
|
214
|
-
if (e !== form) {
|
|
215
|
-
console.warn(e);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
if (config.mode !== 'server-validation' && submission.type === 'validate') {
|
|
229
|
+
if (!config.noValidate && !submitter.formNoValidate && dom.hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') {
|
|
221
230
|
event.preventDefault();
|
|
222
231
|
} else {
|
|
223
232
|
var _config$onSubmit;
|
|
224
233
|
|
|
225
|
-
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event,
|
|
234
|
+
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, {
|
|
235
|
+
formData,
|
|
236
|
+
submission
|
|
237
|
+
});
|
|
226
238
|
}
|
|
239
|
+
|
|
240
|
+
if (event.defaultPrevented) {
|
|
241
|
+
dom.setFormError(form, submission);
|
|
242
|
+
|
|
243
|
+
if (!form.reportValidity()) {
|
|
244
|
+
dom.focusFirstInvalidField(form);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} catch (e) {
|
|
248
|
+
console.warn(e);
|
|
227
249
|
}
|
|
228
250
|
}
|
|
229
251
|
|
|
@@ -287,11 +309,11 @@ function useFieldset(ref, config) {
|
|
|
287
309
|
});
|
|
288
310
|
react.useEffect(() => {
|
|
289
311
|
var invalidHandler = event => {
|
|
290
|
-
var _configRef$current$na
|
|
312
|
+
var _configRef$current$na;
|
|
291
313
|
|
|
292
314
|
var form = dom.getFormElement(ref.current);
|
|
293
315
|
var field = event.target;
|
|
294
|
-
var fieldsetName = (_configRef$current$na =
|
|
316
|
+
var fieldsetName = (_configRef$current$na = configRef.current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : '';
|
|
295
317
|
|
|
296
318
|
if (!form || !dom.isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
|
|
297
319
|
return;
|
|
@@ -335,10 +357,10 @@ function useFieldset(ref, config) {
|
|
|
335
357
|
|
|
336
358
|
|
|
337
359
|
setError(prev => {
|
|
338
|
-
var _configRef$current$na2
|
|
360
|
+
var _configRef$current$na2;
|
|
339
361
|
|
|
340
362
|
var next = prev;
|
|
341
|
-
var fieldsetName = (_configRef$current$na2 =
|
|
363
|
+
var fieldsetName = (_configRef$current$na2 = configRef.current.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : '';
|
|
342
364
|
|
|
343
365
|
for (var field of form.elements) {
|
|
344
366
|
if (dom.isFieldElement(field) && field.name.startsWith(fieldsetName)) {
|
|
@@ -423,7 +445,7 @@ function useFieldset(ref, config) {
|
|
|
423
445
|
* Returns a list of key and config, with a group of helpers
|
|
424
446
|
* configuring buttons for list manipulation
|
|
425
447
|
*
|
|
426
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
448
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist
|
|
427
449
|
*/
|
|
428
450
|
function useFieldList(ref, config) {
|
|
429
451
|
var configRef = react.useRef(config);
|
|
@@ -479,7 +501,7 @@ function useFieldList(ref, config) {
|
|
|
479
501
|
* have it encoded in the value.
|
|
480
502
|
*/
|
|
481
503
|
|
|
482
|
-
var
|
|
504
|
+
var command = new Proxy({}, {
|
|
483
505
|
get(_target, type) {
|
|
484
506
|
return function () {
|
|
485
507
|
var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -559,7 +581,8 @@ function useFieldList(ref, config) {
|
|
|
559
581
|
document.removeEventListener('reset', resetHandler);
|
|
560
582
|
};
|
|
561
583
|
}, [ref]);
|
|
562
|
-
return [list,
|
|
584
|
+
return [list, // @ts-expect-error proxy type
|
|
585
|
+
command];
|
|
563
586
|
}
|
|
564
587
|
|
|
565
588
|
/**
|
|
@@ -567,7 +590,7 @@ function useFieldList(ref, config) {
|
|
|
567
590
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
568
591
|
* introduces custom input mode.
|
|
569
592
|
*
|
|
570
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
593
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput
|
|
571
594
|
*/
|
|
572
595
|
function useControlledInput(config) {
|
|
573
596
|
var _config$defaultValue4;
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { type FieldsetConstraint, type Submission,
|
|
1
|
+
export { type FieldsetConstraint, type Submission, getFormElements, hasError, parse, shouldValidate, } from '@conform-to/dom';
|
|
2
2
|
export * from './hooks';
|
|
3
3
|
export * as conform from './helpers';
|
package/index.js
CHANGED
|
@@ -8,22 +8,18 @@ var helpers = require('./helpers.js');
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
Object.defineProperty(exports, '
|
|
11
|
+
Object.defineProperty(exports, 'getFormElements', {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return dom.
|
|
13
|
+
get: function () { return dom.getFormElements; }
|
|
14
14
|
});
|
|
15
|
-
Object.defineProperty(exports, '
|
|
15
|
+
Object.defineProperty(exports, 'hasError', {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return dom.
|
|
17
|
+
get: function () { return dom.hasError; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, 'parse', {
|
|
20
20
|
enumerable: true,
|
|
21
21
|
get: function () { return dom.parse; }
|
|
22
22
|
});
|
|
23
|
-
Object.defineProperty(exports, 'setFormError', {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
get: function () { return dom.setFormError; }
|
|
26
|
-
});
|
|
27
23
|
Object.defineProperty(exports, 'shouldValidate', {
|
|
28
24
|
enumerable: true,
|
|
29
25
|
get: function () { return dom.shouldValidate; }
|
package/module/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
-
import { getSubmissionType, setFormError, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom';
|
|
2
|
+
import { getSubmissionType, setFormError, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, hasError, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom';
|
|
3
3
|
import { useRef, useState, useEffect } from 'react';
|
|
4
4
|
import { input } from './helpers.js';
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ import { input } from './helpers.js';
|
|
|
7
7
|
* Returns properties required to hook into form events.
|
|
8
8
|
* Applied custom validation and define when error should be reported.
|
|
9
9
|
*
|
|
10
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
10
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform
|
|
11
11
|
*/
|
|
12
12
|
function useForm() {
|
|
13
13
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -178,48 +178,70 @@ function useForm() {
|
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
var formData = getFormData(form, submitter);
|
|
182
|
-
var submission = parse(formData);
|
|
183
|
-
var context = {
|
|
184
|
-
form,
|
|
185
|
-
formData,
|
|
186
|
-
submission
|
|
187
|
-
}; // Touch all fields only if the submitter is not a command button
|
|
188
|
-
|
|
189
|
-
if (!submission.type) {
|
|
190
|
-
for (var field of form.elements) {
|
|
191
|
-
if (isFieldElement(field)) {
|
|
192
|
-
// Mark the field as touched
|
|
193
|
-
field.dataset.conformTouched = 'true';
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
181
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
182
|
+
var submission;
|
|
183
|
+
var formData = getFormData(form, submitter);
|
|
201
184
|
|
|
202
|
-
|
|
185
|
+
if (typeof config.onValidate === 'function') {
|
|
186
|
+
submission = config.onValidate({
|
|
187
|
+
form,
|
|
188
|
+
formData
|
|
189
|
+
});
|
|
190
|
+
} else {
|
|
191
|
+
submission = parse(formData);
|
|
192
|
+
|
|
193
|
+
if (config.mode !== 'server-validation') {
|
|
194
|
+
/**
|
|
195
|
+
* As there is no custom logic defined,
|
|
196
|
+
* removing the custom validity state will allow us
|
|
197
|
+
* finding the latest validation message.
|
|
198
|
+
*
|
|
199
|
+
* This is mainly used to showcase the constraint validation API.
|
|
200
|
+
*/
|
|
201
|
+
setFormError(form, {
|
|
202
|
+
type: 'submit',
|
|
203
|
+
value: {},
|
|
204
|
+
error: []
|
|
205
|
+
});
|
|
203
206
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
for (var _element of form.elements) {
|
|
208
|
+
if (isFieldElement(_element) && _element.willValidate) {
|
|
209
|
+
submission.error.push([_element.name, _element.validationMessage]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} // Touch all fields only if the submitter is not a command button
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
if (submission.type === 'submit') {
|
|
217
|
+
for (var field of form.elements) {
|
|
218
|
+
if (isFieldElement(field)) {
|
|
219
|
+
// Mark the field as touched
|
|
220
|
+
field.dataset.conformTouched = 'true';
|
|
221
|
+
}
|
|
207
222
|
}
|
|
208
223
|
}
|
|
209
|
-
} catch (e) {
|
|
210
|
-
if (e !== form) {
|
|
211
|
-
console.warn(e);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
224
|
|
|
215
|
-
|
|
216
|
-
if (config.mode !== 'server-validation' && submission.type === 'validate') {
|
|
225
|
+
if (!config.noValidate && !submitter.formNoValidate && hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') {
|
|
217
226
|
event.preventDefault();
|
|
218
227
|
} else {
|
|
219
228
|
var _config$onSubmit;
|
|
220
229
|
|
|
221
|
-
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event,
|
|
230
|
+
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, {
|
|
231
|
+
formData,
|
|
232
|
+
submission
|
|
233
|
+
});
|
|
222
234
|
}
|
|
235
|
+
|
|
236
|
+
if (event.defaultPrevented) {
|
|
237
|
+
setFormError(form, submission);
|
|
238
|
+
|
|
239
|
+
if (!form.reportValidity()) {
|
|
240
|
+
focusFirstInvalidField(form);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.warn(e);
|
|
223
245
|
}
|
|
224
246
|
}
|
|
225
247
|
|
|
@@ -283,11 +305,11 @@ function useFieldset(ref, config) {
|
|
|
283
305
|
});
|
|
284
306
|
useEffect(() => {
|
|
285
307
|
var invalidHandler = event => {
|
|
286
|
-
var _configRef$current$na
|
|
308
|
+
var _configRef$current$na;
|
|
287
309
|
|
|
288
310
|
var form = getFormElement(ref.current);
|
|
289
311
|
var field = event.target;
|
|
290
|
-
var fieldsetName = (_configRef$current$na =
|
|
312
|
+
var fieldsetName = (_configRef$current$na = configRef.current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : '';
|
|
291
313
|
|
|
292
314
|
if (!form || !isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
|
|
293
315
|
return;
|
|
@@ -331,10 +353,10 @@ function useFieldset(ref, config) {
|
|
|
331
353
|
|
|
332
354
|
|
|
333
355
|
setError(prev => {
|
|
334
|
-
var _configRef$current$na2
|
|
356
|
+
var _configRef$current$na2;
|
|
335
357
|
|
|
336
358
|
var next = prev;
|
|
337
|
-
var fieldsetName = (_configRef$current$na2 =
|
|
359
|
+
var fieldsetName = (_configRef$current$na2 = configRef.current.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : '';
|
|
338
360
|
|
|
339
361
|
for (var field of form.elements) {
|
|
340
362
|
if (isFieldElement(field) && field.name.startsWith(fieldsetName)) {
|
|
@@ -419,7 +441,7 @@ function useFieldset(ref, config) {
|
|
|
419
441
|
* Returns a list of key and config, with a group of helpers
|
|
420
442
|
* configuring buttons for list manipulation
|
|
421
443
|
*
|
|
422
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
444
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist
|
|
423
445
|
*/
|
|
424
446
|
function useFieldList(ref, config) {
|
|
425
447
|
var configRef = useRef(config);
|
|
@@ -475,7 +497,7 @@ function useFieldList(ref, config) {
|
|
|
475
497
|
* have it encoded in the value.
|
|
476
498
|
*/
|
|
477
499
|
|
|
478
|
-
var
|
|
500
|
+
var command = new Proxy({}, {
|
|
479
501
|
get(_target, type) {
|
|
480
502
|
return function () {
|
|
481
503
|
var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -555,7 +577,8 @@ function useFieldList(ref, config) {
|
|
|
555
577
|
document.removeEventListener('reset', resetHandler);
|
|
556
578
|
};
|
|
557
579
|
}, [ref]);
|
|
558
|
-
return [list,
|
|
580
|
+
return [list, // @ts-expect-error proxy type
|
|
581
|
+
command];
|
|
559
582
|
}
|
|
560
583
|
|
|
561
584
|
/**
|
|
@@ -563,7 +586,7 @@ function useFieldList(ref, config) {
|
|
|
563
586
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
564
587
|
* introduces custom input mode.
|
|
565
588
|
*
|
|
566
|
-
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.
|
|
589
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput
|
|
567
590
|
*/
|
|
568
591
|
function useControlledInput(config) {
|
|
569
592
|
var _config$defaultValue4;
|
package/module/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { getFormElements, hasError, parse, shouldValidate } from '@conform-to/dom';
|
|
2
2
|
export { useControlledInput, useFieldList, useFieldset, useForm } from './hooks.js';
|
|
3
3
|
import * as helpers from './helpers.js';
|
|
4
4
|
export { helpers as conform };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@conform-to/react",
|
|
3
3
|
"description": "Conform view adapter for react",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.4.0-pre.
|
|
5
|
+
"version": "0.4.0-pre.3",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "module/index.js",
|
|
8
8
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"url": "https://github.com/edmundhung/conform/issues"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@conform-to/dom": "0.4.0-pre.
|
|
22
|
+
"@conform-to/dom": "0.4.0-pre.3"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"react": ">=16.8"
|