@conform-to/react 0.6.0-pre.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hooks.d.ts CHANGED
@@ -18,9 +18,9 @@ export interface FormConfig<Schema extends Record<string, any>, ClientSubmission
18
18
  */
19
19
  defaultValue?: FieldValue<Schema>;
20
20
  /**
21
- * An object describing the state from the last submission
21
+ * An object describing the result of the last submission
22
22
  */
23
- state?: Submission;
23
+ lastSubmission?: Submission;
24
24
  /**
25
25
  * An object describing the constraint of each field
26
26
  */
@@ -60,17 +60,20 @@ export interface FormConfig<Schema extends Record<string, any>, ClientSubmission
60
60
  * Properties to be applied to the form element
61
61
  */
62
62
  interface FormProps {
63
- ref: RefObject<HTMLFormElement>;
64
63
  id?: string;
64
+ ref: RefObject<HTMLFormElement>;
65
65
  onSubmit: (event: FormEvent<HTMLFormElement>) => void;
66
66
  noValidate: boolean;
67
+ 'aria-invalid'?: 'true';
68
+ 'aria-describedby'?: string;
67
69
  }
68
- interface Form<Schema extends Record<string, any>> {
70
+ interface Form {
69
71
  id?: string;
70
- ref: RefObject<HTMLFormElement>;
72
+ errorId?: string;
71
73
  error: string;
74
+ errors: string[];
75
+ ref: RefObject<HTMLFormElement>;
72
76
  props: FormProps;
73
- config: FieldsetConfig<Schema>;
74
77
  }
75
78
  /**
76
79
  * Returns properties required to hook into form events.
@@ -78,20 +81,12 @@ interface Form<Schema extends Record<string, any>> {
78
81
  *
79
82
  * @see https://conform.guide/api/react#useform
80
83
  */
81
- export declare function useForm<Schema extends Record<string, any>, ClientSubmission extends Submission | Submission<Schema> = Submission>(config?: FormConfig<Schema, ClientSubmission>): [Form<Schema>, Fieldset<Schema>];
82
- /**
83
- * All the information of the field, including state and config.
84
- */
85
- export type Field<Schema> = {
86
- config: FieldConfig<Schema>;
87
- error?: string;
88
- errors?: string[];
89
- };
84
+ export declare function useForm<Schema extends Record<string, any>, ClientSubmission extends Submission | Submission<Schema> = Submission>(config?: FormConfig<Schema, ClientSubmission>): [Form, Fieldset<Schema>];
90
85
  /**
91
- * A set of field information.
86
+ * A set of field configuration
92
87
  */
93
88
  export type Fieldset<Schema extends Record<string, any>> = {
94
- [Key in keyof Schema]-?: Field<Schema[Key]>;
89
+ [Key in keyof Schema]-?: FieldConfig<Schema[Key]>;
95
90
  };
96
91
  export interface FieldsetConfig<Schema extends Record<string, any>> {
97
92
  /**
@@ -111,7 +106,7 @@ export interface FieldsetConfig<Schema extends Record<string, any>> {
111
106
  */
112
107
  constraint?: FieldsetConstraint<Schema>;
113
108
  /**
114
- * The id of the form, connecting each field to a form remotely.
109
+ * The id of the form, connecting each field to a form remotely
115
110
  */
116
111
  form?: string;
117
112
  }
@@ -130,10 +125,7 @@ export declare function useFieldset<Schema extends Record<string, any>>(ref: Ref
130
125
  */
131
126
  export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Array<Payload>>): Array<{
132
127
  key: string;
133
- error: string | undefined;
134
- errors: string[] | undefined;
135
- config: FieldConfig<Payload>;
136
- }>;
128
+ } & FieldConfig<Payload>>;
137
129
  interface InputControl {
138
130
  change: (eventOrValue: {
139
131
  target: {
package/hooks.js CHANGED
@@ -13,30 +13,30 @@ var react = require('react');
13
13
  * @see https://conform.guide/api/react#useform
14
14
  */
15
15
  function useForm() {
16
- var _config$state;
16
+ var _config$lastSubmissio;
17
17
  var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
18
18
  var configRef = react.useRef(config);
19
19
  var ref = react.useRef(null);
20
- var [lastSubmission, setLastSubmission] = react.useState((_config$state = config.state) !== null && _config$state !== void 0 ? _config$state : null);
21
- var [error, setError] = react.useState(() => {
22
- if (!config.state) {
23
- return '';
20
+ var [lastSubmission, setLastSubmission] = react.useState((_config$lastSubmissio = config.lastSubmission) !== null && _config$lastSubmissio !== void 0 ? _config$lastSubmissio : null);
21
+ var [errors, setErrors] = react.useState(() => {
22
+ if (!config.lastSubmission) {
23
+ return [];
24
24
  }
25
- var message = config.state.error[''];
26
- return dom.getValidationMessage(message);
25
+ return [].concat(config.lastSubmission.error['']);
27
26
  });
28
27
  var [uncontrolledState, setUncontrolledState] = react.useState(() => {
29
- var submission = config.state;
28
+ var submission = config.lastSubmission;
30
29
  if (!submission) {
31
30
  return {
32
31
  defaultValue: config.defaultValue
33
32
  };
34
33
  }
34
+ var scope = dom.getScope(submission.intent);
35
35
  return {
36
36
  defaultValue: submission.payload,
37
37
  initialError: Object.entries(submission.error).reduce((result, _ref) => {
38
38
  var [name, message] = _ref;
39
- if (name !== '' && dom.shouldValidate(submission.intent, name)) {
39
+ if (name !== '' && (scope === null || scope === name)) {
40
40
  result[name] = message;
41
41
  }
42
42
  return result;
@@ -57,7 +57,7 @@ function useForm() {
57
57
  }, []);
58
58
  react.useEffect(() => {
59
59
  var form = ref.current;
60
- var submission = config.state;
60
+ var submission = config.lastSubmission;
61
61
  if (!form || !submission) {
62
62
  return;
63
63
  }
@@ -68,7 +68,7 @@ function useForm() {
68
68
  }));
69
69
  }
70
70
  setLastSubmission(submission);
71
- }, [config.state]);
71
+ }, [config.lastSubmission]);
72
72
  react.useEffect(() => {
73
73
  var form = ref.current;
74
74
  if (!form || !lastSubmission) {
@@ -103,12 +103,12 @@ function useForm() {
103
103
  var handleInvalid = event => {
104
104
  var form = dom.getFormElement(ref.current);
105
105
  var field = event.target;
106
- if (!form || !dom.isFieldElement(field) || field.form !== form || field.name !== '__form__') {
106
+ if (!form || !dom.isFieldElement(field) || field.form !== form || field.name !== dom.FORM_ERROR_ELEMENT_NAME) {
107
107
  return;
108
108
  }
109
109
  event.preventDefault();
110
110
  if (field.dataset.conformTouched) {
111
- setError(field.validationMessage);
111
+ setErrors(dom.getErrors(field.validationMessage));
112
112
  }
113
113
  };
114
114
  var handleReset = event => {
@@ -122,11 +122,10 @@ function useForm() {
122
122
  for (var field of form.elements) {
123
123
  if (dom.isFieldElement(field)) {
124
124
  delete field.dataset.conformTouched;
125
- field.setAttribute('aria-invalid', 'false');
126
125
  field.setCustomValidity('');
127
126
  }
128
127
  }
129
- setError('');
128
+ setErrors([]);
130
129
  setUncontrolledState({
131
130
  defaultValue: formConfig.defaultValue
132
131
  });
@@ -150,12 +149,11 @@ function useForm() {
150
149
  };
151
150
  }, []);
152
151
  var form = {
153
- id: config.id,
154
152
  ref,
155
- error,
153
+ error: errors[0],
154
+ errors,
156
155
  props: {
157
156
  ref,
158
- id: config.id,
159
157
  noValidate,
160
158
  onSubmit(event) {
161
159
  var form = event.currentTarget;
@@ -198,14 +196,22 @@ function useForm() {
198
196
  console.warn(e);
199
197
  }
200
198
  }
201
- },
202
- config: fieldsetConfig
199
+ }
203
200
  };
201
+ if (config.id) {
202
+ form.id = config.id;
203
+ form.errorId = "".concat(config.id, "-error");
204
+ form.props.id = form.id;
205
+ form.props['aria-describedby'] = form.errorId;
206
+ }
207
+ if (form.errorId && form.errors.length > 0) {
208
+ form.props['aria-invalid'] = 'true';
209
+ }
204
210
  return [form, fieldset];
205
211
  }
206
212
 
207
213
  /**
208
- * All the information of the field, including state and config.
214
+ * A set of field configuration
209
215
  */
210
216
 
211
217
  function useFieldset(ref, config) {
@@ -233,7 +239,8 @@ function useFieldset(ref, config) {
233
239
  var [error, setError] = react.useState(() => {
234
240
  var result = {};
235
241
  for (var [key, _error] of Object.entries(uncontrolledState.initialError)) {
236
- result[key] = dom.getErrors(dom.getValidationMessage(_error === null || _error === void 0 ? void 0 : _error['']));
242
+ var _error$;
243
+ result[key] = [].concat((_error$ = _error === null || _error === void 0 ? void 0 : _error['']) !== null && _error$ !== void 0 ? _error$ : []);
237
244
  }
238
245
  return result;
239
246
  });
@@ -254,10 +261,6 @@ function useFieldset(ref, config) {
254
261
  // Update the error only if the field belongs to the fieldset
255
262
  if (typeof key === 'string' && paths.length === 0) {
256
263
  if (field.dataset.conformTouched) {
257
- // Update the aria attribute only if it is set
258
- if (field.getAttribute('aria-invalid')) {
259
- field.setAttribute('aria-invalid', field.validationMessage !== '' ? 'true' : 'false');
260
- }
261
264
  setError(prev => {
262
265
  var prevMessage = dom.getValidationMessage(prev === null || prev === void 0 ? void 0 : prev[key]);
263
266
  if (prevMessage === field.validationMessage) {
@@ -309,19 +312,17 @@ function useFieldset(ref, config) {
309
312
  var fieldsetConfig = config !== null && config !== void 0 ? config : {};
310
313
  var constraint = (_fieldsetConfig$const = fieldsetConfig.constraint) === null || _fieldsetConfig$const === void 0 ? void 0 : _fieldsetConfig$const[key];
311
314
  var errors = error === null || error === void 0 ? void 0 : error[key];
312
- var field = {
313
- config: _rollupPluginBabelHelpers.objectSpread2({
314
- name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
315
- defaultValue: uncontrolledState.defaultValue[key],
316
- initialError: uncontrolledState.initialError[key]
317
- }, constraint),
315
+ var field = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, constraint), {}, {
316
+ name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
317
+ defaultValue: uncontrolledState.defaultValue[key],
318
+ initialError: uncontrolledState.initialError[key],
318
319
  error: errors === null || errors === void 0 ? void 0 : errors[0],
319
320
  errors
320
- };
321
+ });
321
322
  if (fieldsetConfig.form) {
322
- field.config.form = fieldsetConfig.form;
323
- field.config.id = "".concat(fieldsetConfig.form, "-").concat(field.config.name);
324
- field.config.errorId = "".concat(field.config.id, "-error");
323
+ field.form = fieldsetConfig.form;
324
+ field.id = "".concat(fieldsetConfig.form, "-").concat(field.name);
325
+ field.errorId = "".concat(field.id, "-error");
325
326
  }
326
327
  return field;
327
328
  }
@@ -354,7 +355,10 @@ function useFieldList(ref, config) {
354
355
  initialError
355
356
  };
356
357
  });
357
- var [error, setError] = react.useState(() => uncontrolledState.initialError.map(error => dom.getErrors(dom.getValidationMessage(error === null || error === void 0 ? void 0 : error['']))));
358
+ var [error, setError] = react.useState(() => uncontrolledState.initialError.map(error => {
359
+ var _error$2;
360
+ return [].concat((_error$2 = error === null || error === void 0 ? void 0 : error['']) !== null && _error$2 !== void 0 ? _error$2 : []);
361
+ }));
358
362
  var [entries, setEntries] = react.useState(() => {
359
363
  var _config$defaultValue3;
360
364
  return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]);
@@ -464,19 +468,18 @@ function useFieldList(ref, config) {
464
468
  var fieldConfig = {
465
469
  name: "".concat(config.name, "[").concat(index, "]"),
466
470
  defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index],
467
- initialError: uncontrolledState.initialError[index]
471
+ initialError: uncontrolledState.initialError[index],
472
+ error: errors === null || errors === void 0 ? void 0 : errors[0],
473
+ errors
468
474
  };
469
475
  if (config.form) {
470
476
  fieldConfig.form = config.form;
471
477
  fieldConfig.id = "".concat(config.form, "-").concat(config.name);
472
478
  fieldConfig.errorId = "".concat(fieldConfig.id, "-error");
473
479
  }
474
- return {
475
- key,
476
- error: errors === null || errors === void 0 ? void 0 : errors[0],
477
- errors,
478
- config: fieldConfig
479
- };
480
+ return _rollupPluginBabelHelpers.objectSpread2({
481
+ key
482
+ }, fieldConfig);
480
483
  });
481
484
  }
482
485
 
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { type FieldConfig, type FieldsetConstraint, type Submission, getFormElements, list, validate, requestIntent, requestSubmit, parse, validateConstraint, } from '@conform-to/dom';
2
- export * from './hooks';
1
+ export { type FieldConfig, type FieldsetConstraint, type Submission, parse, validateConstraint, list, validate, requestIntent, isFieldElement, } from '@conform-to/dom';
2
+ export { type Fieldset, type FieldsetConfig, type FormConfig, useForm, useFieldset, useFieldList, useInputEvent, } from './hooks';
3
3
  export * as conform from './helpers';
package/index.js CHANGED
@@ -8,9 +8,9 @@ var helpers = require('./helpers.js');
8
8
 
9
9
 
10
10
 
11
- Object.defineProperty(exports, 'getFormElements', {
11
+ Object.defineProperty(exports, 'isFieldElement', {
12
12
  enumerable: true,
13
- get: function () { return dom.getFormElements; }
13
+ get: function () { return dom.isFieldElement; }
14
14
  });
15
15
  Object.defineProperty(exports, 'list', {
16
16
  enumerable: true,
@@ -24,10 +24,6 @@ Object.defineProperty(exports, 'requestIntent', {
24
24
  enumerable: true,
25
25
  get: function () { return dom.requestIntent; }
26
26
  });
27
- Object.defineProperty(exports, 'requestSubmit', {
28
- enumerable: true,
29
- get: function () { return dom.requestSubmit; }
30
- });
31
27
  Object.defineProperty(exports, 'validate', {
32
28
  enumerable: true,
33
29
  get: function () { return dom.validate; }
package/module/helpers.js CHANGED
@@ -1,4 +1,5 @@
1
- export { VALIDATION_SKIPPED, VALIDATION_UNDEFINED } from '@conform-to/dom';
1
+ import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
2
+ export { INTENT, VALIDATION_SKIPPED, VALIDATION_UNDEFINED } from '@conform-to/dom';
2
3
 
3
4
  /**
4
5
  * Style to make the input element visually hidden
@@ -15,88 +16,66 @@ var hiddenStyle = {
15
16
  whiteSpace: 'nowrap',
16
17
  border: 0
17
18
  };
18
- function input(config) {
19
- var _config$initialError;
20
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
21
- var attributes = {
19
+ function getFormControlProps(config, options) {
20
+ var _config$error;
21
+ var props = {
22
22
  id: config.id,
23
- type: options.type,
24
23
  name: config.name,
25
24
  form: config.form,
26
- required: config.required,
25
+ required: config.required
26
+ };
27
+ if (config.id) {
28
+ props.id = config.id;
29
+ props['aria-describedby'] = config.errorId;
30
+ }
31
+ if (config.errorId && (_config$error = config.error) !== null && _config$error !== void 0 && _config$error.length) {
32
+ props['aria-invalid'] = true;
33
+ }
34
+ if (config.initialError && Object.entries(config.initialError).length > 0) {
35
+ props.autoFocus = true;
36
+ }
37
+ if (options !== null && options !== void 0 && options.hidden) {
38
+ props.style = hiddenStyle;
39
+ props.tabIndex = -1;
40
+ props['aria-hidden'] = true;
41
+ }
42
+ return props;
43
+ }
44
+ function input(config) {
45
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
46
+ var props = _objectSpread2(_objectSpread2({}, getFormControlProps(config, options)), {}, {
47
+ type: options.type,
27
48
  minLength: config.minLength,
28
49
  maxLength: config.maxLength,
29
50
  min: config.min,
30
51
  max: config.max,
31
52
  step: config.step,
32
53
  pattern: config.pattern,
33
- multiple: config.multiple,
34
- 'aria-invalid': Boolean((_config$initialError = config.initialError) === null || _config$initialError === void 0 ? void 0 : _config$initialError.length),
35
- 'aria-describedby': config.errorId
36
- };
37
- if (options !== null && options !== void 0 && options.hidden) {
38
- attributes.style = hiddenStyle;
39
- attributes.tabIndex = -1;
40
- attributes['aria-hidden'] = true;
41
- }
42
- if (config.initialError && Object.entries(config.initialError).length > 0) {
43
- attributes.autoFocus = true;
44
- }
54
+ multiple: config.multiple
55
+ });
45
56
  if (options.type === 'checkbox' || options.type === 'radio') {
46
57
  var _options$value;
47
- attributes.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on';
48
- attributes.defaultChecked = config.defaultValue === attributes.value;
58
+ props.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on';
59
+ props.defaultChecked = config.defaultValue === props.value;
49
60
  } else if (options.type !== 'file') {
50
- attributes.defaultValue = config.defaultValue;
61
+ props.defaultValue = config.defaultValue;
51
62
  }
52
- return attributes;
63
+ return props;
53
64
  }
54
65
  function select(config, options) {
55
- var _config$defaultValue, _config$initialError2;
56
- var attributes = {
57
- id: config.id,
58
- name: config.name,
59
- form: config.form,
60
- defaultValue: config.multiple ? Array.isArray(config.defaultValue) ? config.defaultValue : [] : "".concat((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : ''),
61
- required: config.required,
62
- multiple: config.multiple,
63
- 'aria-invalid': Boolean((_config$initialError2 = config.initialError) === null || _config$initialError2 === void 0 ? void 0 : _config$initialError2.length),
64
- 'aria-describedby': config.errorId
65
- };
66
- if (options !== null && options !== void 0 && options.hidden) {
67
- attributes.style = hiddenStyle;
68
- attributes.tabIndex = -1;
69
- attributes['aria-hidden'] = true;
70
- }
71
- if (config.initialError && Object.entries(config.initialError).length > 0) {
72
- attributes.autoFocus = true;
73
- }
74
- return attributes;
66
+ var props = _objectSpread2(_objectSpread2({}, getFormControlProps(config, options)), {}, {
67
+ defaultValue: config.defaultValue,
68
+ multiple: config.multiple
69
+ });
70
+ return props;
75
71
  }
76
72
  function textarea(config, options) {
77
- var _config$defaultValue2, _config$initialError3;
78
- var attributes = {
79
- id: config.id,
80
- name: config.name,
81
- form: config.form,
82
- defaultValue: "".concat((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : ''),
83
- required: config.required,
73
+ var props = _objectSpread2(_objectSpread2({}, getFormControlProps(config, options)), {}, {
74
+ defaultValue: config.defaultValue,
84
75
  minLength: config.minLength,
85
- maxLength: config.maxLength,
86
- autoFocus: Boolean(config.initialError),
87
- 'aria-invalid': Boolean((_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : _config$initialError3.length),
88
- 'aria-describedby': config.errorId
89
- };
90
- if (options !== null && options !== void 0 && options.hidden) {
91
- attributes.style = hiddenStyle;
92
- attributes.tabIndex = -1;
93
- attributes['aria-hidden'] = true;
94
- }
95
- if (config.initialError && Object.entries(config.initialError).length > 0) {
96
- attributes.autoFocus = true;
97
- }
98
- return attributes;
76
+ maxLength: config.maxLength
77
+ });
78
+ return props;
99
79
  }
100
- var intent = '__intent__';
101
80
 
102
- export { input, intent, select, textarea };
81
+ export { input, select, textarea };