@conform-to/react 0.5.1 → 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/README.md CHANGED
@@ -10,15 +10,13 @@
10
10
  - [useFieldset](#usefieldset)
11
11
  - [useFieldList](#usefieldlist)
12
12
  - [useInputEvent](#useinputevent)
13
- - [useControlledInput](#usecontrolledinput)
14
13
  - [conform](#conform)
14
+ - [parse](#parse)
15
+ - [validateConstraint](#validateconstraint)
15
16
  - [list](#list)
16
17
  - [validate](#validate)
17
- - [requestCommand](#requestcommand)
18
- - [getFormElements](#getformelements)
19
- - [hasError](#haserror)
20
- - [parse](#parse)
21
- - [shouldValidate](#shouldvalidate)
18
+ - [requestIntent](#requestintent)
19
+ - [isFieldElement](#isfieldelement)
22
20
 
23
21
  <!-- /aside -->
24
22
 
@@ -28,9 +26,9 @@ By default, the browser calls the [reportValidity()](https://developer.mozilla.o
28
26
 
29
27
  This hook enhances the form validation behaviour by:
30
28
 
31
- - Enabling customizing form validation behaviour.
32
- - Capturing the error message and removes the error bubbles.
33
- - Preparing all properties required to configure the dom elements.
29
+ - Enabling customizing validation logic.
30
+ - Capturing error message and removes the error bubbles.
31
+ - Preparing all properties required to configure the form elements.
34
32
 
35
33
  ```tsx
36
34
  import { useForm } from '@conform-to/react';
@@ -43,14 +41,6 @@ function LoginForm() {
43
41
  */
44
42
  id: undefined,
45
43
 
46
- /**
47
- * Validation mode.
48
- * Support "client-only" or "server-validation".
49
- *
50
- * Default to `client-only`.
51
- */
52
- mode: 'client-only',
53
-
54
44
  /**
55
45
  * Define when the error should be reported initially.
56
46
  * Support "onSubmit", "onChange", "onBlur".
@@ -62,17 +52,17 @@ function LoginForm() {
62
52
  /**
63
53
  * An object representing the initial value of the form.
64
54
  */
65
- defaultValue: undefined;
55
+ defaultValue: undefined,
66
56
 
67
57
  /**
68
- * An object describing the state from the last submission
58
+ * The last submission result from the server
69
59
  */
70
- state: undefined;
60
+ lastSubmission: undefined,
71
61
 
72
62
  /**
73
63
  * An object describing the constraint of each field
74
64
  */
75
- constraint: undefined;
65
+ constraint: undefined,
76
66
 
77
67
  /**
78
68
  * Enable native validation before hydation.
@@ -99,7 +89,7 @@ function LoginForm() {
99
89
  /**
100
90
  * The submit event handler of the form.
101
91
  */
102
- onSubmit(event, { formData, submission }) {
92
+ onSubmit(event, { formData, submission, action, encType, method }) {
103
93
  // ...
104
94
  },
105
95
  });
@@ -174,20 +164,20 @@ function Example() {
174
164
  const [form, { address }] = useForm<{ address: Address }>();
175
165
  const { city, zipcode, street, country } = useFieldset(
176
166
  form.ref,
177
- address.config,
167
+ address,
178
168
  );
179
169
 
180
170
  return (
181
171
  <form {...form.props}>
182
172
  <fieldset>
183
173
  <legned>Address</legend>
184
- <input {...conform.input(street.config)} />
174
+ <input {...conform.input(street)} />
185
175
  <div>{street.error}</div>
186
- <input {...conform.input(zipcode.config)} />
176
+ <input {...conform.input(zipcode)} />
187
177
  <div>{zipcode.error}</div>
188
- <input {...conform.input(city.config)} />
178
+ <input {...conform.input(city)} />
189
179
  <div>{city.error}</div>
190
- <input {...conform.input(country.config)} />
180
+ <input {...conform.input(country)} />
191
181
  <div>{country.error}</div>
192
182
  </fieldset>
193
183
  <button>Submit</button>
@@ -213,7 +203,7 @@ function Fieldset(config: FieldConfig<Address>) {
213
203
  <details>
214
204
  <summary>Why does `useFieldset` require a ref object of the form or fieldset?</summary>
215
205
 
216
- **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.
206
+ **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.
217
207
 
218
208
  ```tsx
219
209
  function ExampleForm() {
@@ -240,7 +230,7 @@ function ExampleForm() {
240
230
 
241
231
  ### useFieldList
242
232
 
243
- This hook enables you to work with [array](/docs/configuration.md#array) and support [list](#list) command 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.
233
+ 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.
244
234
 
245
235
  ```tsx
246
236
  import { useForm, useFieldList, list } from '@conform-to/react';
@@ -254,27 +244,25 @@ type Schema = {
254
244
 
255
245
  function Example() {
256
246
  const [form, { items }] = useForm<Schema>();
257
- const list = useFieldList(form.ref, items.config);
247
+ const itemsList = useFieldList(form.ref, items);
258
248
 
259
249
  return (
260
250
  <fieldset ref={ref}>
261
- {list.map((item, index) => (
251
+ {itemsList.map((item, index) => (
262
252
  <div key={item.key}>
263
253
  {/* Setup an input per item */}
264
- <input {...conform.input(item.config)} />
254
+ <input {...conform.input(item)} />
265
255
 
266
256
  {/* Error of each item */}
267
257
  <span>{item.error}</span>
268
258
 
269
259
  {/* Setup a delete button (Note: It is `items` not `item`) */}
270
- <button {...list.remove(items.config.name, { index })}>Delete</button>
260
+ <button {...list.remove(items.name, { index })}>Delete</button>
271
261
  </div>
272
262
  ))}
273
263
 
274
264
  {/* Setup a button that can append a new row with optional default value */}
275
- <button {...list.append(items.config.name, { defaultValue: '' })}>
276
- add
277
- </button>
265
+ <button {...list.append(items.name, { defaultValue: '' })}>add</button>
278
266
  </fieldset>
279
267
  );
280
268
  }
@@ -293,9 +281,9 @@ import { useState, useRef } from 'react';
293
281
 
294
282
  function MuiForm() {
295
283
  const [form, { category }] = useForm();
296
- const [value, setValue] = useState(category.config.defaultValue ?? '');
284
+ const [value, setValue] = useState(category.defaultValue ?? '');
297
285
  const [ref, control] = useInputEvent({
298
- onReset: () => setValue(category.config.defaultValue ?? ''),
286
+ onReset: () => setValue(category.defaultValue ?? ''),
299
287
  });
300
288
  const inputRef = useRef<HTMLInputElement>(null);
301
289
 
@@ -304,7 +292,7 @@ function MuiForm() {
304
292
  {/* Render a shadow input somewhere */}
305
293
  <input
306
294
  ref={ref}
307
- {...conform.input(category.config, { hidden: true })}
295
+ {...conform.input(category, { hidden: true })}
308
296
  onChange={(e) => setValue(e.target.value)}
309
297
  onFocus={() => inputRef.current?.focus()}
310
298
  />
@@ -330,54 +318,11 @@ function MuiForm() {
330
318
 
331
319
  ---
332
320
 
333
- ### useControlledInput
334
-
335
- > This API is deprecated and replaced with the [useInputEvent](#useinputevent) hook.
336
-
337
- It returns the properties required to configure a shadow input for validation and helper to integrate it. This is particularly useful when [integrating custom input components](/docs/integrations.md#custom-input-component) like dropdown and datepicker.
338
-
339
- ```tsx
340
- import { useForm, useControlledInput } from '@conform-to/react';
341
- import { Select, MenuItem } from '@mui/material';
342
-
343
- function MuiForm() {
344
- const [form, { category }] = useForm();
345
- const [inputProps, control] = useControlledInput(category.config);
346
-
347
- return (
348
- <form {...form.props}>
349
- {/* Render a shadow input somewhere */}
350
- <input {...inputProps} />
351
-
352
- {/* MUI Select is a controlled component */}
353
- <TextField
354
- label="Category"
355
- inputRef={control.ref}
356
- value={control.value}
357
- onChange={control.onChange}
358
- onBlur={control.onBlur}
359
- inputProps={{
360
- onInvalid: control.onInvalid,
361
- }}
362
- select
363
- >
364
- <MenuItem value="">Please select</MenuItem>
365
- <MenuItem value="a">Category A</MenuItem>
366
- <MenuItem value="b">Category B</MenuItem>
367
- <MenuItem value="c">Category C</MenuItem>
368
- </TextField>
369
- </form>
370
- );
371
- }
372
- ```
373
-
374
- ---
375
-
376
321
  ### conform
377
322
 
378
- It provides several helpers to remove the boilerplate when configuring a form control.
323
+ 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).
379
324
 
380
- You are recommended to create a wrapper on top if you need to integrate with custom input component. As the helper derives attributes for [accessibility](/docs/accessibility.md#configuration) concerns and helps [focus management](/docs/focus-management.md#focusing-before-javascript-is-loaded).
325
+ You can also create a wrapper on top if you need to integrate with custom input component.
381
326
 
382
327
  Before:
383
328
 
@@ -391,31 +336,31 @@ function Example() {
391
336
  <form {...form.props}>
392
337
  <input
393
338
  type="text"
394
- name={title.config.name}
395
- form={title.config.form}
396
- defaultValue={title.config.defaultValue}
397
- requried={title.config.required}
398
- minLength={title.config.minLength}
399
- maxLength={title.config.maxLength}
400
- min={title.config.min}
401
- max={title.config.max}
402
- multiple={title.config.multiple}
403
- pattern={title.config.pattern}
339
+ name={title.name}
340
+ form={title.form}
341
+ defaultValue={title.defaultValue}
342
+ requried={title.required}
343
+ minLength={title.minLength}
344
+ maxLength={title.maxLength}
345
+ min={title.min}
346
+ max={title.max}
347
+ multiple={title.multiple}
348
+ pattern={title.pattern}
404
349
  />
405
350
  <textarea
406
- name={description.config.name}
407
- form={description.config.form}
408
- defaultValue={description.config.defaultValue}
409
- requried={description.config.required}
410
- minLength={description.config.minLength}
411
- maxLength={description.config.maxLength}
351
+ name={description.name}
352
+ form={description.form}
353
+ defaultValue={description.defaultValue}
354
+ requried={description.required}
355
+ minLength={description.minLength}
356
+ maxLength={description.maxLength}
412
357
  />
413
358
  <select
414
- name={category.config.name}
415
- form={category.config.form}
416
- defaultValue={category.config.defaultValue}
417
- requried={category.config.required}
418
- multiple={category.config.multiple}
359
+ name={category.name}
360
+ form={category.form}
361
+ defaultValue={category.defaultValue}
362
+ requried={category.required}
363
+ multiple={category.multiple}
419
364
  >
420
365
  {/* ... */}
421
366
  </select>
@@ -434,9 +379,9 @@ function Example() {
434
379
 
435
380
  return (
436
381
  <form {...form.props}>
437
- <input {...conform.input(title.config, { type: 'text' })} />
438
- <textarea {...conform.textarea(description.config)} />
439
- <select {...conform.select(category.config)}>{/* ... */}</select>
382
+ <input {...conform.input(title, { type: 'text' })} />
383
+ <textarea {...conform.textarea(description)} />
384
+ <select {...conform.select(category)}>{/* ... */}</select>
440
385
  </form>
441
386
  );
442
387
  }
@@ -444,9 +389,117 @@ function Example() {
444
389
 
445
390
  ---
446
391
 
392
+ ### parse
393
+
394
+ It parses the formData based on the [naming convention](/docs/configuration.md#naming-convention) with the validation result from the resolver.
395
+
396
+ ```tsx
397
+ import { parse } from '@conform-to/react';
398
+
399
+ const formData = new FormData();
400
+ const submission = parse(formData, {
401
+ resolve({ email, password }) {
402
+ const error: Record<string, string> = {};
403
+
404
+ if (typeof email !== 'string') {
405
+ error.email = 'Email is required';
406
+ } else if (!/^[^@]+@[^@]+$/.test(email)) {
407
+ error.email = 'Email is invalid';
408
+ }
409
+
410
+ if (typeof password !== 'string') {
411
+ error.password = 'Password is required';
412
+ }
413
+
414
+ if (error.email || error.password) {
415
+ return { error };
416
+ }
417
+
418
+ return {
419
+ value: { email, password },
420
+ };
421
+ },
422
+ });
423
+ ```
424
+
425
+ ---
426
+
427
+ ### validateConstraint
428
+
429
+ 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).
430
+
431
+ ```tsx
432
+ import { useForm, validateConstraint } from '@conform-to/react';
433
+ import { Form } from 'react-router-dom';
434
+
435
+ export default function SignupForm() {
436
+ const [form, { email, password, confirmPassword }] = useForm({
437
+ onValidate(context) {
438
+ // This enables validating each field based on the validity state and custom cosntraint if defined
439
+ return validateConstraint(
440
+ ...context,
441
+ constraint: {
442
+ // Define custom constraint
443
+ match(value, { formData, attributeValue }) {
444
+ // Check if the value of the field match the value of another field
445
+ return value === formData.get(attributeValue);
446
+ },
447
+ });
448
+ }
449
+ });
450
+
451
+ return (
452
+ <Form method="post" {...form.props}>
453
+ <div>
454
+ <label>Email</label>
455
+ <input
456
+ name="email"
457
+ type="email"
458
+ required
459
+ pattern="[^@]+@[^@]+\\.[^@]+"
460
+ />
461
+ {email.error === 'required' ? (
462
+ <div>Email is required</div>
463
+ ) : email.error === 'type' ? (
464
+ <div>Email is invalid</div>
465
+ ) : null}
466
+ </div>
467
+ <div>
468
+ <label>Password</label>
469
+ <input
470
+ name="password"
471
+ type="password"
472
+ required
473
+ />
474
+ {password.error === 'required' ? (
475
+ <div>Password is required</div>
476
+ ) : null}
477
+ </div>
478
+ <div>
479
+ <label>Confirm Password</label>
480
+ <input
481
+ name="confirmPassword"
482
+ type="password"
483
+ required
484
+ data-constraint-match="password"
485
+ />
486
+ {confirmPassword.error === 'required' ? (
487
+ <div>Confirm Password is required</div>
488
+ ) : confirmPassword.error === 'match' ? (
489
+ <div>Password does not match</div>
490
+ ) : null}
491
+ </div>
492
+ <button>Signup</button>
493
+ </Form>
494
+ );
495
+ }
496
+ ```
497
+
498
+ ---
499
+
447
500
  ### list
448
501
 
449
- It provides serveral helpers to configure a command button for [modifying a list](/docs/commands.md#modifying-a-list).
502
+ It provides serveral helpers to configure an intent button for [modifying a list](/docs/commands.md#modifying-a-list).
450
503
 
451
504
  ```tsx
452
505
  import { list } from '@conform-to/react';
@@ -479,7 +532,7 @@ function Example() {
479
532
 
480
533
  ### validate
481
534
 
482
- It returns the properties required to configure a command button for [validation](/docs/commands.md#validation).
535
+ It returns the properties required to configure an intent button for [validation](/docs/commands.md#validation).
483
536
 
484
537
  ```tsx
485
538
  import { validate } from '@conform-to/react';
@@ -499,9 +552,9 @@ function Example() {
499
552
 
500
553
  ---
501
554
 
502
- ### requestCommand
555
+ ### requestIntent
503
556
 
504
- It lets you [trigger a command](/docs/commands.md#triggering-a-command) without requiring users to click on a button. It supports both [list](#list) and [validate](#validate) command.
557
+ It lets you [trigger an intent](/docs/commands.md#triggering-an-intent) without requiring users to click on a button. It supports both [list](#list) and [validate](#validate) intent.
505
558
 
506
559
  ```tsx
507
560
  import {
@@ -509,23 +562,23 @@ import {
509
562
  useFieldList,
510
563
  conform,
511
564
  list,
512
- requestCommand,
565
+ requestIntent,
513
566
  } from '@conform-to/react';
514
567
  import DragAndDrop from 'awesome-dnd-example';
515
568
 
516
569
  export default function Todos() {
517
570
  const [form, { tasks }] = useForm();
518
- const taskList = useFieldList(form.ref, tasks.config);
571
+ const taskList = useFieldList(form.ref, tasks);
519
572
 
520
573
  const handleDrop = (from, to) =>
521
- requestCommand(form.ref.current, list.reorder({ from, to }));
574
+ requestIntent(form.ref.current, list.reorder({ from, to }));
522
575
 
523
576
  return (
524
577
  <form {...form.props}>
525
578
  <DragAndDrop onDrop={handleDrop}>
526
579
  {taskList.map((task, index) => (
527
580
  <div key={task.key}>
528
- <input {...conform.input(task.config)} />
581
+ <input {...conform.input(task)} />
529
582
  </div>
530
583
  ))}
531
584
  </DragAndDrop>
@@ -537,107 +590,22 @@ export default function Todos() {
537
590
 
538
591
  ---
539
592
 
540
- ### getFormElements
593
+ ### isFieldElement
541
594
 
542
- It returns all _input_ / _select_ / _textarea_ or _button_ in the forms. Useful when looping through the form elements to validate each field manually.
595
+ 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.
543
596
 
544
597
  ```tsx
545
- import { useForm, parse, getFormElements } from '@conform-to/react';
546
-
547
- export default function LoginForm() {
548
- const [form] = useForm({
549
- onValidate({ form, formData }) {
550
- const submission = parse(formData);
551
-
552
- for (const element of getFormElements(form)) {
553
- switch (element.name) {
554
- case 'email': {
555
- if (element.validity.valueMissing) {
556
- submission.error.push([element.name, 'Email is required']);
557
- } else if (element.validity.typeMismatch) {
558
- submission.error.push([element.name, 'Email is invalid']);
559
- }
560
- break;
561
- }
562
- case 'password': {
563
- if (element.validity.valueMissing) {
564
- submission.error.push([element.name, 'Password is required']);
565
- }
566
- break;
567
- }
598
+ function Example() {
599
+ return (
600
+ <form
601
+ onFocus={(event) => {
602
+ if (isFieldElement(event.target)) {
603
+ // event.target is now considered one of the form elements type
568
604
  }
569
- }
570
-
571
- return submission;
572
- },
573
-
574
- // ....
575
- });
576
-
577
- // ...
605
+ }}
606
+ >
607
+ {/* ... */}
608
+ </form>
609
+ );
578
610
  }
579
611
  ```
580
-
581
- ---
582
-
583
- ### hasError
584
-
585
- This helper checks if there is any message defined in error array with the provided name.
586
-
587
- ```ts
588
- import { hasError } from '@conform-to/react';
589
-
590
- /**
591
- * Assume the error looks like this:
592
- */
593
- const error = [['email', 'Email is required']];
594
-
595
- // This will log `true`
596
- console.log(hasError(error, 'email'));
597
-
598
- // This will log `false`
599
- console.log(hasError(error, 'password'));
600
- ```
601
-
602
- ---
603
-
604
- ### parse
605
-
606
- It parses the formData based on the [naming convention](/docs/submission).
607
-
608
- ```tsx
609
- import { parse } from '@conform-to/react';
610
-
611
- const formData = new FormData();
612
- const submission = parse(formData);
613
-
614
- console.log(submission);
615
- ```
616
-
617
- ---
618
-
619
- ### shouldValidate
620
-
621
- This helper checks if the scope of validation includes a specific field by checking the submission:
622
-
623
- ```tsx
624
- import { shouldValidate } from '@conform-to/react';
625
-
626
- /**
627
- * The submission type and intent give us hint on what should be valdiated.
628
- * If the type is 'validate', only the field with name matching the metadata must be validated.
629
- * If the type is 'submit', everything should be validated (Default submission)
630
- */
631
- const submission = {
632
- context: 'validate',
633
- intent: 'email',
634
- value: {},
635
- error: [],
636
- };
637
-
638
- // This will log 'true'
639
- console.log(shouldValidate(submission, 'email'));
640
-
641
- // This will log 'false'
642
- console.log(shouldValidate(submission, 'password'));
643
- ```
@@ -24,6 +24,7 @@ function _objectSpread2(target) {
24
24
  return target;
25
25
  }
26
26
  function _defineProperty(obj, key, value) {
27
+ key = _toPropertyKey(key);
27
28
  if (key in obj) {
28
29
  Object.defineProperty(obj, key, {
29
30
  value: value,
@@ -36,6 +37,22 @@ function _defineProperty(obj, key, value) {
36
37
  }
37
38
  return obj;
38
39
  }
40
+ function _toPrimitive(input, hint) {
41
+ if (typeof input !== "object" || input === null) return input;
42
+ var prim = input[Symbol.toPrimitive];
43
+ if (prim !== undefined) {
44
+ var res = prim.call(input, hint || "default");
45
+ if (typeof res !== "object") return res;
46
+ throw new TypeError("@@toPrimitive must return a primitive value.");
47
+ }
48
+ return (hint === "string" ? String : Number)(input);
49
+ }
50
+ function _toPropertyKey(arg) {
51
+ var key = _toPrimitive(arg, "string");
52
+ return typeof key === "symbol" ? key : String(key);
53
+ }
39
54
 
40
55
  exports.defineProperty = _defineProperty;
41
56
  exports.objectSpread2 = _objectSpread2;
57
+ exports.toPrimitive = _toPrimitive;
58
+ exports.toPropertyKey = _toPropertyKey;
package/helpers.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { FieldConfig } from '@conform-to/dom';
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 FieldProps {
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 FieldProps {
15
+ interface InputProps<Schema> extends FormControlProps {
16
16
  type?: HTMLInputTypeAttribute;
17
17
  minLength?: number;
18
18
  maxLength?: number;
@@ -25,16 +25,16 @@ interface InputProps<Schema> extends FieldProps {
25
25
  defaultChecked?: boolean;
26
26
  defaultValue?: string;
27
27
  }
28
- interface SelectProps extends FieldProps {
28
+ interface SelectProps extends FormControlProps {
29
29
  defaultValue?: string | number | readonly string[] | undefined;
30
30
  multiple?: boolean;
31
31
  }
32
- interface TextareaProps extends FieldProps {
32
+ interface TextareaProps extends FormControlProps {
33
33
  minLength?: number;
34
34
  maxLength?: number;
35
35
  defaultValue?: string;
36
36
  }
37
- declare type InputOptions = {
37
+ type InputOptions = {
38
38
  type: 'checkbox' | 'radio';
39
39
  hidden?: boolean;
40
40
  value?: string;
@@ -46,11 +46,11 @@ declare type InputOptions = {
46
46
  export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: {
47
47
  type: 'file';
48
48
  }): InputProps<Schema>;
49
- export declare function input<Schema extends any>(config: FieldConfig<Schema>, options?: InputOptions): InputProps<Schema>;
50
- export declare function select<Schema>(config: FieldConfig<Schema>, options?: {
49
+ export declare function input<Schema extends Primitive>(config: FieldConfig<Schema>, options?: InputOptions): InputProps<Schema>;
50
+ export declare function select(config: FieldConfig<Primitive | Primitive[]>, options?: {
51
51
  hidden?: boolean;
52
52
  }): SelectProps;
53
- export declare function textarea<Schema>(config: FieldConfig<Schema>, options?: {
53
+ export declare function textarea(config: FieldConfig<Primitive>, options?: {
54
54
  hidden?: boolean;
55
55
  }): TextareaProps;
56
- export {};
56
+ export { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED };