@conform-to/react
Advanced tools
Comparing version 0.4.0-pre.2 to 0.4.0-pre.3
import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type ListCommand, type Primitive, type Submission } from '@conform-to/dom'; | ||
import { type InputHTMLAttributes, type FormEvent, type RefObject } from 'react'; | ||
interface FormContext<Schema extends Record<string, any>> { | ||
form: HTMLFormElement; | ||
formData: FormData; | ||
submission: Submission<Schema>; | ||
} | ||
export interface FormConfig<Schema extends Record<string, any>> { | ||
@@ -43,3 +38,6 @@ /** | ||
*/ | ||
onValidate?: (context: FormContext<Schema>) => Array<[string, string]>; | ||
onValidate?: ({ form, formData, }: { | ||
form: HTMLFormElement; | ||
formData: FormData; | ||
}) => Submission<Schema>; | ||
/** | ||
@@ -49,3 +47,6 @@ * The submit event handler of the form. It will be called | ||
*/ | ||
onSubmit?: (event: FormEvent<HTMLFormElement>, context: FormContext<Schema>) => void; | ||
onSubmit?: (event: FormEvent<HTMLFormElement>, context: { | ||
formData: FormData; | ||
submission: Submission<Schema>; | ||
}) => void; | ||
} | ||
@@ -70,3 +71,3 @@ /** | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#useform | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform | ||
*/ | ||
@@ -112,7 +113,7 @@ export declare function useForm<Schema extends Record<string, any>>(config?: FormConfig<Schema>): Form<Schema>; | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usefieldset | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldset | ||
*/ | ||
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config?: FieldsetConfig<Schema>): Fieldset<Schema>; | ||
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config?: FieldConfig<Schema>): Fieldset<Schema>; | ||
interface ControlButtonProps { | ||
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldsetConfig<Schema>): Fieldset<Schema>; | ||
export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Schema>): Fieldset<Schema>; | ||
interface CommandButtonProps { | ||
name?: string; | ||
@@ -123,20 +124,10 @@ value?: string; | ||
} | ||
declare type CommandPayload<Schema, Type extends ListCommand<FieldValue<Schema>>['type']> = Extract<ListCommand<FieldValue<Schema>>, { | ||
declare type ListCommandPayload<Schema, Type extends ListCommand<FieldValue<Schema>>['type']> = Extract<ListCommand<FieldValue<Schema>>, { | ||
type: Type; | ||
}>['payload']; | ||
/** | ||
* A group of helpers for configuring a list control button | ||
*/ | ||
interface ListControl<Schema> { | ||
prepend(payload?: CommandPayload<Schema, 'prepend'>): ControlButtonProps; | ||
append(payload?: CommandPayload<Schema, 'append'>): ControlButtonProps; | ||
replace(payload: CommandPayload<Schema, 'replace'>): ControlButtonProps; | ||
remove(payload: CommandPayload<Schema, 'remove'>): ControlButtonProps; | ||
reorder(payload: CommandPayload<Schema, 'reorder'>): ControlButtonProps; | ||
} | ||
/** | ||
* Returns a list of key and config, with a group of helpers | ||
* configuring buttons for list manipulation | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usefieldlist | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist | ||
*/ | ||
@@ -148,3 +139,9 @@ export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Array<Payload>>): [ | ||
}>, | ||
ListControl<Payload> | ||
{ | ||
prepend(payload?: ListCommandPayload<Payload, 'prepend'>): CommandButtonProps; | ||
append(payload?: ListCommandPayload<Payload, 'append'>): CommandButtonProps; | ||
replace(payload: ListCommandPayload<Payload, 'replace'>): CommandButtonProps; | ||
remove(payload: ListCommandPayload<Payload, 'remove'>): CommandButtonProps; | ||
reorder(payload: ListCommandPayload<Payload, 'reorder'>): CommandButtonProps; | ||
} | ||
]; | ||
@@ -172,3 +169,3 @@ interface ShadowInputProps extends InputHTMLAttributes<HTMLInputElement> { | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usecontrolledinput | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput | ||
*/ | ||
@@ -175,0 +172,0 @@ export declare function useControlledInput<Element extends { |
79
hooks.js
@@ -14,3 +14,3 @@ 'use strict'; | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#useform | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform | ||
*/ | ||
@@ -187,41 +187,46 @@ function useForm() { | ||
try { | ||
var submission; | ||
var formData = dom.getFormData(form, submitter); | ||
var submission = dom.parse(formData); | ||
var _context = { | ||
form, | ||
formData, | ||
submission | ||
}; // Touch all fields only if the submitter is not a command button | ||
if (submission.context === 'submit') { | ||
for (var field of form.elements) { | ||
if (dom.isFieldElement(field)) { | ||
// Mark the field as touched | ||
field.dataset.conformTouched = 'true'; | ||
} | ||
} | ||
} | ||
var _error; | ||
if (typeof config.onValidate === 'function') { | ||
_error = config.onValidate(_context); | ||
submission = config.onValidate({ | ||
form, | ||
formData | ||
}); | ||
} else { | ||
submission = dom.parse(formData); | ||
if (config.mode !== 'server-validation') { | ||
// Clear previous result | ||
/** | ||
* As there is no custom logic defined, | ||
* removing the custom validity state will allow us | ||
* finding the latest validation message. | ||
* | ||
* This is mainly used to showcase the constraint validation API. | ||
*/ | ||
dom.setFormError(form, { | ||
context: 'submit', | ||
type: 'submit', | ||
value: {}, | ||
error: [] | ||
}); | ||
for (var _element of form.elements) { | ||
if (dom.isFieldElement(_element) && _element.willValidate) { | ||
submission.error.push([_element.name, _element.validationMessage]); | ||
} | ||
} | ||
} | ||
} // Touch all fields only if the submitter is not a command button | ||
_error = dom.getFormError(form); | ||
} | ||
if (_error.length > 0) { | ||
submission.error.push(..._error); | ||
if (submission.type === 'submit') { | ||
for (var field of form.elements) { | ||
if (dom.isFieldElement(field)) { | ||
// Mark the field as touched | ||
field.dataset.conformTouched = 'true'; | ||
} | ||
} | ||
} | ||
if (!config.noValidate && !submitter.formNoValidate && dom.hasError(submission.error) || submission.context === 'validate' && config.mode !== 'server-validation') { | ||
if (!config.noValidate && !submitter.formNoValidate && dom.hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') { | ||
event.preventDefault(); | ||
@@ -231,3 +236,6 @@ } else { | ||
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, _context); | ||
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, { | ||
formData, | ||
submission | ||
}); | ||
} | ||
@@ -307,7 +315,7 @@ | ||
var invalidHandler = event => { | ||
var _configRef$current$na, _configRef$current; | ||
var _configRef$current$na; | ||
var form = dom.getFormElement(ref.current); | ||
var field = event.target; | ||
var fieldsetName = (_configRef$current$na = (_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : ''; | ||
var fieldsetName = (_configRef$current$na = configRef.current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : ''; | ||
@@ -356,6 +364,6 @@ if (!form || !dom.isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) { | ||
setError(prev => { | ||
var _configRef$current$na2, _configRef$current2; | ||
var _configRef$current$na2; | ||
var next = prev; | ||
var fieldsetName = (_configRef$current$na2 = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : ''; | ||
var fieldsetName = (_configRef$current$na2 = configRef.current.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : ''; | ||
@@ -445,3 +453,3 @@ for (var field of form.elements) { | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usefieldlist | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist | ||
*/ | ||
@@ -502,3 +510,3 @@ function useFieldList(ref, config) { | ||
var control = new Proxy({}, { | ||
var command = new Proxy({}, { | ||
get(_target, type) { | ||
@@ -583,3 +591,4 @@ return function () { | ||
}, [ref]); | ||
return [list, control]; | ||
return [list, // @ts-expect-error proxy type | ||
command]; | ||
} | ||
@@ -592,3 +601,3 @@ | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usecontrolledinput | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput | ||
*/ | ||
@@ -595,0 +604,0 @@ function useControlledInput(config) { |
@@ -1,3 +0,3 @@ | ||
export { type FieldsetConstraint, type Submission, getFormError, hasError, isFieldElement, parse, shouldValidate, } from '@conform-to/dom'; | ||
export { type FieldsetConstraint, type Submission, getFormElements, hasError, parse, shouldValidate, } from '@conform-to/dom'; | ||
export * from './hooks'; | ||
export * as conform from './helpers'; |
@@ -11,5 +11,5 @@ 'use strict'; | ||
Object.defineProperty(exports, 'getFormError', { | ||
Object.defineProperty(exports, 'getFormElements', { | ||
enumerable: true, | ||
get: function () { return dom.getFormError; } | ||
get: function () { return dom.getFormElements; } | ||
}); | ||
@@ -20,6 +20,2 @@ Object.defineProperty(exports, 'hasError', { | ||
}); | ||
Object.defineProperty(exports, 'isFieldElement', { | ||
enumerable: true, | ||
get: function () { return dom.isFieldElement; } | ||
}); | ||
Object.defineProperty(exports, 'parse', { | ||
@@ -26,0 +22,0 @@ enumerable: true, |
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
import { getSubmissionType, setFormError, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, getFormError, hasError, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom'; | ||
import { getSubmissionType, setFormError, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, hasError, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom'; | ||
import { useRef, useState, useEffect } from 'react'; | ||
@@ -10,3 +10,3 @@ import { input } from './helpers.js'; | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#useform | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#useform | ||
*/ | ||
@@ -183,41 +183,46 @@ function useForm() { | ||
try { | ||
var submission; | ||
var formData = getFormData(form, submitter); | ||
var submission = parse(formData); | ||
var _context = { | ||
form, | ||
formData, | ||
submission | ||
}; // Touch all fields only if the submitter is not a command button | ||
if (submission.context === 'submit') { | ||
for (var field of form.elements) { | ||
if (isFieldElement(field)) { | ||
// Mark the field as touched | ||
field.dataset.conformTouched = 'true'; | ||
} | ||
} | ||
} | ||
var _error; | ||
if (typeof config.onValidate === 'function') { | ||
_error = config.onValidate(_context); | ||
submission = config.onValidate({ | ||
form, | ||
formData | ||
}); | ||
} else { | ||
submission = parse(formData); | ||
if (config.mode !== 'server-validation') { | ||
// Clear previous result | ||
/** | ||
* As there is no custom logic defined, | ||
* removing the custom validity state will allow us | ||
* finding the latest validation message. | ||
* | ||
* This is mainly used to showcase the constraint validation API. | ||
*/ | ||
setFormError(form, { | ||
context: 'submit', | ||
type: 'submit', | ||
value: {}, | ||
error: [] | ||
}); | ||
for (var _element of form.elements) { | ||
if (isFieldElement(_element) && _element.willValidate) { | ||
submission.error.push([_element.name, _element.validationMessage]); | ||
} | ||
} | ||
} | ||
} // Touch all fields only if the submitter is not a command button | ||
_error = getFormError(form); | ||
} | ||
if (_error.length > 0) { | ||
submission.error.push(..._error); | ||
if (submission.type === 'submit') { | ||
for (var field of form.elements) { | ||
if (isFieldElement(field)) { | ||
// Mark the field as touched | ||
field.dataset.conformTouched = 'true'; | ||
} | ||
} | ||
} | ||
if (!config.noValidate && !submitter.formNoValidate && hasError(submission.error) || submission.context === 'validate' && config.mode !== 'server-validation') { | ||
if (!config.noValidate && !submitter.formNoValidate && hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') { | ||
event.preventDefault(); | ||
@@ -227,3 +232,6 @@ } else { | ||
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, _context); | ||
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, { | ||
formData, | ||
submission | ||
}); | ||
} | ||
@@ -303,7 +311,7 @@ | ||
var invalidHandler = event => { | ||
var _configRef$current$na, _configRef$current; | ||
var _configRef$current$na; | ||
var form = getFormElement(ref.current); | ||
var field = event.target; | ||
var fieldsetName = (_configRef$current$na = (_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : ''; | ||
var fieldsetName = (_configRef$current$na = configRef.current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : ''; | ||
@@ -352,6 +360,6 @@ if (!form || !isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) { | ||
setError(prev => { | ||
var _configRef$current$na2, _configRef$current2; | ||
var _configRef$current$na2; | ||
var next = prev; | ||
var fieldsetName = (_configRef$current$na2 = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : ''; | ||
var fieldsetName = (_configRef$current$na2 = configRef.current.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : ''; | ||
@@ -441,3 +449,3 @@ for (var field of form.elements) { | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usefieldlist | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usefieldlist | ||
*/ | ||
@@ -498,3 +506,3 @@ function useFieldList(ref, config) { | ||
var control = new Proxy({}, { | ||
var command = new Proxy({}, { | ||
get(_target, type) { | ||
@@ -579,3 +587,4 @@ return function () { | ||
}, [ref]); | ||
return [list, control]; | ||
return [list, // @ts-expect-error proxy type | ||
command]; | ||
} | ||
@@ -588,3 +597,3 @@ | ||
* | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.2/packages/conform-react/README.md#usecontrolledinput | ||
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.3/packages/conform-react/README.md#usecontrolledinput | ||
*/ | ||
@@ -591,0 +600,0 @@ function useControlledInput(config) { |
@@ -1,4 +0,4 @@ | ||
export { getFormError, hasError, isFieldElement, parse, shouldValidate } from '@conform-to/dom'; | ||
export { getFormElements, hasError, parse, shouldValidate } from '@conform-to/dom'; | ||
export { useControlledInput, useFieldList, useFieldset, useForm } from './hooks.js'; | ||
import * as helpers from './helpers.js'; | ||
export { helpers as conform }; |
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "0.4.0-pre.2", | ||
"version": "0.4.0-pre.3", | ||
"main": "index.js", | ||
@@ -23,3 +23,3 @@ "module": "module/index.js", | ||
"dependencies": { | ||
"@conform-to/dom": "0.4.0-pre.2" | ||
"@conform-to/dom": "0.4.0-pre.3" | ||
}, | ||
@@ -26,0 +26,0 @@ "peerDependencies": { |
176
README.md
@@ -14,6 +14,5 @@ # @conform-to/react | ||
- [conform](#conform) | ||
- [getFormElements](#getformelements) | ||
- [hasError](#haserror) | ||
- [isFieldElement](#isfieldelement) | ||
- [parse](#parse) | ||
- [setFormError](#setformerror) | ||
- [shouldValidate](#shouldvalidate) | ||
@@ -300,29 +299,2 @@ | ||
<details> | ||
<summary>Is it required to provide the FieldsetConfig to `useFieldset`?</summary> | ||
No. The only thing required is the ref object. All the config is optional. You can always pass them to each fields manually. | ||
```tsx | ||
import { useForm, useFieldset } from '@conform-to/react'; | ||
function SubscriptionForm() { | ||
const formProps = useForm(); | ||
const { email } = useFieldset(formProps.ref); | ||
return ( | ||
<form {...formProps}> | ||
<input | ||
type="email" | ||
name={email.config.name} | ||
defaultValue="support@conform.dev" | ||
required | ||
/> | ||
</form> | ||
); | ||
} | ||
``` | ||
</details> | ||
<details> | ||
<summary>Why does `useFieldset` require a ref object of the form or fieldset?</summary> | ||
@@ -357,3 +329,3 @@ | ||
It returns a list of key and config, with a group of helpers configuring buttons for list manipulation | ||
It returns a list of key and config, with helpers to configure command buttons with [list command](/docs/submission.md#list-command). | ||
@@ -379,3 +351,3 @@ ```tsx | ||
const { books } = useFieldset<Collection>(ref); | ||
const [bookList, control] = useFieldList(ref, books.config); | ||
const [bookList, command] = useFieldList(ref, books.config); | ||
@@ -397,3 +369,3 @@ return ( | ||
{/* To setup a delete button */} | ||
<button {...control.remove({ index })}>Delete</button> | ||
<button {...command.remove({ index })}>Delete</button> | ||
</div> | ||
@@ -403,3 +375,3 @@ ))} | ||
{/* To setup a button that can append a new row with optional default value */} | ||
<button {...control.append({ defaultValue: { name: '', isbn: '' } })}> | ||
<button {...command.append({ defaultValue: { name: '', isbn: '' } })}> | ||
add | ||
@@ -421,3 +393,3 @@ </button> | ||
const { books } = useFieldset<Collection>(ref); | ||
const [bookList, control] = useFieldList(ref, books.config); | ||
const [bookList, command] = useFieldList(ref, books.config); | ||
@@ -432,3 +404,3 @@ return ( | ||
{/* To setup a delete button */} | ||
<button {...control.remove({ index })}>Delete</button> | ||
<button {...command.remove({ index })}>Delete</button> | ||
</div> | ||
@@ -438,3 +410,3 @@ ))} | ||
{/* To setup a button that can append a new row */} | ||
<button {...control.append()}>add</button> | ||
<button {...command.append()}>add</button> | ||
</fieldset> | ||
@@ -594,70 +566,39 @@ ); | ||
### hasError | ||
This helper checks if there is any message defined in error array with the provided name. | ||
```ts | ||
import { hasError } from '@conform-to/react'; | ||
/** | ||
* Assume the error looks like this: | ||
*/ | ||
const error = [['email', 'Email is required']]; | ||
// This will log `true` | ||
console.log(hasError(error, 'email')); | ||
// This will log `false` | ||
console.log(hasError(error, 'password')); | ||
``` | ||
--- | ||
### isFieldElement | ||
### getFormElements | ||
This checks if the provided element is an `input` / `select` / `textarea` or `button` HTML element with type guard. Useful when you need to access the validityState of the fields and modify the validation message manually. | ||
It returns all _input_ / _select_ / _textarea_ or _button_ in the forms. Useful when looping through the form elements to validate each field. | ||
```tsx | ||
import { isFieldElement } from '@conform-to/react'; | ||
import { useForm, parse, getFormElements } from '@conform-to/react'; | ||
export default function SignupForm() { | ||
export default function LoginForm() { | ||
const form = useForm({ | ||
onValidate({ form }) { | ||
for (const element of form.elements) { | ||
if (isFieldElement(element)) { | ||
switch (field.name) { | ||
case 'email': | ||
if (field.validity.valueMissing) { | ||
field.setCustomValidity('Email is required'); | ||
} else if (field.validity.typeMismatch) { | ||
field.setCustomValidity('Please enter a valid email'); | ||
} else { | ||
field.setCustomValidity(''); | ||
} | ||
break; | ||
case 'password': | ||
if (field.validity.valueMissing) { | ||
field.setCustomValidity('Password is required'); | ||
} else if (field.validity.tooShort) { | ||
field.setCustomValidity( | ||
'The password should be at least 10 characters long', | ||
); | ||
} else { | ||
field.setCustomValidity(''); | ||
} | ||
break; | ||
case 'confirm-password': { | ||
if (field.validity.valueMissing) { | ||
field.setCustomValidity('Confirm Password is required'); | ||
} else if (field.value !== formData.get('password')) { | ||
field.setCustomValidity('The password does not match'); | ||
} else { | ||
field.setCustomValidity(''); | ||
} | ||
break; | ||
onValidate({ form, formData }) { | ||
const submission = parse(formData); | ||
for (const element of getFormElements(form)) { | ||
switch (element.name) { | ||
case 'email': { | ||
if (element.validity.valueMissing) { | ||
submission.error.push([element.name, 'Email is required']); | ||
} else if (element.validity.typeMismatch) { | ||
submission.error.push([element.name, 'Email is invalid']); | ||
} | ||
break; | ||
} | ||
case 'password': { | ||
if (element.validity.valueMissing) { | ||
submission.error.push([element.name, 'Password is required']); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
return submission; | ||
}, | ||
// .... | ||
}); | ||
@@ -671,13 +612,19 @@ | ||
### parse | ||
### hasError | ||
It parses the formData based on the [naming convention](/docs/submission). | ||
This helper checks if there is any message defined in error array with the provided name. | ||
```tsx | ||
import { parse } from '@conform-to/react'; | ||
```ts | ||
import { hasError } from '@conform-to/react'; | ||
const formData = new FormData(formElement); | ||
const submission = parse(formData); | ||
/** | ||
* Assume the error looks like this: | ||
*/ | ||
const error = [['email', 'Email is required']]; | ||
console.log(submission); | ||
// This will log `true` | ||
console.log(hasError(error, 'email')); | ||
// This will log `false` | ||
console.log(hasError(error, 'password')); | ||
``` | ||
@@ -687,23 +634,13 @@ | ||
### setFormError | ||
### parse | ||
This helpers updates the form error based on the submission result by looping through all elements in the form and update the error with the [setCustomValidity](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setCustomValidity) API. | ||
It parses the formData based on the [naming convention](/docs/submission). | ||
```tsx | ||
import { setFormError } from '@conform-to/react'; | ||
import { parse } from '@conform-to/react'; | ||
function ExampleForm() { | ||
const form = useForm({ | ||
onValidate({ form, submission }) { | ||
const error = validate(submission); | ||
const formData = new FormData(); | ||
const submission = parse(formData); | ||
setFormError(form, { | ||
...submission, | ||
error, | ||
}); | ||
}, | ||
}); | ||
// ... | ||
} | ||
console.log(submission); | ||
``` | ||
@@ -721,10 +658,9 @@ | ||
/** | ||
* The submission type and metadata give us hint on what should be valdiated. | ||
* The submission type and intent give us hint on what should be valdiated. | ||
* If the type is 'validate', only the field with name matching the metadata must be validated. | ||
* | ||
* However, if the type is `undefined`, both will log true (Default submission) | ||
* If the type is 'submit', everything should be validated (Default submission) | ||
*/ | ||
const submission = { | ||
type: 'validate', | ||
metadata: 'email', | ||
context: 'validate', | ||
intent: 'email', | ||
value: {}, | ||
@@ -731,0 +667,0 @@ error: [], |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1549
78925
663
+ Added@conform-to/dom@0.4.0-pre.3(transitive)
- Removed@conform-to/dom@0.4.0-pre.2(transitive)
Updated@conform-to/dom@0.4.0-pre.3