@conform-to/react 0.3.0 → 0.3.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 +99 -48
- package/helpers.js +22 -4
- package/hooks.d.ts +11 -6
- package/hooks.js +36 -10
- package/module/helpers.js +22 -4
- package/module/hooks.js +36 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
> [React](https://github.com/facebook/react) adapter for [conform](https://github.com/edmundhung/conform)
|
|
4
4
|
|
|
5
|
+
<!-- aside -->
|
|
6
|
+
|
|
5
7
|
## API Reference
|
|
6
8
|
|
|
7
|
-
- [useForm](#
|
|
8
|
-
- [useFieldset](#
|
|
9
|
-
- [useFieldList](#
|
|
10
|
-
- [useControlledInput](#
|
|
9
|
+
- [useForm](#useform)
|
|
10
|
+
- [useFieldset](#usefieldset)
|
|
11
|
+
- [useFieldList](#usefieldlist)
|
|
12
|
+
- [useControlledInput](#usecontrolledinput)
|
|
13
|
+
- [createValidate](#createvalidate)
|
|
11
14
|
- [conform](#conform)
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
<!-- /aside -->
|
|
14
17
|
|
|
15
18
|
### useForm
|
|
16
19
|
|
|
@@ -219,31 +222,31 @@ function BookFieldset() {
|
|
|
219
222
|
* This would be 'Invalid ISBN' initially as specified
|
|
220
223
|
* in the initialError config
|
|
221
224
|
*/
|
|
222
|
-
console.log(
|
|
225
|
+
console.log(isbn.error);
|
|
223
226
|
|
|
224
227
|
/**
|
|
225
228
|
* This would be `book.isbn` instead of `isbn`
|
|
226
229
|
* if the `name` option is provided
|
|
227
230
|
*/
|
|
228
|
-
console.log(
|
|
231
|
+
console.log(isbn.config.name);
|
|
229
232
|
|
|
230
233
|
/**
|
|
231
234
|
* This would be `0340013818` if specified
|
|
232
235
|
* on the `initalValue` option
|
|
233
236
|
*/
|
|
234
|
-
console.log(
|
|
237
|
+
console.log(isbn.config.defaultValue);
|
|
235
238
|
|
|
236
239
|
/**
|
|
237
240
|
* Initial error message
|
|
238
241
|
* This would be 'Invalid ISBN' if specified
|
|
239
242
|
*/
|
|
240
|
-
console.log(
|
|
243
|
+
console.log(isbn.config.initialError);
|
|
241
244
|
|
|
242
245
|
/**
|
|
243
246
|
* This would be `random-form-id`
|
|
244
247
|
* because of the `form` option provided
|
|
245
248
|
*/
|
|
246
|
-
console.log(
|
|
249
|
+
console.log(isbn.config.form);
|
|
247
250
|
|
|
248
251
|
/**
|
|
249
252
|
* Constraint of the field (required, minLength etc)
|
|
@@ -254,8 +257,8 @@ function BookFieldset() {
|
|
|
254
257
|
* pattern: '[0-9]{10,13}'
|
|
255
258
|
* }
|
|
256
259
|
*/
|
|
257
|
-
console.log(
|
|
258
|
-
console.log(
|
|
260
|
+
console.log(isbn.config.required);
|
|
261
|
+
console.log(isbn.config.pattern);
|
|
259
262
|
|
|
260
263
|
return <form {...formProps}>{/* ... */}</form>;
|
|
261
264
|
}
|
|
@@ -353,7 +356,7 @@ type Collection = {
|
|
|
353
356
|
function CollectionFieldset() {
|
|
354
357
|
const ref = useRef();
|
|
355
358
|
const { books } = useFieldset<Collection>(ref);
|
|
356
|
-
const [bookList, control] = useFieldList(ref, books);
|
|
359
|
+
const [bookList, control] = useFieldList(ref, books.config);
|
|
357
360
|
|
|
358
361
|
return (
|
|
359
362
|
<fieldset ref={ref}>
|
|
@@ -392,14 +395,14 @@ import { useRef } from 'react';
|
|
|
392
395
|
function CollectionFieldset() {
|
|
393
396
|
const ref = useRef();
|
|
394
397
|
const { books } = useFieldset<Collection>(ref);
|
|
395
|
-
const [bookList, control] = useFieldList(ref, books);
|
|
398
|
+
const [bookList, control] = useFieldList(ref, books.config);
|
|
396
399
|
|
|
397
400
|
return (
|
|
398
401
|
<fieldset ref={ref}>
|
|
399
402
|
{bookList.map((book, index) => (
|
|
400
403
|
<div key={book.key}>
|
|
401
|
-
{/* `book.
|
|
402
|
-
<BookFieldset {...book.config}
|
|
404
|
+
{/* `book.config` is a FieldConfig object similar to `books` */}
|
|
405
|
+
<BookFieldset {...book.config} />
|
|
403
406
|
|
|
404
407
|
{/* To setup a delete button */}
|
|
405
408
|
<button {...control.remove({ index })}>Delete</button>
|
|
@@ -426,11 +429,7 @@ function BookFieldset({ name, form, defaultValue, error }) {
|
|
|
426
429
|
error,
|
|
427
430
|
});
|
|
428
431
|
|
|
429
|
-
return
|
|
430
|
-
<fieldset ref={ref}>
|
|
431
|
-
{/* ... */}
|
|
432
|
-
</fieldset>
|
|
433
|
-
);
|
|
432
|
+
return <fieldset ref={ref}>{/* ... */}</fieldset>;
|
|
434
433
|
}
|
|
435
434
|
```
|
|
436
435
|
|
|
@@ -470,7 +469,7 @@ import { useRef } from 'react';
|
|
|
470
469
|
function MuiForm() {
|
|
471
470
|
const ref = useRef();
|
|
472
471
|
const { category } = useFieldset(schema);
|
|
473
|
-
const [inputProps, control] = useControlledInput(category);
|
|
472
|
+
const [inputProps, control] = useControlledInput(category.config);
|
|
474
473
|
|
|
475
474
|
return (
|
|
476
475
|
<fieldset ref={ref}>
|
|
@@ -480,6 +479,7 @@ function MuiForm() {
|
|
|
480
479
|
{/* MUI Select is a controlled component */}
|
|
481
480
|
<Select
|
|
482
481
|
label="Category"
|
|
482
|
+
inputRef={control.ref}
|
|
483
483
|
value={control.value}
|
|
484
484
|
onChange={control.onChange}
|
|
485
485
|
onBlur={control.onBlur}
|
|
@@ -499,6 +499,57 @@ function MuiForm() {
|
|
|
499
499
|
|
|
500
500
|
---
|
|
501
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>;
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
502
553
|
### conform
|
|
503
554
|
|
|
504
555
|
It provides several helpers to configure a native input field quickly:
|
|
@@ -509,13 +560,13 @@ import { useRef } from 'react';
|
|
|
509
560
|
|
|
510
561
|
function RandomForm() {
|
|
511
562
|
const ref = useRef();
|
|
512
|
-
const {
|
|
563
|
+
const { category } = useFieldset(ref);
|
|
513
564
|
|
|
514
565
|
return (
|
|
515
566
|
<fieldset ref={ref}>
|
|
516
|
-
<input {...conform.input(
|
|
517
|
-
<textarea {...conform.textarea(
|
|
518
|
-
<select {...conform.select(
|
|
567
|
+
<input {...conform.input(category.config, { type: 'text' })} />
|
|
568
|
+
<textarea {...conform.textarea(category.config)} />
|
|
569
|
+
<select {...conform.select(category.config)}>{/* ... */}</select>
|
|
519
570
|
</fieldset>
|
|
520
571
|
);
|
|
521
572
|
}
|
|
@@ -526,37 +577,37 @@ This is equivalent to:
|
|
|
526
577
|
```tsx
|
|
527
578
|
function RandomForm() {
|
|
528
579
|
const ref = useRef();
|
|
529
|
-
const {
|
|
580
|
+
const { category } = useFieldset(ref);
|
|
530
581
|
|
|
531
582
|
return (
|
|
532
583
|
<fieldset ref={ref}>
|
|
533
584
|
<input
|
|
534
585
|
type="text"
|
|
535
|
-
name={
|
|
536
|
-
form={
|
|
537
|
-
defaultValue={
|
|
538
|
-
requried={
|
|
539
|
-
minLength={
|
|
540
|
-
maxLength={
|
|
541
|
-
min={
|
|
542
|
-
max={
|
|
543
|
-
multiple={
|
|
544
|
-
pattern={
|
|
586
|
+
name={category.config.name}
|
|
587
|
+
form={category.config.form}
|
|
588
|
+
defaultValue={category.config.defaultValue}
|
|
589
|
+
requried={category.config.required}
|
|
590
|
+
minLength={category.config.minLength}
|
|
591
|
+
maxLength={category.config.maxLength}
|
|
592
|
+
min={category.config.min}
|
|
593
|
+
max={category.config.max}
|
|
594
|
+
multiple={category.config.multiple}
|
|
595
|
+
pattern={category.config.pattern}
|
|
545
596
|
>
|
|
546
597
|
<textarea
|
|
547
|
-
name={
|
|
548
|
-
form={
|
|
549
|
-
defaultValue={
|
|
550
|
-
requried={
|
|
551
|
-
minLength={
|
|
552
|
-
maxLength={
|
|
598
|
+
name={category.config.name}
|
|
599
|
+
form={category.config.form}
|
|
600
|
+
defaultValue={category.config.defaultValue}
|
|
601
|
+
requried={category.config.required}
|
|
602
|
+
minLength={category.config.minLength}
|
|
603
|
+
maxLength={category.config.maxLength}
|
|
553
604
|
/>
|
|
554
605
|
<select
|
|
555
|
-
name={
|
|
556
|
-
form={
|
|
557
|
-
defaultValue={
|
|
558
|
-
requried={
|
|
559
|
-
multiple={
|
|
606
|
+
name={category.config.name}
|
|
607
|
+
form={category.config.form}
|
|
608
|
+
defaultValue={category.config.defaultValue}
|
|
609
|
+
requried={category.config.required}
|
|
610
|
+
multiple={category.config.multiple}
|
|
560
611
|
>
|
|
561
612
|
{/* ... */}
|
|
562
613
|
</select>
|
package/helpers.js
CHANGED
|
@@ -22,6 +22,10 @@ function input(config) {
|
|
|
22
22
|
multiple: config.multiple
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
if (typeof config.initialError !== 'undefined') {
|
|
26
|
+
attributes.autoFocus = true;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
if (isCheckboxOrRadio) {
|
|
26
30
|
attributes.value = value !== null && value !== void 0 ? value : 'on';
|
|
27
31
|
attributes.defaultChecked = config.defaultValue === attributes.value;
|
|
@@ -34,25 +38,39 @@ function input(config) {
|
|
|
34
38
|
function select(config) {
|
|
35
39
|
var _config$defaultValue;
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
var attributes = {
|
|
38
42
|
name: config.name,
|
|
39
43
|
form: config.form,
|
|
40
44
|
defaultValue: config.multiple ? Array.isArray(config.defaultValue) ? config.defaultValue : [] : "".concat((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : ''),
|
|
41
45
|
required: config.required,
|
|
42
|
-
multiple: config.multiple
|
|
46
|
+
multiple: config.multiple,
|
|
47
|
+
autoFocus: typeof config.initialError !== 'undefined' ? Boolean(config.initialError) : undefined
|
|
43
48
|
};
|
|
49
|
+
|
|
50
|
+
if (typeof config.initialError !== 'undefined') {
|
|
51
|
+
attributes.autoFocus = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return attributes;
|
|
44
55
|
}
|
|
45
56
|
function textarea(config) {
|
|
46
57
|
var _config$defaultValue2;
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
var attributes = {
|
|
49
60
|
name: config.name,
|
|
50
61
|
form: config.form,
|
|
51
62
|
defaultValue: "".concat((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : ''),
|
|
52
63
|
required: config.required,
|
|
53
64
|
minLength: config.minLength,
|
|
54
|
-
maxLength: config.maxLength
|
|
65
|
+
maxLength: config.maxLength,
|
|
66
|
+
autoFocus: Boolean(config.initialError)
|
|
55
67
|
};
|
|
68
|
+
|
|
69
|
+
if (typeof config.initialError !== 'undefined') {
|
|
70
|
+
attributes.autoFocus = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return attributes;
|
|
56
74
|
}
|
|
57
75
|
|
|
58
76
|
exports.input = input;
|
package/hooks.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface FormProps {
|
|
|
42
42
|
* Returns properties required to hook into form events.
|
|
43
43
|
* Applied custom validation and define when error should be reported.
|
|
44
44
|
*
|
|
45
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
45
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
|
|
46
46
|
*/
|
|
47
47
|
export declare function useForm(config?: FormConfig): FormProps;
|
|
48
48
|
/**
|
|
@@ -83,7 +83,7 @@ export interface FieldsetConfig<Schema extends Record<string, any>> {
|
|
|
83
83
|
/**
|
|
84
84
|
* Returns all the information about the fieldset.
|
|
85
85
|
*
|
|
86
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
86
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldset
|
|
87
87
|
*/
|
|
88
88
|
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config?: FieldsetConfig<Schema>): Fieldset<Schema>;
|
|
89
89
|
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config?: FieldConfig<Schema>): Fieldset<Schema>;
|
|
@@ -110,7 +110,7 @@ interface ListControl<Schema> {
|
|
|
110
110
|
* Returns a list of key and config, with a group of helpers
|
|
111
111
|
* configuring buttons for list manipulation
|
|
112
112
|
*
|
|
113
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
113
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
|
|
114
114
|
*/
|
|
115
115
|
export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Array<Payload>>): [
|
|
116
116
|
Array<{
|
|
@@ -122,7 +122,10 @@ export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormEleme
|
|
|
122
122
|
interface ShadowInputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
123
123
|
ref: RefObject<HTMLInputElement>;
|
|
124
124
|
}
|
|
125
|
-
interface InputControl {
|
|
125
|
+
interface InputControl<Element extends {
|
|
126
|
+
focus: () => void;
|
|
127
|
+
}> {
|
|
128
|
+
ref: RefObject<Element>;
|
|
126
129
|
value: string;
|
|
127
130
|
onChange: (eventOrValue: {
|
|
128
131
|
target: {
|
|
@@ -137,7 +140,9 @@ interface InputControl {
|
|
|
137
140
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
138
141
|
* introduces custom input mode.
|
|
139
142
|
*
|
|
140
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
143
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
|
|
141
144
|
*/
|
|
142
|
-
export declare function useControlledInput<
|
|
145
|
+
export declare function useControlledInput<Element extends {
|
|
146
|
+
focus: () => void;
|
|
147
|
+
} = HTMLInputElement, Schema extends Primitive = Primitive>(field: FieldConfig<Schema>): [ShadowInputProps, InputControl<Element>];
|
|
143
148
|
export {};
|
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.3.
|
|
14
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
|
|
15
15
|
*/
|
|
16
16
|
function useForm() {
|
|
17
17
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -125,10 +125,17 @@ function useForm() {
|
|
|
125
125
|
*/
|
|
126
126
|
|
|
127
127
|
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
|
|
128
|
-
|
|
128
|
+
var focused = false;
|
|
129
|
+
|
|
129
130
|
for (var field of form.elements) {
|
|
130
131
|
if (dom.isFieldElement(field)) {
|
|
131
|
-
field
|
|
132
|
+
// Mark the field as touched
|
|
133
|
+
field.dataset.conformTouched = 'true'; // Focus on the first invalid field
|
|
134
|
+
|
|
135
|
+
if (!focused && !field.validity.valid && field.tagName !== 'BUTTON') {
|
|
136
|
+
field.focus();
|
|
137
|
+
focused = true;
|
|
138
|
+
}
|
|
132
139
|
}
|
|
133
140
|
} // Check the validity of the form
|
|
134
141
|
|
|
@@ -303,7 +310,7 @@ function useFieldset(ref, config) {
|
|
|
303
310
|
|
|
304
311
|
return new Proxy({}, {
|
|
305
312
|
get(_target, key) {
|
|
306
|
-
var _constraint, _config$defaultValue, _config$initialError3, _config$initialError4, _error$key;
|
|
313
|
+
var _constraint, _config$defaultValue, _config$initialError$, _config$initialError3, _config$initialError4, _config$initialError5, _config$initialError6, _error$key;
|
|
307
314
|
|
|
308
315
|
if (typeof key !== 'string') {
|
|
309
316
|
return;
|
|
@@ -315,7 +322,7 @@ function useFieldset(ref, config) {
|
|
|
315
322
|
name: config !== null && config !== void 0 && config.name ? "".concat(config.name, ".").concat(key) : key,
|
|
316
323
|
form: config === null || config === void 0 ? void 0 : config.form,
|
|
317
324
|
defaultValue: config === null || config === void 0 ? void 0 : (_config$defaultValue = config.defaultValue) === null || _config$defaultValue === void 0 ? void 0 : _config$defaultValue[key],
|
|
318
|
-
initialError: config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details
|
|
325
|
+
initialError: (_config$initialError$ = config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details) !== null && _config$initialError$ !== void 0 ? _config$initialError$ : config === null || config === void 0 ? void 0 : (_config$initialError5 = config.initialError) === null || _config$initialError5 === void 0 ? void 0 : (_config$initialError6 = _config$initialError5[key]) === null || _config$initialError6 === void 0 ? void 0 : _config$initialError6.message
|
|
319
326
|
}, constraint),
|
|
320
327
|
error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''
|
|
321
328
|
};
|
|
@@ -329,7 +336,7 @@ function useFieldset(ref, config) {
|
|
|
329
336
|
* Returns a list of key and config, with a group of helpers
|
|
330
337
|
* configuring buttons for list manipulation
|
|
331
338
|
*
|
|
332
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
339
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
|
|
333
340
|
*/
|
|
334
341
|
function useFieldList(ref, config) {
|
|
335
342
|
var [entries, setEntries] = react.useState(() => {
|
|
@@ -338,7 +345,7 @@ function useFieldList(ref, config) {
|
|
|
338
345
|
return Object.entries((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [undefined]);
|
|
339
346
|
});
|
|
340
347
|
var list = entries.map((_ref, index) => {
|
|
341
|
-
var _config$defaultValue3, _config$
|
|
348
|
+
var _config$defaultValue3, _config$initialError7, _config$initialError8;
|
|
342
349
|
|
|
343
350
|
var [key, defaultValue] = _ref;
|
|
344
351
|
return {
|
|
@@ -346,7 +353,7 @@ function useFieldList(ref, config) {
|
|
|
346
353
|
config: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, config), {}, {
|
|
347
354
|
name: "".concat(config.name, "[").concat(index, "]"),
|
|
348
355
|
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue3 = config.defaultValue) === null || _config$defaultValue3 === void 0 ? void 0 : _config$defaultValue3[index],
|
|
349
|
-
initialError: (_config$
|
|
356
|
+
initialError: (_config$initialError7 = config.initialError) === null || _config$initialError7 === void 0 ? void 0 : (_config$initialError8 = _config$initialError7[index]) === null || _config$initialError8 === void 0 ? void 0 : _config$initialError8.details
|
|
350
357
|
})
|
|
351
358
|
};
|
|
352
359
|
});
|
|
@@ -448,12 +455,13 @@ function useFieldList(ref, config) {
|
|
|
448
455
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
449
456
|
* introduces custom input mode.
|
|
450
457
|
*
|
|
451
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
458
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
|
|
452
459
|
*/
|
|
453
460
|
function useControlledInput(field) {
|
|
454
461
|
var _field$defaultValue;
|
|
455
462
|
|
|
456
463
|
var ref = react.useRef(null);
|
|
464
|
+
var inputRef = react.useRef(null);
|
|
457
465
|
var [value, setValue] = react.useState("".concat((_field$defaultValue = field.defaultValue) !== null && _field$defaultValue !== void 0 ? _field$defaultValue : ''));
|
|
458
466
|
|
|
459
467
|
var handleChange = eventOrValue => {
|
|
@@ -483,10 +491,28 @@ function useControlledInput(field) {
|
|
|
483
491
|
|
|
484
492
|
return [_rollupPluginBabelHelpers.objectSpread2({
|
|
485
493
|
ref,
|
|
486
|
-
|
|
494
|
+
style: {
|
|
495
|
+
position: 'absolute',
|
|
496
|
+
width: '1px',
|
|
497
|
+
height: '1px',
|
|
498
|
+
padding: 0,
|
|
499
|
+
margin: '-1px',
|
|
500
|
+
overflow: 'hidden',
|
|
501
|
+
clip: 'rect(0,0,0,0)',
|
|
502
|
+
whiteSpace: 'nowrap',
|
|
503
|
+
borderWidth: 0
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
onFocus() {
|
|
507
|
+
var _inputRef$current;
|
|
508
|
+
|
|
509
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
510
|
+
}
|
|
511
|
+
|
|
487
512
|
}, helpers.input(field, {
|
|
488
513
|
type: 'text'
|
|
489
514
|
})), {
|
|
515
|
+
ref: inputRef,
|
|
490
516
|
value,
|
|
491
517
|
onChange: handleChange,
|
|
492
518
|
onBlur: handleBlur,
|
package/module/helpers.js
CHANGED
|
@@ -18,6 +18,10 @@ function input(config) {
|
|
|
18
18
|
multiple: config.multiple
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
if (typeof config.initialError !== 'undefined') {
|
|
22
|
+
attributes.autoFocus = true;
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
if (isCheckboxOrRadio) {
|
|
22
26
|
attributes.value = value !== null && value !== void 0 ? value : 'on';
|
|
23
27
|
attributes.defaultChecked = config.defaultValue === attributes.value;
|
|
@@ -30,25 +34,39 @@ function input(config) {
|
|
|
30
34
|
function select(config) {
|
|
31
35
|
var _config$defaultValue;
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
var attributes = {
|
|
34
38
|
name: config.name,
|
|
35
39
|
form: config.form,
|
|
36
40
|
defaultValue: config.multiple ? Array.isArray(config.defaultValue) ? config.defaultValue : [] : "".concat((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : ''),
|
|
37
41
|
required: config.required,
|
|
38
|
-
multiple: config.multiple
|
|
42
|
+
multiple: config.multiple,
|
|
43
|
+
autoFocus: typeof config.initialError !== 'undefined' ? Boolean(config.initialError) : undefined
|
|
39
44
|
};
|
|
45
|
+
|
|
46
|
+
if (typeof config.initialError !== 'undefined') {
|
|
47
|
+
attributes.autoFocus = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return attributes;
|
|
40
51
|
}
|
|
41
52
|
function textarea(config) {
|
|
42
53
|
var _config$defaultValue2;
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
var attributes = {
|
|
45
56
|
name: config.name,
|
|
46
57
|
form: config.form,
|
|
47
58
|
defaultValue: "".concat((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : ''),
|
|
48
59
|
required: config.required,
|
|
49
60
|
minLength: config.minLength,
|
|
50
|
-
maxLength: config.maxLength
|
|
61
|
+
maxLength: config.maxLength,
|
|
62
|
+
autoFocus: Boolean(config.initialError)
|
|
51
63
|
};
|
|
64
|
+
|
|
65
|
+
if (typeof config.initialError !== 'undefined') {
|
|
66
|
+
attributes.autoFocus = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return attributes;
|
|
52
70
|
}
|
|
53
71
|
|
|
54
72
|
export { input, select, textarea };
|
package/module/hooks.js
CHANGED
|
@@ -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.3.
|
|
10
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
|
|
11
11
|
*/
|
|
12
12
|
function useForm() {
|
|
13
13
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -121,10 +121,17 @@ function useForm() {
|
|
|
121
121
|
*/
|
|
122
122
|
|
|
123
123
|
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
|
|
124
|
-
|
|
124
|
+
var focused = false;
|
|
125
|
+
|
|
125
126
|
for (var field of form.elements) {
|
|
126
127
|
if (isFieldElement(field)) {
|
|
127
|
-
field
|
|
128
|
+
// Mark the field as touched
|
|
129
|
+
field.dataset.conformTouched = 'true'; // Focus on the first invalid field
|
|
130
|
+
|
|
131
|
+
if (!focused && !field.validity.valid && field.tagName !== 'BUTTON') {
|
|
132
|
+
field.focus();
|
|
133
|
+
focused = true;
|
|
134
|
+
}
|
|
128
135
|
}
|
|
129
136
|
} // Check the validity of the form
|
|
130
137
|
|
|
@@ -299,7 +306,7 @@ function useFieldset(ref, config) {
|
|
|
299
306
|
|
|
300
307
|
return new Proxy({}, {
|
|
301
308
|
get(_target, key) {
|
|
302
|
-
var _constraint, _config$defaultValue, _config$initialError3, _config$initialError4, _error$key;
|
|
309
|
+
var _constraint, _config$defaultValue, _config$initialError$, _config$initialError3, _config$initialError4, _config$initialError5, _config$initialError6, _error$key;
|
|
303
310
|
|
|
304
311
|
if (typeof key !== 'string') {
|
|
305
312
|
return;
|
|
@@ -311,7 +318,7 @@ function useFieldset(ref, config) {
|
|
|
311
318
|
name: config !== null && config !== void 0 && config.name ? "".concat(config.name, ".").concat(key) : key,
|
|
312
319
|
form: config === null || config === void 0 ? void 0 : config.form,
|
|
313
320
|
defaultValue: config === null || config === void 0 ? void 0 : (_config$defaultValue = config.defaultValue) === null || _config$defaultValue === void 0 ? void 0 : _config$defaultValue[key],
|
|
314
|
-
initialError: config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details
|
|
321
|
+
initialError: (_config$initialError$ = config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details) !== null && _config$initialError$ !== void 0 ? _config$initialError$ : config === null || config === void 0 ? void 0 : (_config$initialError5 = config.initialError) === null || _config$initialError5 === void 0 ? void 0 : (_config$initialError6 = _config$initialError5[key]) === null || _config$initialError6 === void 0 ? void 0 : _config$initialError6.message
|
|
315
322
|
}, constraint),
|
|
316
323
|
error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''
|
|
317
324
|
};
|
|
@@ -325,7 +332,7 @@ function useFieldset(ref, config) {
|
|
|
325
332
|
* Returns a list of key and config, with a group of helpers
|
|
326
333
|
* configuring buttons for list manipulation
|
|
327
334
|
*
|
|
328
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
335
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
|
|
329
336
|
*/
|
|
330
337
|
function useFieldList(ref, config) {
|
|
331
338
|
var [entries, setEntries] = useState(() => {
|
|
@@ -334,7 +341,7 @@ function useFieldList(ref, config) {
|
|
|
334
341
|
return Object.entries((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [undefined]);
|
|
335
342
|
});
|
|
336
343
|
var list = entries.map((_ref, index) => {
|
|
337
|
-
var _config$defaultValue3, _config$
|
|
344
|
+
var _config$defaultValue3, _config$initialError7, _config$initialError8;
|
|
338
345
|
|
|
339
346
|
var [key, defaultValue] = _ref;
|
|
340
347
|
return {
|
|
@@ -342,7 +349,7 @@ function useFieldList(ref, config) {
|
|
|
342
349
|
config: _objectSpread2(_objectSpread2({}, config), {}, {
|
|
343
350
|
name: "".concat(config.name, "[").concat(index, "]"),
|
|
344
351
|
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue3 = config.defaultValue) === null || _config$defaultValue3 === void 0 ? void 0 : _config$defaultValue3[index],
|
|
345
|
-
initialError: (_config$
|
|
352
|
+
initialError: (_config$initialError7 = config.initialError) === null || _config$initialError7 === void 0 ? void 0 : (_config$initialError8 = _config$initialError7[index]) === null || _config$initialError8 === void 0 ? void 0 : _config$initialError8.details
|
|
346
353
|
})
|
|
347
354
|
};
|
|
348
355
|
});
|
|
@@ -444,12 +451,13 @@ function useFieldList(ref, config) {
|
|
|
444
451
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
445
452
|
* introduces custom input mode.
|
|
446
453
|
*
|
|
447
|
-
* @see https://github.com/edmundhung/conform/tree/v0.3.
|
|
454
|
+
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
|
|
448
455
|
*/
|
|
449
456
|
function useControlledInput(field) {
|
|
450
457
|
var _field$defaultValue;
|
|
451
458
|
|
|
452
459
|
var ref = useRef(null);
|
|
460
|
+
var inputRef = useRef(null);
|
|
453
461
|
var [value, setValue] = useState("".concat((_field$defaultValue = field.defaultValue) !== null && _field$defaultValue !== void 0 ? _field$defaultValue : ''));
|
|
454
462
|
|
|
455
463
|
var handleChange = eventOrValue => {
|
|
@@ -479,10 +487,28 @@ function useControlledInput(field) {
|
|
|
479
487
|
|
|
480
488
|
return [_objectSpread2({
|
|
481
489
|
ref,
|
|
482
|
-
|
|
490
|
+
style: {
|
|
491
|
+
position: 'absolute',
|
|
492
|
+
width: '1px',
|
|
493
|
+
height: '1px',
|
|
494
|
+
padding: 0,
|
|
495
|
+
margin: '-1px',
|
|
496
|
+
overflow: 'hidden',
|
|
497
|
+
clip: 'rect(0,0,0,0)',
|
|
498
|
+
whiteSpace: 'nowrap',
|
|
499
|
+
borderWidth: 0
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
onFocus() {
|
|
503
|
+
var _inputRef$current;
|
|
504
|
+
|
|
505
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
506
|
+
}
|
|
507
|
+
|
|
483
508
|
}, input(field, {
|
|
484
509
|
type: 'text'
|
|
485
510
|
})), {
|
|
511
|
+
ref: inputRef,
|
|
486
512
|
value,
|
|
487
513
|
onChange: handleChange,
|
|
488
514
|
onBlur: handleBlur,
|
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.3.
|
|
5
|
+
"version": "0.3.1",
|
|
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.3.
|
|
22
|
+
"@conform-to/dom": "0.3.1"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"react": ">=16.8"
|