@shopify/react-form-state
Advanced tools
Comparing version 0.9.1 to 0.10.0
@@ -7,2 +7,10 @@ # Changelog | ||
<!-- ## Unreleased --> | ||
## [0.10.0] | ||
### Changed | ||
- when `validateOnSubmit` is enabled, validation errors are surfaced on the form's `errors`. [#601](https://github.com/Shopify/quilt/pull/601) | ||
## [0.9.1] | ||
@@ -9,0 +17,0 @@ |
@@ -63,2 +63,3 @@ import * as React from 'react'; | ||
private readonly hasClientErrors; | ||
private readonly clientErrors; | ||
private readonly fields; | ||
@@ -65,0 +66,0 @@ private submit; |
@@ -23,3 +23,3 @@ "use strict"; | ||
_this.submit = function (event) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var _a, onSubmit, validateOnSubmit, formData, errors; | ||
var _a, onSubmit, validateOnSubmit, formData, clientErrors, errors; | ||
return tslib_1.__generator(this, function (_b) { | ||
@@ -44,4 +44,5 @@ switch (_b.label) { | ||
_b.sent(); | ||
if (this.hasClientErrors) { | ||
this.setState({ submitting: false }); | ||
clientErrors = this.clientErrors; | ||
if (clientErrors.length > 0) { | ||
this.setState({ submitting: false, errors: clientErrors }); | ||
return [2 /*return*/]; | ||
@@ -165,2 +166,13 @@ } | ||
}); | ||
Object.defineProperty(FormState.prototype, "clientErrors", { | ||
get: function () { | ||
var fields = this.state.fields; | ||
return utilities_1.flatMap(Object.values(fields), function (_a) { | ||
var error = _a.error; | ||
return collectErrors(error); | ||
}); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(FormState.prototype, "fields", { | ||
@@ -357,1 +369,15 @@ get: function () { | ||
} | ||
function collectErrors(message) { | ||
if (!message) { | ||
return []; | ||
} | ||
if (typeof message === 'string') { | ||
return [{ message: message }]; | ||
} | ||
if (Array.isArray(message)) { | ||
return utilities_1.flatMap(message, function (itemError) { return collectErrors(itemError); }); | ||
} | ||
return utilities_1.flatMap(Object.values(message), function (nestedError) { | ||
return collectErrors(nestedError); | ||
}); | ||
} |
@@ -8,1 +8,2 @@ import isEqual from 'fast-deep-equal'; | ||
export declare function set<InputType extends Object>(rootObject: InputType, path: string[], value: any): any; | ||
export declare function flatMap<T>(array: any[], mapper: (item: any, index?: number) => T | T[]): T[]; |
@@ -49,1 +49,5 @@ "use strict"; | ||
exports.set = set; | ||
function flatMap(array, mapper) { | ||
return array.reduce(function (acc, item, index) { return acc.concat(mapper(item, index)); }, []); | ||
} | ||
exports.flatMap = flatMap; |
@@ -360,6 +360,6 @@ # Building forms with FormState | ||
You can configure `<FormState />` to run all validators on the form before executing `onSubmit` by passing it the `validateOnSubmit` prop. If any of the validators return an error, the submit is cancelled and `onSubmit` is not run. | ||
You can configure `<FormState />` to run all validators on the form before executing `onSubmit` by passing it the `validateOnSubmit` prop. If any of the validators return an error, the submit is cancelled and `onSubmit` is not run. Any errors discovered will be available on the `errors` object. | ||
```typescript | ||
import {TextField, Form, Button} from '@shopify/polaris'; | ||
import {Banner, Button, ExceptionList, Form, TextField} from '@shopify/polaris'; | ||
import FormState, {validators} from '@shopify/react-form-state'; | ||
@@ -386,9 +386,20 @@ | ||
{formDetails => { | ||
const {fields, submit} = formDetails; | ||
const {errors, fields, submit} = formDetails; | ||
const errorBanner = Boolean(errors.length) && ( | ||
<Banner status="critical" title={`${errors.length} Errors`}> | ||
<ExceptionList | ||
items={errors.map(({message: description}) => ({description}))} | ||
/> | ||
</Banner> | ||
); | ||
return ( | ||
<Form onSubmit={submit}> | ||
<TextField label="Title" {...fields.title} /> | ||
<Button type="submit">Submit</Button> | ||
</Form> | ||
<> | ||
{errorBanner} | ||
<Form onSubmit={submit}> | ||
<TextField label="Title" {...fields.title} /> | ||
<Button type="submit">Submit</Button> | ||
</Form> | ||
</> | ||
); | ||
@@ -401,2 +412,4 @@ }} | ||
In addition to being propagated down to their respective `fields`, these client-side validation errors can be accessed together at the top level via the `errors` array, in the same way as your remote errors (returned from `onSubmit`) and external errors (see below). | ||
To learn more about building validators, and the built in functions exposed by this package, check out the [validators guide](validators.md). | ||
@@ -403,0 +416,0 @@ |
{ | ||
"name": "@shopify/react-form-state", | ||
"version": "0.9.1", | ||
"version": "0.10.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "description": "Manage react forms tersely and type-safe with no magic.", |
/* eslint-disable no-case-declarations */ | ||
import * as React from 'react'; | ||
import {mapObject, set, isEqual} from './utilities'; | ||
import {mapObject, set, isEqual, flatMap} from './utilities'; | ||
import { | ||
@@ -188,2 +188,8 @@ FieldDescriptors, | ||
private get clientErrors() { | ||
const {fields} = this.state; | ||
return flatMap(Object.values(fields), ({error}) => collectErrors(error)); | ||
} | ||
private get fields() { | ||
@@ -220,4 +226,6 @@ const {fields} = this.state; | ||
if (this.hasClientErrors) { | ||
this.setState({submitting: false}); | ||
const clientErrors = this.clientErrors; | ||
if (clientErrors.length > 0) { | ||
this.setState({submitting: false, errors: clientErrors}); | ||
return; | ||
@@ -533,1 +541,21 @@ } | ||
} | ||
function collectErrors( | ||
message: string | any[] | {} | undefined, | ||
): RemoteError[] { | ||
if (!message) { | ||
return []; | ||
} | ||
if (typeof message === 'string') { | ||
return [{message}]; | ||
} | ||
if (Array.isArray(message)) { | ||
return flatMap(message, itemError => collectErrors(itemError)); | ||
} | ||
return flatMap(Object.values(message), nestedError => | ||
collectErrors(nestedError), | ||
); | ||
} |
@@ -53,1 +53,11 @@ import isEqual from 'fast-deep-equal'; | ||
} | ||
export function flatMap<T>( | ||
array: any[], | ||
mapper: (item: any, index?: number) => T | T[], | ||
): T[] { | ||
return array.reduce( | ||
(acc, item, index) => acc.concat(mapper(item, index)), | ||
[], | ||
); | ||
} |
Sorry, the diff of this file is not supported yet
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
192615
4232