@coxy/react-validator 2.0.4 → 2.0.5

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/.eslintrc.js CHANGED
@@ -1,7 +1,5 @@
1
1
  module.exports = {
2
2
  root: true,
3
3
  parser: '@typescript-eslint/parser',
4
- extends: [
5
- '@coxy/eslint-config/react'
6
- ]
4
+ extends: ['@coxy/eslint-config/react', 'plugin:prettier/recommended'],
7
5
  }
package/.prettierrc.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ singleQuote: true,
3
+ trailingComma: 'all',
4
+ arrowParens: 'always',
5
+ semi: false,
6
+ bracketSpacing: true,
7
+ tabWidth: 2,
8
+ printWidth: 120,
9
+ jsxSingleQuote: true,
10
+ }
package/dist/context.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /// <reference types="react" />
2
+ import { Validity } from './types';
2
3
  export declare const Context: import("react").Context<{
3
4
  registerField: (field: string | number) => void;
4
5
  unregisterField: (field: string | number) => void;
6
+ customErrors: Array<Validity>;
5
7
  }>;
package/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export { ValidatorField } from './validator-field';
3
3
  export { ValidatorWrapper } from './validator-wrapper';
4
4
  export { Validator } from './validator';
5
5
  export { useValidator } from './use-validator';
6
+ export * from './types';
package/dist/index.js CHANGED
@@ -1,4 +1,18 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
17
  exports.useValidator = exports.Validator = exports.ValidatorWrapper = exports.ValidatorField = exports.rules = void 0;
4
18
  var rules_1 = require("./rules");
@@ -11,3 +25,4 @@ var validator_1 = require("./validator");
11
25
  Object.defineProperty(exports, "Validator", { enumerable: true, get: function () { return validator_1.Validator; } });
12
26
  var use_validator_1 = require("./use-validator");
13
27
  Object.defineProperty(exports, "useValidator", { enumerable: true, get: function () { return use_validator_1.useValidator; } });
28
+ __exportStar(require("./types"), exports);
package/dist/rules.d.ts CHANGED
@@ -1,10 +1,5 @@
1
- import { Value } from './validator-field';
2
- declare type Fn = (value: Value) => string;
3
- export interface RuleInstance {
4
- rule: (value: Value) => boolean;
5
- message: string | Fn;
6
- }
7
- export declare type ValidatorRules = RuleInstance[];
1
+ import { ValidatorRule } from './types';
2
+ export declare type ValidatorRules = ValidatorRule[];
8
3
  export declare const rules: {
9
4
  notEmpty: {
10
5
  rule: (value: any) => boolean;
@@ -35,4 +30,3 @@ export declare const rules: {
35
30
  message: string;
36
31
  }[];
37
32
  };
38
- export {};
package/dist/rules.js CHANGED
@@ -3,41 +3,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rules = void 0;
4
4
  const emailReg = /^(([^<>()\[\]\\.,;:\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,}))$/;
5
5
  exports.rules = {
6
- notEmpty: [{
6
+ notEmpty: [
7
+ {
7
8
  rule: (value) => value !== '' && value.length > 0,
8
- message: 'Value is required'
9
- }],
10
- bool: [{
9
+ message: 'Value is required',
10
+ },
11
+ ],
12
+ bool: [
13
+ {
11
14
  rule: (value) => !!value,
12
- message: 'Value is required'
13
- }],
14
- password: [{
15
+ message: 'Value is required',
16
+ },
17
+ ],
18
+ password: [
19
+ {
15
20
  rule: (value) => value.length > 0,
16
- message: 'Password field cannot be empty'
17
- }, {
21
+ message: 'Password field cannot be empty',
22
+ },
23
+ {
18
24
  rule: (value) => value.length > 5,
19
- message: 'Password field can not be less than 6 characters'
20
- }],
21
- email: [{
25
+ message: 'Password field can not be less than 6 characters',
26
+ },
27
+ ],
28
+ email: [
29
+ {
22
30
  rule: (value) => !!value && value !== '' && value.length !== 0,
23
- message: 'Email is required'
24
- }, {
31
+ message: 'Email is required',
32
+ },
33
+ {
25
34
  rule: (value) => emailReg.test(String(value).toLowerCase()),
26
- message: 'Email is invalid'
27
- }],
28
- min: (min) => [{
35
+ message: 'Email is invalid',
36
+ },
37
+ ],
38
+ min: (min) => [
39
+ {
29
40
  rule: (value) => parseFloat(value) > min,
30
- message: `The value must be greater than ${min}`
31
- }],
32
- max: (max) => [{
41
+ message: `The value must be greater than ${min}`,
42
+ },
43
+ ],
44
+ max: (max) => [
45
+ {
33
46
  rule: (value) => parseFloat(value) < max,
34
- message: `The value must be smaller ${max}`
35
- }],
36
- length: (min, max) => [{
47
+ message: `The value must be smaller ${max}`,
48
+ },
49
+ ],
50
+ length: (min, max) => [
51
+ {
37
52
  rule: (value) => String(value).length >= min,
38
- message: `No less than ${min} symbols`
39
- }, {
53
+ message: `No less than ${min} symbols`,
54
+ },
55
+ {
40
56
  rule: (value) => (max !== undefined ? String(value).length <= max : true),
41
- message: `No more than ${max} symbols`
42
- }]
57
+ message: `No more than ${max} symbols`,
58
+ },
59
+ ],
43
60
  };
@@ -0,0 +1,24 @@
1
+ import { ValidatorRules } from './rules';
2
+ import { Value } from './validator-field';
3
+ declare type Fn = (value: Value) => string;
4
+ export interface ValidatorRule {
5
+ rule: (value: Value) => boolean;
6
+ message: string | Fn;
7
+ }
8
+ export interface ErrorMessage {
9
+ message: string;
10
+ isValid: boolean;
11
+ }
12
+ export interface Validity {
13
+ message: string;
14
+ isValid: boolean;
15
+ errors?: ErrorMessage[];
16
+ id?: string | number;
17
+ }
18
+ export interface FieldParams {
19
+ value: Value;
20
+ rules: ValidatorRules;
21
+ required?: boolean;
22
+ id?: string | number;
23
+ }
24
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,4 @@
1
1
  import { ValidatorRules } from './rules';
2
- import { Validity, Value } from './validator-field';
2
+ import { Value } from './validator-field';
3
+ import { Validity } from './types';
3
4
  export declare function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>];
@@ -1,16 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
+ import { Validity } from 'types';
2
3
  import { ValidatorRules } from './rules';
3
4
  export declare type Value = any;
4
- export interface ErrorMessage {
5
- message: string;
6
- isValid: boolean;
7
- }
8
- export interface Validity {
9
- message: string;
10
- isValid: boolean;
11
- errors?: ErrorMessage[];
12
- id?: string | number;
13
- }
14
5
  declare type Fn = (validity: Validity, value: Value) => ReactNode;
15
6
  interface Props {
16
7
  rules?: ValidatorRules;
@@ -20,6 +11,7 @@ interface Props {
20
11
  children?: ReactNode | Fn;
21
12
  unregisterField: (val: any) => void;
22
13
  registerField: (val: any) => void;
14
+ customErrors: Array<Validity>;
23
15
  }
24
- export declare function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField'>): JSX.Element;
16
+ export declare function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>): JSX.Element;
25
17
  export {};
@@ -13,21 +13,26 @@ class ValidationFieldWrapper extends react_1.Component {
13
13
  this.props.registerField(this);
14
14
  }
15
15
  validate() {
16
+ const props = this.props;
17
+ const customError = props.customErrors.find((item) => item.id === props.id);
18
+ if (customError) {
19
+ return customError;
20
+ }
16
21
  const field = new validator_1.Field({
17
- rules: this.props.rules,
18
- required: this.props.required,
19
- value: this.props.value,
20
- id: this.props.id
22
+ rules: props.rules,
23
+ required: props.required,
24
+ value: props.value,
25
+ id: props.id,
21
26
  });
22
27
  return field.validate();
23
28
  }
24
29
  render() {
25
30
  const { children, value } = this.props;
26
31
  const validity = this.validate();
27
- return (typeof children === 'function' ? children(validity, value) : children);
32
+ return typeof children === 'function' ? children(validity, value) : children;
28
33
  }
29
34
  }
30
35
  function ValidatorField(props) {
31
- return ((0, jsx_runtime_1.jsx)(context_1.Context.Consumer, { children: (data) => ((0, jsx_runtime_1.jsx)(ValidationFieldWrapper, Object.assign({}, props, { registerField: data.registerField, unregisterField: data.unregisterField }))) }));
36
+ return ((0, jsx_runtime_1.jsx)(context_1.Context.Consumer, { children: (data) => ((0, jsx_runtime_1.jsx)(ValidationFieldWrapper, Object.assign({}, props, { customErrors: data.customErrors, registerField: data.registerField, unregisterField: data.unregisterField }))) }));
32
37
  }
33
38
  exports.ValidatorField = ValidatorField;
@@ -1,4 +1,6 @@
1
1
  import { Component, ReactNode, RefObject } from 'react';
2
+ import { Validity } from './types';
3
+ import { Field } from './validator';
2
4
  interface ComponentProps {
3
5
  children?: ReactNode;
4
6
  stopAtFirstError?: boolean;
@@ -6,12 +8,17 @@ interface ComponentProps {
6
8
  }
7
9
  export declare class ValidatorWrapper extends Component<ComponentProps> {
8
10
  fields: any[];
11
+ state: {
12
+ customErrors: any[];
13
+ };
9
14
  constructor(props: any, ctx: any);
10
15
  componentWillUnmount(): void;
11
16
  registerField(field: any): void;
12
17
  unregisterField(field: any): void;
13
- getField(id: any): any;
14
- validate(): import("./validator-field").Validity;
18
+ getField(id: any): Field | null;
19
+ setCustomError(customError: Validity): void;
20
+ clearCustomErrors(): void;
21
+ validate(): Validity;
15
22
  render(): JSX.Element;
16
23
  }
17
24
  export {};
@@ -9,6 +9,9 @@ class ValidatorWrapper extends react_1.Component {
9
9
  constructor(props, ctx) {
10
10
  super(props, ctx);
11
11
  this.fields = [];
12
+ this.state = {
13
+ customErrors: [],
14
+ };
12
15
  this.registerField = this.registerField.bind(this);
13
16
  this.unregisterField = this.unregisterField.bind(this);
14
17
  }
@@ -28,6 +31,14 @@ class ValidatorWrapper extends react_1.Component {
28
31
  getField(id) {
29
32
  return this.fields.find((field) => field.props.id === id) || null;
30
33
  }
34
+ setCustomError(customError) {
35
+ this.setState({
36
+ customErrors: [...this.state.customErrors, customError],
37
+ });
38
+ }
39
+ clearCustomErrors() {
40
+ this.setState({ customErrors: [] });
41
+ }
31
42
  validate() {
32
43
  const validator = new validator_1.Validator({ stopAtFirstError: this.props.stopAtFirstError });
33
44
  this.fields.forEach((comp) => {
@@ -36,7 +47,11 @@ class ValidatorWrapper extends react_1.Component {
36
47
  return validator.validate();
37
48
  }
38
49
  render() {
39
- return ((0, jsx_runtime_1.jsx)(context_1.Context.Provider, Object.assign({ value: { registerField: this.registerField, unregisterField: this.unregisterField } }, { children: this.props.children })));
50
+ return ((0, jsx_runtime_1.jsx)(context_1.Context.Provider, Object.assign({ value: {
51
+ customErrors: this.state.customErrors,
52
+ registerField: this.registerField,
53
+ unregisterField: this.unregisterField,
54
+ } }, { children: this.props.children })));
40
55
  }
41
56
  }
42
57
  exports.ValidatorWrapper = ValidatorWrapper;
@@ -1,11 +1,4 @@
1
- import { Validity, Value } from './validator-field';
2
- import { ValidatorRules } from './rules';
3
- export interface FieldParams {
4
- value: Value;
5
- rules: ValidatorRules;
6
- required?: boolean;
7
- id?: string | number;
8
- }
1
+ import { FieldParams, Validity } from './types';
9
2
  export declare class Field {
10
3
  private rules;
11
4
  private required;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coxy/react-validator",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "🚀 Simple validation form for React or NodeJS apps. useValidator are included ;)",
5
5
  "main": "./dist/index.js",
6
6
  "repository": {
@@ -45,14 +45,17 @@
45
45
  "coveralls": "3.1.1",
46
46
  "eslint": "8.25.0",
47
47
  "eslint-config-standard": "17.0.0",
48
+ "eslint-config-prettier": "8.8.0",
48
49
  "eslint-plugin-import": "2.26.0",
49
50
  "eslint-plugin-jsx-a11y": "6.6.1",
50
51
  "eslint-plugin-n": "15.3.0",
51
52
  "eslint-plugin-promise": "6.0.1",
52
53
  "eslint-plugin-filename-rules": "1.2.0",
53
54
  "eslint-plugin-react": "7.31.8",
55
+ "eslint-plugin-prettier": "4.2.1",
54
56
  "jest": "29.1.2",
55
57
  "jest-environment-jsdom": "29.1.2",
58
+ "prettier": "2.8.7",
56
59
  "react-dom": "18.2.0",
57
60
  "react-test-renderer": "18.2.0",
58
61
  "ts-jest": "29.0.3",
package/src/context.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { createContext } from 'react'
2
2
 
3
+ import { Validity } from './types'
4
+
3
5
  export const Context = createContext<{
4
- registerField:(field: string | number) => void,
5
- unregisterField:(field: string | number) => void
6
- }>(null)
6
+ registerField: (field: string | number) => void
7
+ unregisterField: (field: string | number) => void
8
+ customErrors: Array<Validity>
9
+ }>(null)
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export { ValidatorField } from './validator-field'
3
3
  export { ValidatorWrapper } from './validator-wrapper'
4
4
  export { Validator } from './validator'
5
5
  export { useValidator } from './use-validator'
6
+ export * from './types'
package/src/rules.ts CHANGED
@@ -1,59 +1,70 @@
1
- import { Value } from './validator-field'
1
+ import { ValidatorRule } from './types'
2
2
 
3
3
  // eslint-disable-next-line
4
- const emailReg = /^(([^<>()\[\]\\.,;:\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,}))$/
4
+ const emailReg =
5
+ /^(([^<>()\[\]\\.,;:\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,}))$/
5
6
 
6
- type Fn = (value: Value) => string
7
+ export type ValidatorRules = ValidatorRule[]
7
8
 
8
- export interface RuleInstance {
9
- rule: (value: Value) => boolean
10
- message: string | Fn
11
- }
9
+ export const rules = {
10
+ notEmpty: [
11
+ {
12
+ rule: (value) => value !== '' && value.length > 0,
13
+ message: 'Value is required',
14
+ },
15
+ ],
12
16
 
13
- export type ValidatorRules = RuleInstance[]
17
+ bool: [
18
+ {
19
+ rule: (value) => !!value,
20
+ message: 'Value is required',
21
+ },
22
+ ],
14
23
 
15
- export const rules = {
16
- notEmpty: [{
17
- rule: (value) => value !== '' && value.length > 0,
18
- message: 'Value is required'
19
- }],
20
-
21
- bool: [{
22
- rule: (value) => !!value,
23
- message: 'Value is required'
24
- }],
25
-
26
- password: [{
27
- rule: (value) => value.length > 0,
28
- message: 'Password field cannot be empty'
29
- }, {
30
- rule: (value) => value.length > 5,
31
- message: 'Password field can not be less than 6 characters'
32
- }],
33
-
34
- email: [{
35
- rule: (value) => !!value && value !== '' && value.length !== 0,
36
- message: 'Email is required'
37
- }, {
38
- rule: (value) => emailReg.test(String(value).toLowerCase()),
39
- message: 'Email is invalid'
40
- }],
41
-
42
- min: (min) => [{
43
- rule: (value) => parseFloat(value) > min,
44
- message: `The value must be greater than ${min}`
45
- }],
46
-
47
- max: (max) => [{
48
- rule: (value) => parseFloat(value) < max,
49
- message: `The value must be smaller ${max}`
50
- }],
51
-
52
- length: (min, max?) => [{
53
- rule: (value) => String(value).length >= min,
54
- message: `No less than ${min} symbols`
55
- }, {
56
- rule: (value) => (max !== undefined ? String(value).length <= max : true),
57
- message: `No more than ${max} symbols`
58
- }]
24
+ password: [
25
+ {
26
+ rule: (value) => value.length > 0,
27
+ message: 'Password field cannot be empty',
28
+ },
29
+ {
30
+ rule: (value) => value.length > 5,
31
+ message: 'Password field can not be less than 6 characters',
32
+ },
33
+ ],
34
+
35
+ email: [
36
+ {
37
+ rule: (value) => !!value && value !== '' && value.length !== 0,
38
+ message: 'Email is required',
39
+ },
40
+ {
41
+ rule: (value) => emailReg.test(String(value).toLowerCase()),
42
+ message: 'Email is invalid',
43
+ },
44
+ ],
45
+
46
+ min: (min) => [
47
+ {
48
+ rule: (value) => parseFloat(value) > min,
49
+ message: `The value must be greater than ${min}`,
50
+ },
51
+ ],
52
+
53
+ max: (max) => [
54
+ {
55
+ rule: (value) => parseFloat(value) < max,
56
+ message: `The value must be smaller ${max}`,
57
+ },
58
+ ],
59
+
60
+ length: (min, max?) => [
61
+ {
62
+ rule: (value) => String(value).length >= min,
63
+ message: `No less than ${min} symbols`,
64
+ },
65
+ {
66
+ rule: (value) => (max !== undefined ? String(value).length <= max : true),
67
+ message: `No more than ${max} symbols`,
68
+ },
69
+ ],
59
70
  }
package/src/types.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { ValidatorRules } from './rules'
2
+ import { Value } from './validator-field'
3
+ type Fn = (value: Value) => string
4
+
5
+ export interface ValidatorRule {
6
+ rule: (value: Value) => boolean
7
+ message: string | Fn
8
+ }
9
+
10
+ export interface ErrorMessage {
11
+ message: string
12
+ isValid: boolean
13
+ }
14
+
15
+ export interface Validity {
16
+ message: string
17
+ isValid: boolean
18
+ errors?: ErrorMessage[]
19
+ id?: string | number
20
+ }
21
+
22
+ export interface FieldParams {
23
+ value: Value
24
+ rules: ValidatorRules
25
+ required?: boolean
26
+ id?: string | number
27
+ }
@@ -25,7 +25,7 @@ afterEach(() => {
25
25
  jest.useFakeTimers()
26
26
 
27
27
  it('check state change and hide field', () => {
28
- function Comp () {
28
+ function Comp() {
29
29
  const [value, setValue] = useState(false)
30
30
  const [isValid, validateObject] = useValidator(value, rules.bool)
31
31
 
@@ -39,8 +39,8 @@ it('check state change and hide field', () => {
39
39
 
40
40
  return (
41
41
  <>
42
- <span data-testid="test1">{isValid ? 'true' : 'false'}</span>
43
- <span data-testid="test2">{validateObject.message || 'true'}</span>
42
+ <span data-testid='test1'>{isValid ? 'true' : 'false'}</span>
43
+ <span data-testid='test2'>{validateObject.message || 'true'}</span>
44
44
  </>
45
45
  )
46
46
  }
@@ -1,11 +1,11 @@
1
1
  import { Validator } from './validator'
2
2
  import { ValidatorRules } from './rules'
3
- import { Validity, Value } from './validator-field'
3
+ import { Value } from './validator-field'
4
+ import { Validity } from './types'
4
5
 
5
- export function useValidator (value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {
6
+ export function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {
6
7
  const validator = new Validator()
7
8
  validator.addField({ value, rules })
8
9
  const { isValid, ...validateObject } = validator.validate()
9
10
  return [isValid, validateObject]
10
11
  }
11
-
@@ -14,20 +14,20 @@ it('render without wrapper', () => {
14
14
  })
15
15
 
16
16
  it('normal render', () => {
17
- render((
17
+ render(
18
18
  <ValidatorWrapper>
19
- <ValidatorField rules={[]} value="" />
20
- </ValidatorWrapper>
21
- ))
19
+ <ValidatorField rules={[]} value='' />
20
+ </ValidatorWrapper>,
21
+ )
22
22
  })
23
23
 
24
24
  it('check context validator', () => {
25
25
  const validator = createRef<ValidatorWrapper>()
26
- render((
26
+ render(
27
27
  <ValidatorWrapper ref={validator}>
28
28
  <ValidatorField rules={[]} />
29
- </ValidatorWrapper>
30
- ))
29
+ </ValidatorWrapper>,
30
+ )
31
31
 
32
32
  const validateResult = validator.current.validate()
33
33
 
@@ -39,16 +39,16 @@ it('check failed validation', () => {
39
39
  const validator1 = createRef<ValidatorWrapper>()
40
40
  const validator2 = createRef<ValidatorWrapper>()
41
41
 
42
- render((
42
+ render(
43
43
  <>
44
44
  <ValidatorWrapper ref={validator1}>
45
- <ValidatorField rules={rules.email} value="test" />
45
+ <ValidatorField rules={rules.email} value='test' />
46
46
  </ValidatorWrapper>
47
47
  <ValidatorWrapper ref={validator2}>
48
- <ValidatorField rules={rules.email} value="" />
48
+ <ValidatorField rules={rules.email} value='' />
49
49
  </ValidatorWrapper>
50
- </>
51
- ))
50
+ </>,
51
+ )
52
52
 
53
53
  act(() => {
54
54
  const validateResult1 = validator1.current.validate()
@@ -70,7 +70,7 @@ jest.useFakeTimers()
70
70
  it('check state change and hide field', () => {
71
71
  const validator1 = createRef<ValidatorWrapper>()
72
72
 
73
- function Comp () {
73
+ function Comp() {
74
74
  const [st, setSt] = useState(true)
75
75
 
76
76
  useEffect(() => {
@@ -83,10 +83,8 @@ it('check state change and hide field', () => {
83
83
 
84
84
  return (
85
85
  <ValidatorWrapper ref={validator1}>
86
- <ValidatorField rules={rules.email} value="test" />
87
- {st && (
88
- <ValidatorField rules={rules.email} value="" />
89
- )}
86
+ <ValidatorField rules={rules.email} value='test' />
87
+ {st && <ValidatorField rules={rules.email} value='' />}
90
88
  </ValidatorWrapper>
91
89
  )
92
90
  }
@@ -104,11 +102,11 @@ it('check state change and hide field', () => {
104
102
 
105
103
  it('check success validation', () => {
106
104
  const validator = createRef<ValidatorWrapper>()
107
- render((
105
+ render(
108
106
  <ValidatorWrapper ref={validator}>
109
- <ValidatorField rules={rules.email} value="email@email.com" />
110
- </ValidatorWrapper>
111
- ))
107
+ <ValidatorField rules={rules.email} value='email@email.com' />
108
+ </ValidatorWrapper>,
109
+ )
112
110
 
113
111
  const validateResult = validator.current.validate()
114
112
 
@@ -118,17 +116,13 @@ it('check success validation', () => {
118
116
 
119
117
  it('check success validation fot child function', () => {
120
118
  const validator = createRef<ValidatorWrapper>()
121
- render((
119
+ render(
122
120
  <ValidatorWrapper ref={validator}>
123
- <ValidatorField rules={rules.email} value="email@email.com">
124
- {({ isValid, message }) => (
125
- <>
126
- {!isValid && <div>{message}</div>}
127
- </>
128
- )}
121
+ <ValidatorField rules={rules.email} value='email@email.com'>
122
+ {({ isValid, message }) => <>{!isValid && <div>{message}</div>}</>}
129
123
  </ValidatorField>
130
- </ValidatorWrapper>
131
- ))
124
+ </ValidatorWrapper>,
125
+ )
132
126
 
133
127
  const validateResult = validator.current.validate()
134
128
 
@@ -138,21 +132,19 @@ it('check success validation fot child function', () => {
138
132
 
139
133
  it('check custom rule message function', () => {
140
134
  const validator = createRef<ValidatorWrapper>()
141
- const rule = [{
142
- rule: (value) => value !== 'test',
143
- message: (value) => `test message ${value}`
144
- }]
145
- render((
135
+ const rule = [
136
+ {
137
+ rule: (value) => value !== 'test',
138
+ message: (value) => `test message ${value}`,
139
+ },
140
+ ]
141
+ render(
146
142
  <ValidatorWrapper ref={validator}>
147
- <ValidatorField rules={rule} value="test">
148
- {({ isValid, message }) => (
149
- <>
150
- {!isValid && <div>{message}</div>}
151
- </>
152
- )}
143
+ <ValidatorField rules={rule} value='test'>
144
+ {({ isValid, message }) => <>{!isValid && <div>{message}</div>}</>}
153
145
  </ValidatorField>
154
- </ValidatorWrapper>
155
- ))
146
+ </ValidatorWrapper>,
147
+ )
156
148
 
157
149
  const validateResult = validator.current.validate()
158
150
 
@@ -1,4 +1,5 @@
1
1
  import { Component, ReactNode } from 'react'
2
+ import { Validity } from 'types'
2
3
 
3
4
  import { Context } from './context'
4
5
  import { Field } from './validator'
@@ -6,62 +7,58 @@ import { ValidatorRules } from './rules'
6
7
 
7
8
  export type Value = any
8
9
 
9
- export interface ErrorMessage {
10
- message: string
11
- isValid: boolean
12
- }
13
-
14
- export interface Validity {
15
- message: string
16
- isValid: boolean
17
- errors?: ErrorMessage[]
18
- id?: string | number
19
- }
20
-
21
10
  type Fn = (validity: Validity, value: Value) => ReactNode
22
11
 
23
12
  interface Props {
24
- rules?: ValidatorRules,
25
- required?: boolean,
13
+ rules?: ValidatorRules
14
+ required?: boolean
26
15
  value?: Value
27
16
  id?: string | number
28
17
  children?: ReactNode | Fn
29
18
  unregisterField: (val: any) => void
30
19
  registerField: (val: any) => void
20
+ customErrors: Array<Validity>
31
21
  }
32
22
 
33
23
  class ValidationFieldWrapper extends Component<Props> {
34
- componentWillUnmount () {
24
+ componentWillUnmount() {
35
25
  this.props.unregisterField(this)
36
26
  }
37
27
 
38
- componentDidMount () {
28
+ componentDidMount() {
39
29
  this.props.registerField(this)
40
30
  }
41
31
 
42
- validate (): Validity {
32
+ validate(): Validity {
33
+ const props = this.props
34
+ const customError = props.customErrors.find((item) => item.id === props.id)
35
+ if (customError) {
36
+ return customError
37
+ }
38
+
43
39
  const field = new Field({
44
- rules: this.props.rules,
45
- required: this.props.required,
46
- value: this.props.value,
47
- id: this.props.id
40
+ rules: props.rules,
41
+ required: props.required,
42
+ value: props.value,
43
+ id: props.id,
48
44
  })
49
45
  return field.validate()
50
46
  }
51
47
 
52
- render () {
48
+ render() {
53
49
  const { children, value } = this.props
54
50
  const validity = this.validate()
55
- return (typeof children === 'function' ? children(validity, value) : children)
51
+ return typeof children === 'function' ? children(validity, value) : children
56
52
  }
57
53
  }
58
54
 
59
- export function ValidatorField (props: Omit<Props, 'registerField' | 'unregisterField'>) {
55
+ export function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>) {
60
56
  return (
61
57
  <Context.Consumer>
62
58
  {(data) => (
63
59
  <ValidationFieldWrapper
64
60
  {...props}
61
+ customErrors={data.customErrors}
65
62
  registerField={data.registerField}
66
63
  unregisterField={data.unregisterField}
67
64
  />
@@ -15,7 +15,7 @@ it('render without child', () => {
15
15
 
16
16
  it('check wrapper validator', () => {
17
17
  const validator = createRef<ValidatorWrapper>()
18
- render((
18
+ render(
19
19
  <ValidatorWrapper ref={validator}>
20
20
  <ValidatorField rules={[]} />
21
21
  <ValidatorField rules={[]} />
@@ -23,8 +23,8 @@ it('check wrapper validator', () => {
23
23
  <ValidatorField rules={[]} />
24
24
  <ValidatorField rules={[]} />
25
25
  <ValidatorField rules={[]} />
26
- </ValidatorWrapper>
27
- ))
26
+ </ValidatorWrapper>,
27
+ )
28
28
 
29
29
  expect(typeof validator.current).toBe('object')
30
30
  expect(typeof validator.current.validate).toBe('function')
@@ -32,12 +32,12 @@ it('check wrapper validator', () => {
32
32
 
33
33
  it('check getField validator', () => {
34
34
  const validator = createRef<ValidatorWrapper>()
35
- render((
35
+ render(
36
36
  <ValidatorWrapper ref={validator}>
37
- <ValidatorField rules={[]} id="test" />
38
- <ValidatorField rules={[]} id="test-fields" />
39
- </ValidatorWrapper>
40
- ))
37
+ <ValidatorField rules={[]} id='test' />
38
+ <ValidatorField rules={[]} id='test-fields' />
39
+ </ValidatorWrapper>,
40
+ )
41
41
  expect(typeof validator.current.getField).toBe('function')
42
42
  const field = validator.current.getField('test')
43
43
 
@@ -50,11 +50,11 @@ it('check getField validator', () => {
50
50
 
51
51
  it('check getField undefined field', () => {
52
52
  const validator = createRef<ValidatorWrapper>()
53
- render((
53
+ render(
54
54
  <ValidatorWrapper ref={validator}>
55
- <ValidatorField rules={[]} id="test-empty-field" />
56
- </ValidatorWrapper>
57
- ))
55
+ <ValidatorField rules={[]} id='test-empty-field' />
56
+ </ValidatorWrapper>,
57
+ )
58
58
 
59
59
  const field = validator.current.getField('8')
60
60
  expect(field).toBe(null)
@@ -62,13 +62,13 @@ it('check getField undefined field', () => {
62
62
 
63
63
  it('check stopAtFirstError validator', () => {
64
64
  const validator = createRef<ValidatorWrapper>()
65
- render((
65
+ render(
66
66
  <ValidatorWrapper ref={validator} stopAtFirstError>
67
- <ValidatorField rules={[]} value="test" />
68
- <ValidatorField rules={rules.email} value="test" />
69
- <ValidatorField rules={rules.password} value="" />
70
- </ValidatorWrapper>
71
- ))
67
+ <ValidatorField rules={[]} value='test' />
68
+ <ValidatorField rules={rules.email} value='test' />
69
+ <ValidatorField rules={rules.password} value='' />
70
+ </ValidatorWrapper>,
71
+ )
72
72
  const fieldValidate = validator.current.validate()
73
73
  expect(fieldValidate.isValid).toBe(false)
74
74
  expect(fieldValidate.message).toBe('Email is invalid')
@@ -77,11 +77,11 @@ it('check stopAtFirstError validator', () => {
77
77
 
78
78
  it('check unregisterField, registerField', () => {
79
79
  const validator = createRef<ValidatorWrapper>()
80
- render((
80
+ render(
81
81
  <ValidatorWrapper ref={validator}>
82
- <ValidatorField rules={[]} id="test-register-field" />
83
- </ValidatorWrapper>
84
- ))
82
+ <ValidatorField rules={[]} id='test-register-field' />
83
+ </ValidatorWrapper>,
84
+ )
85
85
 
86
86
  expect(typeof validator.current.registerField).toBe('function')
87
87
  expect(typeof validator.current.unregisterField).toBe('function')
@@ -92,10 +92,10 @@ it('check filed in field', () => {
92
92
  render(
93
93
  <ValidatorWrapper ref={validator}>
94
94
  <ValidatorField rules={[]}>
95
- <ValidatorField rules={[]} id="check-validate-field-1" />
96
- <ValidatorField rules={[]} id="check-validate-field-2" />
95
+ <ValidatorField rules={[]} id='check-validate-field-1' />
96
+ <ValidatorField rules={[]} id='check-validate-field-2' />
97
97
  </ValidatorField>
98
- </ValidatorWrapper>
98
+ </ValidatorWrapper>,
99
99
  )
100
100
 
101
101
  expect(typeof validator.current).toBe('object')
@@ -107,14 +107,14 @@ it('check filed in field', () => {
107
107
  it('check wrapper in wrapper', () => {
108
108
  const validatorOut = createRef<ValidatorWrapper>()
109
109
  const validatorIn = createRef<ValidatorWrapper>()
110
- render((
110
+ render(
111
111
  <ValidatorWrapper ref={validatorOut}>
112
- <ValidatorField rules={rules.email} value="" />
112
+ <ValidatorField rules={rules.email} value='' />
113
113
  <ValidatorWrapper ref={validatorIn}>
114
- <ValidatorField rules={rules.password} value="successpasswword" />
114
+ <ValidatorField rules={rules.password} value='successpasswword' />
115
115
  </ValidatorWrapper>
116
- </ValidatorWrapper>
117
- ))
116
+ </ValidatorWrapper>,
117
+ )
118
118
  expect(validatorIn.current.validate().isValid).toBe(true)
119
119
  expect(validatorOut.current.validate().isValid).toBe(false)
120
120
  })
@@ -122,16 +122,16 @@ it('check wrapper in wrapper', () => {
122
122
  it('check two validators', () => {
123
123
  const validatorSuccess = createRef<ValidatorWrapper>()
124
124
  const validatorFailed = createRef<ValidatorWrapper>()
125
- render((
125
+ render(
126
126
  <>
127
127
  <ValidatorWrapper ref={validatorSuccess}>
128
- <ValidatorField rules={rules.password} value="successpasswword" />
128
+ <ValidatorField rules={rules.password} value='successpasswword' />
129
129
  </ValidatorWrapper>
130
130
  <ValidatorWrapper ref={validatorFailed}>
131
- <ValidatorField rules={rules.email} value="" />
131
+ <ValidatorField rules={rules.email} value='' />
132
132
  </ValidatorWrapper>
133
- </>
134
- ))
133
+ </>,
134
+ )
135
135
 
136
136
  expect(validatorFailed.current.validate().isValid).toBe(false)
137
137
  expect(validatorSuccess.current.validate().isValid).toBe(true)
@@ -1,7 +1,8 @@
1
1
  import { Component, ReactNode, RefObject } from 'react'
2
2
 
3
+ import { Validity } from './types'
3
4
  import { Context } from './context'
4
- import { Validator } from './validator'
5
+ import { Field, Validator } from './validator'
5
6
 
6
7
  interface ComponentProps {
7
8
  children?: ReactNode
@@ -11,33 +12,46 @@ interface ComponentProps {
11
12
 
12
13
  export class ValidatorWrapper extends Component<ComponentProps> {
13
14
  fields = []
15
+ state = {
16
+ customErrors: [],
17
+ }
14
18
 
15
- constructor (props, ctx) {
19
+ constructor(props, ctx) {
16
20
  super(props, ctx)
17
21
  this.registerField = this.registerField.bind(this)
18
22
  this.unregisterField = this.unregisterField.bind(this)
19
23
  }
20
24
 
21
- componentWillUnmount () {
25
+ componentWillUnmount() {
22
26
  this.fields = []
23
27
  }
24
28
 
25
- registerField (field) {
29
+ registerField(field) {
26
30
  if (field && !this.fields.includes(field)) {
27
31
  this.fields.push(field)
28
32
  }
29
33
  }
30
34
 
31
- unregisterField (field) {
35
+ unregisterField(field) {
32
36
  const index = this.fields.indexOf(field)
33
37
  if (index > -1) this.fields.splice(index, 1)
34
38
  }
35
39
 
36
- getField (id) {
40
+ getField(id): Field | null {
37
41
  return this.fields.find((field) => field.props.id === id) || null
38
42
  }
39
43
 
40
- validate () {
44
+ setCustomError(customError: Validity) {
45
+ this.setState({
46
+ customErrors: [...this.state.customErrors, customError],
47
+ })
48
+ }
49
+
50
+ clearCustomErrors() {
51
+ this.setState({ customErrors: [] })
52
+ }
53
+
54
+ validate(): Validity {
41
55
  const validator = new Validator({ stopAtFirstError: this.props.stopAtFirstError })
42
56
  this.fields.forEach((comp) => {
43
57
  validator.addField(comp.props)
@@ -45,10 +59,14 @@ export class ValidatorWrapper extends Component<ComponentProps> {
45
59
  return validator.validate()
46
60
  }
47
61
 
48
- render () {
62
+ render() {
49
63
  return (
50
64
  <Context.Provider
51
- value={{ registerField: this.registerField, unregisterField: this.unregisterField }}
65
+ value={{
66
+ customErrors: this.state.customErrors,
67
+ registerField: this.registerField,
68
+ unregisterField: this.unregisterField,
69
+ }}
52
70
  >
53
71
  {this.props.children}
54
72
  </Context.Provider>
@@ -12,7 +12,7 @@ it('check normal add and remove fields', () => {
12
12
  const fieldPassword = validator.addField({
13
13
  rules: rules.password,
14
14
  value: '',
15
- id: 'for-remove'
15
+ id: 'for-remove',
16
16
  })
17
17
 
18
18
  expect(typeof fieldPassword).toBe('object')
package/src/validator.ts CHANGED
@@ -1,40 +1,24 @@
1
- import { Validity, Value } from './validator-field'
1
+ import { Value } from './validator-field'
2
2
  import { ValidatorRules } from './rules'
3
-
4
- export interface FieldParams {
5
- value: Value
6
- rules: ValidatorRules,
7
- required?: boolean
8
- id?: string|number
9
- }
3
+ import { FieldParams, Validity } from './types'
10
4
 
11
5
  export class Field {
12
6
  private rules: ValidatorRules
13
7
  private required: boolean
14
8
  private value: Value
15
- public id: string|number
9
+ public id: string | number
16
10
 
17
- constructor ({
18
- rules,
19
- required,
20
- value,
21
- id
22
- }: FieldParams) {
11
+ constructor({ rules, required, value, id }: FieldParams) {
23
12
  this.rules = rules
24
13
  this.required = required
25
14
  this.value = value
26
15
  this.id = id
27
16
  }
28
17
 
29
- validate (): Validity {
18
+ validate(): Validity {
30
19
  let isValid = true
31
20
  let message = ''
32
- const {
33
- rules,
34
- value,
35
- required,
36
- id
37
- } = this
21
+ const { rules, value, required, id } = this
38
22
 
39
23
  const isEmptyValue = !value && parseFloat(value) !== 0
40
24
 
@@ -65,27 +49,27 @@ export class Validator {
65
49
  private fields: Field[]
66
50
  private params: ValidatorParams
67
51
 
68
- constructor (params?: ValidatorParams) {
52
+ constructor(params?: ValidatorParams) {
69
53
  this.params = params || null
70
54
  this.fields = []
71
55
  }
72
56
 
73
- addField (params: FieldParams): Field {
57
+ addField(params: FieldParams): Field {
74
58
  const field = new Field(params)
75
59
  this.fields.push(field)
76
60
  return field
77
61
  }
78
62
 
79
- removeField (field: Field): void {
63
+ removeField(field: Field): void {
80
64
  const index = this.fields.indexOf(field)
81
65
  if (index > -1) this.fields.splice(index, 1)
82
66
  }
83
67
 
84
- getField (id: Field['id']): Field {
68
+ getField(id: Field['id']): Field {
85
69
  return this.fields.find((field) => field.id === id) || null
86
70
  }
87
71
 
88
- validate (): Validity {
72
+ validate(): Validity {
89
73
  let prevResult
90
74
  const statuses = this.fields.map((field) => {
91
75
  if (this.params?.stopAtFirstError && prevResult && prevResult.isValid === false) {