Skip to content

Commit 553d7be

Browse files
committed
Allow rules to be a single rule
1 parent 16e673e commit 553d7be

File tree

10 files changed

+72
-30
lines changed

10 files changed

+72
-30
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ It just needs to support a `handleChange` `handleBlur` and `value` prop. This is
5050

5151
```js
5252
import React from "react";
53-
import { useField, UseFieldProps } from "react-validify";
53+
import { useField, FieldProps } from "react-validify";
5454

55-
const Input = ({ name, rules }: UseFieldProps) => {
55+
type Props = { placeholder: string } & FieldProps;
56+
57+
const Input = ({ name, rules, placeholder }: Props) => {
5658
let { handleChange, handleBlur, value, errors } = useField({ name, rules });
5759

5860
return (
@@ -62,6 +64,7 @@ const Input = ({ name, rules }: UseFieldProps) => {
6264
name={name}
6365
value={value}
6466
onBlur={handleBlur}
67+
placeholder={placeholder}
6568
onChange={(event) => handleChange(event.target.value)}
6669
/>
6770
</div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-validify",
3-
"version": "6.0.4",
3+
"version": "6.1.0",
44
"description": "Form validation made easy",
55
"main": "dist/index.js",
66
"module": "lib/index.js",

src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Form } from "./form";
1+
export * from "./form";
2+
export * from "./use-field";
3+
export * from "./use-submit";
24
import * as rules from "./rules";
3-
import useField from "./use-field";
4-
import useSubmit from "./use-submit";
55

6-
export { Form, useField, useSubmit, rules };
6+
export { rules };

src/rules.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
export type RuleFn = (
22
value: string,
3-
values: { [key: string]: string },
3+
values: { [key: string]: string }
44
) => string | boolean | undefined | null;
55

6+
export type RuleFns = RuleFn | RuleFn[];
7+
68
// Taken from Stackoverflow
7-
export const email: RuleFn = value => {
9+
export const email: RuleFn = (value) => {
810
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
9-
if (!re.test(String(value).toLowerCase())) return 'Email address is invalid';
11+
if (!re.test(String(value).toLowerCase())) return "Email address is invalid";
1012
};
1113

12-
export const required: RuleFn = value =>
13-
!value || !value.toString().length ? 'This field is required' : null;
14+
export const required: RuleFn = (value) =>
15+
!value || !value.toString().length ? "This field is required" : null;

src/use-field.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import get from "lodash/get";
33
import set from "lodash/set";
44
import validate from "./validate";
55
import { FormContext } from "./form";
6-
import { RuleFn } from "rules";
6+
import { RuleFns } from "rules";
77

8-
export type UseFieldProps = {
8+
export type FieldProps = {
99
name: string;
10-
rules?: RuleFn[];
10+
rules?: RuleFns;
1111
};
1212

13-
const useField = ({ name, rules: fieldRules }: UseFieldProps) => {
13+
export const useField = ({ name, rules: fieldRules }: FieldProps) => {
1414
const {
1515
errors,
1616
values,
@@ -23,7 +23,13 @@ const useField = ({ name, rules: fieldRules }: UseFieldProps) => {
2323

2424
//set the rules when they change, clear when unmounted
2525
useEffect(() => {
26-
rules.current[name] = fieldRules || [];
26+
//This check lets us pass in a single rule without making an array, or an array of rules
27+
if (Array.isArray(fieldRules)) {
28+
rules.current[name] = fieldRules;
29+
} else {
30+
rules.current[name] = fieldRules ? [fieldRules] : [];
31+
}
32+
2733
return () => {
2834
rules.current[name] = [];
2935
};
@@ -86,5 +92,3 @@ const useField = ({ name, rules: fieldRules }: UseFieldProps) => {
8692
errors: fieldErrors.length ? fieldErrors : null,
8793
};
8894
};
89-
90-
export default useField;

src/use-submit.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react";
22
import validate from "./validate";
33
import { FormContext } from "./form";
44

5-
const useSubmit = () => {
5+
export const useSubmit = () => {
66
const {
77
rules,
88
values,
@@ -36,5 +36,3 @@ const useSubmit = () => {
3636
canSubmit: !errors.length,
3737
};
3838
};
39-
40-
export default useSubmit;

src/validate.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import get from "lodash/get";
22
import { Dispatch, MutableRefObject, SetStateAction } from "react";
33
import { Error, RulesRef } from "./form";
4-
import { RuleFn } from "rules";
54

65
type Props = {
76
values: any;

tests/form.test.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import React from "react";
22
import { render, fireEvent, wait, act } from "@testing-library/react";
3-
import { TestForm, TestFormWithRemovedField } from "./helpers/form";
3+
import {
4+
TestForm,
5+
TestFormWithRemovedField,
6+
TestFormWithSingleRule,
7+
} from "./helpers/form";
48

59
test("Checks dependent rule", async () => {
610
let errorMessage = "Must be longer value than date 2 field";
@@ -210,3 +214,19 @@ test(`Doesnt check rule after component is unmounted`, async () => {
210214
//it should call submit even though email is empty, because it was unmounted
211215
expect(spy.mock.calls[0][0].email).toEqual("");
212216
});
217+
218+
test(`Passing in single rule without array works correctly`, () => {
219+
let { queryByPlaceholderText, queryByText } = render(
220+
<TestFormWithSingleRule />
221+
);
222+
const email = queryByPlaceholderText("email");
223+
224+
fireEvent.focus(email);
225+
fireEvent.change(email, { target: { value: "testtesst.com" } });
226+
fireEvent.blur(email);
227+
228+
expect(queryByText("Email address is invalid")).toBeTruthy();
229+
fireEvent.change(email, { target: { value: "[email protected]" } });
230+
fireEvent.blur(email);
231+
expect(queryByText("Email address is invalid")).toBeNull();
232+
});

tests/helpers/form.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,20 @@ export const TestFormWithRemovedField = (props: Props) => {
5555

5656
return <TestForm {...props} unmountEmail={unmountEmail} />;
5757
};
58+
59+
export const TestFormWithSingleRule = ({
60+
onSubmit,
61+
noRules,
62+
nameRule,
63+
unmountEmail,
64+
}: Props) => {
65+
let [values, setValues] = useState<TestValues>({ email: "test" });
66+
67+
return (
68+
<Form values={values} onValues={setValues}>
69+
<Input name="email" rules={email} />
70+
71+
<Submit onSubmit={onSubmit} />
72+
</Form>
73+
);
74+
};

tests/helpers/input.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import React from "react";
2-
import useField from "../../src/use-field";
2+
import useField, { FieldProps } from "../../src/use-field";
33

4-
const Input = (props) => {
4+
const Input = ({ name, rules }: FieldProps) => {
55
let { handleChange, handleBlur, value, errors } = useField({
6-
name: props.name,
7-
rules: props.rules,
6+
name,
7+
rules,
88
});
99
return (
1010
<div>
1111
{errors ? <p>{errors[0]}</p> : null}
1212
<input
13-
{...props}
1413
value={value || ""}
1514
onBlur={handleBlur}
16-
placeholder={props.name}
15+
placeholder={name}
1716
onChange={(event) => handleChange(event.target.value)}
1817
/>
1918
</div>

0 commit comments

Comments
 (0)