Skip to content

Commit

Permalink
[@mantine/form] Add superstruct support (#2957)
Browse files Browse the repository at this point in the history
* [@mantine/form] Add superstruct support

* fix code style issues

* [@mantine/form] update README

add superstruct to the list of supported validation libraries

* [@mantine/demos] add superstructResolver demo

Co-authored-by: Dmitry Shvetsov <d24v@Dmitrys-MacBook-Pro.local>
  • Loading branch information
dmshvetsov and Dmitry Shvetsov committed Dec 17, 2022
1 parent 4076d7f commit 41fed0c
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 1 deletion.
11 changes: 10 additions & 1 deletion docs/src/docs/form/validation.mdx
Expand Up @@ -60,7 +60,12 @@ from the validation results.

## Schema based validation

`@mantine/form` supports schema validation with [zod](https://www.npmjs.com/package/zod), [joi](https://www.npmjs.com/package/joi) and [yup](https://www.npmjs.com/package/yup) out of the box.
Out of the box `@mantine/form` supports schema validation with:
- [zod](https://www.npmjs.com/package/zod)
- [joi](https://www.npmjs.com/package/joi)
- [yup](https://www.npmjs.com/package/yup)
- [superstruct](https://www.npmjs.com/package/superstruct)

You will need to install one of the libraries yourself, as `@mantine/form` package does not depend on any of them.
If you do not know what validation library to choose, we recommend choosing [zod](https://www.npmjs.com/package/zod)
as the most modern and developer-friendly library.
Expand All @@ -77,6 +82,10 @@ as the most modern and developer-friendly library.

<Demo data={FormDemos.yup} demoProps={{ toggle: true }} />

### superstruct

<Demo data={FormDemos.superstruct} demoProps={{ toggle: true }} />

## Validate fields on change

To validate all fields on change set `validateInputOnChange` option to `true`:
Expand Down
65 changes: 65 additions & 0 deletions src/mantine-demos/src/demos/form/Form.demo.superstruct.tsx
@@ -0,0 +1,65 @@
/* eslint-disable no-console */
import { MantineDemo } from '@mantine/ds';
import { SchemaBase } from './_schema-base';

const code = `
import { useForm, superstructResolver } from '@mantine/form';
import { NumberInput, TextInput, Button, Box, Group } from '@mantine/core';
import * as s from 'superstruct';
import isEmail from 'is-email';
const emailString = s.define('email', isEmail);
const schema = s.object({
name: s.size(s.string(), 2, 30),
email: emailString,
age: s.min(s.number(), 18)
});
function Demo() {
const form = useForm({
validate: superstructResolver(schema),
initialValues: {
name: '',
email: '',
age: 18
}
});
return (
<Box sx={{ maxWidth: 340 }} mx="auto">
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
withAsterisk
label="Email"
placeholder="example@mail.com"
{...form.getInputProps('email')}
/>
<TextInput
withAsterisk
label="Name"
placeholder="John Doe"
mt="sm"
{...form.getInputProps('name')}
/>
<NumberInput
withAsterisk
label="Age"
placeholder="Your age"
mt="sm"
{...form.getInputProps('age')}
/>
<Group position="right" mt="xl">
<Button type="submit">Submit</Button>
</Group>
</form>
</Box>
);
}
`;

export const superstruct: MantineDemo = {
type: 'demo',
component: SchemaBase,
code,
};
1 change: 1 addition & 0 deletions src/mantine-form/src/index.ts
Expand Up @@ -4,6 +4,7 @@ export { FORM_INDEX } from './form-index';
export * from './validators';

export { zodResolver } from './resolvers/zod-resolver/zod-resolver';
export { superstructResolver } from './resolvers/superstruct-resolver/superstruct-resolver';
export { yupResolver } from './resolvers/yup-resolver/yup-resolver';
export { joiResolver } from './resolvers/joi-resolver/joi-resolver';

Expand Down
@@ -0,0 +1,36 @@
import type { FormErrors } from '../../types';

type StructFailure = {
value: any;
key: any;
type: string;
refinement: string | undefined;
message: string;
explanation?: string;
branch: Array<any>;
path: Array<any>;
};

type StructValidaationError = {
failures: () => Array<StructFailure>;
};

export function superstructResolver(schema: any) {
function structValidation(values: Record<string, any>): FormErrors {
const formErrors: FormErrors = {};

const [err]: [StructValidaationError | null, unknown] = schema.validate(values);
if (!err) {
return formErrors;
}

err.failures().forEach((fieldFailure) => {
const fieldName = fieldFailure.path.join(' ');
formErrors[fieldFailure.path.join('.')] = `${fieldName}: ${fieldFailure.message}`;
});

return formErrors;
}

return structValidation;
}

0 comments on commit 41fed0c

Please sign in to comment.