@coxy/react-validator 3.0.0 → 4.0.0
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/biome.json +4 -2
- package/dist/index.d.mts +32 -42
- package/dist/index.d.ts +32 -42
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/example/example.tsx +21 -25
- package/example/index.html +2 -7
- package/example/tsconfig.json +6 -6
- package/package.json +12 -13
- package/src/context.ts +8 -3
- package/src/custom-errors.test.tsx +73 -0
- package/src/index.test.ts +19 -4
- package/src/index.ts +4 -3
- package/src/rules.test.ts +9 -4
- package/src/rules.ts +14 -14
- package/src/use-validator.test.tsx +1 -2
- package/src/validator-field.test.tsx +34 -3
- package/src/validator-field.tsx +44 -54
- package/src/validator-wrapper.test.tsx +31 -13
- package/src/validator-wrapper.tsx +58 -55
- package/src/validator.test.tsx +10 -0
- package/src/validator.ts +3 -3
- package/src/jest.d.ts +0 -2
package/biome.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
+
"files": {
|
|
3
|
+
"includes": ["src/**/*", "example/example.tsx"]
|
|
4
|
+
},
|
|
2
5
|
"formatter": {
|
|
3
6
|
"enabled": true,
|
|
4
7
|
"indentStyle": "space",
|
|
5
8
|
"indentWidth": 2,
|
|
6
9
|
"lineWidth": 120,
|
|
7
|
-
"formatWithErrors": false
|
|
8
|
-
"ignore": ["**/*.min.js"]
|
|
10
|
+
"formatWithErrors": false
|
|
9
11
|
},
|
|
10
12
|
"javascript": {
|
|
11
13
|
"formatter": {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { ReactNode
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
type Value = any;
|
|
5
5
|
type Fn$1 = (validity: Validity, value: Value) => ReactNode;
|
|
6
|
-
|
|
7
|
-
rules?: ValidatorRules;
|
|
8
|
-
required?: boolean;
|
|
9
|
-
value?: Value;
|
|
10
|
-
id?: string | number;
|
|
6
|
+
declare const ValidatorField: react.ForwardRefExoticComponent<FieldParams & {
|
|
11
7
|
children?: ReactNode | Fn$1;
|
|
12
|
-
|
|
13
|
-
registerField: (val: Value) => void;
|
|
14
|
-
customErrors: Array<Validity>;
|
|
15
|
-
}
|
|
16
|
-
declare function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>): react_jsx_runtime.JSX.Element;
|
|
8
|
+
} & react.RefAttributes<unknown>>;
|
|
17
9
|
|
|
18
10
|
type Fn = (value: Value) => string;
|
|
19
11
|
interface ValidatorRule {
|
|
@@ -40,39 +32,41 @@ interface FieldParams {
|
|
|
40
32
|
type ValidatorRules = ValidatorRule[];
|
|
41
33
|
declare const rules: {
|
|
42
34
|
notEmpty: {
|
|
43
|
-
rule: (value:
|
|
35
|
+
rule: (value: string) => boolean;
|
|
44
36
|
message: string;
|
|
45
37
|
}[];
|
|
46
38
|
bool: {
|
|
47
|
-
rule: (value:
|
|
39
|
+
rule: (value: string) => boolean;
|
|
48
40
|
message: string;
|
|
49
41
|
}[];
|
|
50
42
|
password: {
|
|
51
|
-
rule: (value:
|
|
43
|
+
rule: (value: string) => boolean;
|
|
52
44
|
message: string;
|
|
53
45
|
}[];
|
|
54
46
|
email: {
|
|
55
|
-
rule: (value:
|
|
47
|
+
rule: (value: string) => boolean;
|
|
56
48
|
message: string;
|
|
57
49
|
}[];
|
|
58
|
-
min: (min:
|
|
59
|
-
rule: (value:
|
|
50
|
+
min: (min: number) => {
|
|
51
|
+
rule: (value: string) => boolean;
|
|
60
52
|
message: string;
|
|
61
53
|
}[];
|
|
62
|
-
max: (max:
|
|
63
|
-
rule: (value:
|
|
54
|
+
max: (max: number) => {
|
|
55
|
+
rule: (value: string) => boolean;
|
|
64
56
|
message: string;
|
|
65
57
|
}[];
|
|
66
|
-
length: (min:
|
|
67
|
-
rule: (value:
|
|
58
|
+
length: (min: number, max?: number) => {
|
|
59
|
+
rule: (value: string) => boolean;
|
|
68
60
|
message: string;
|
|
69
61
|
}[];
|
|
70
62
|
};
|
|
71
63
|
|
|
64
|
+
declare function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>];
|
|
65
|
+
|
|
72
66
|
declare class Field {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
protected rules: ValidatorRules;
|
|
68
|
+
protected required: boolean;
|
|
69
|
+
protected value: Value;
|
|
76
70
|
id: string | number;
|
|
77
71
|
constructor({ rules, required, value, id }: FieldParams);
|
|
78
72
|
validate(): Validity;
|
|
@@ -90,27 +84,23 @@ declare class Validator {
|
|
|
90
84
|
validate(): Validity;
|
|
91
85
|
}
|
|
92
86
|
|
|
87
|
+
interface RegisteredFieldHandle {
|
|
88
|
+
props: FieldParams;
|
|
89
|
+
validate: () => Validity;
|
|
90
|
+
}
|
|
91
|
+
|
|
93
92
|
interface ComponentProps {
|
|
94
93
|
children?: ReactNode;
|
|
95
94
|
stopAtFirstError?: boolean;
|
|
96
|
-
ref?: RefObject<ValidatorWrapper>;
|
|
97
95
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
registerField(field: any): void;
|
|
106
|
-
unregisterField(field: any): void;
|
|
107
|
-
getField(id: any): Field | null;
|
|
108
|
-
setCustomError(customError: Validity): void;
|
|
109
|
-
clearCustomErrors(): void;
|
|
110
|
-
validate(): Validity;
|
|
111
|
-
render(): ReactNode;
|
|
96
|
+
interface ValidatorWrapper {
|
|
97
|
+
validate: () => Validity;
|
|
98
|
+
getField: (id: string | number) => RegisteredFieldHandle | null;
|
|
99
|
+
registerField: (field: RegisteredFieldHandle) => void;
|
|
100
|
+
unregisterField: (field: RegisteredFieldHandle) => void;
|
|
101
|
+
setCustomError: (customError: Validity) => void;
|
|
102
|
+
clearCustomErrors: () => void;
|
|
112
103
|
}
|
|
113
|
-
|
|
114
|
-
declare function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>];
|
|
104
|
+
declare const ValidatorWrapper: react.ForwardRefExoticComponent<ComponentProps & react.RefAttributes<ValidatorWrapper>>;
|
|
115
105
|
|
|
116
106
|
export { type ErrorMessage, type FieldParams, Validator, ValidatorField, type ValidatorRule, ValidatorWrapper, type Validity, rules, useValidator };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { ReactNode
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
type Value = any;
|
|
5
5
|
type Fn$1 = (validity: Validity, value: Value) => ReactNode;
|
|
6
|
-
|
|
7
|
-
rules?: ValidatorRules;
|
|
8
|
-
required?: boolean;
|
|
9
|
-
value?: Value;
|
|
10
|
-
id?: string | number;
|
|
6
|
+
declare const ValidatorField: react.ForwardRefExoticComponent<FieldParams & {
|
|
11
7
|
children?: ReactNode | Fn$1;
|
|
12
|
-
|
|
13
|
-
registerField: (val: Value) => void;
|
|
14
|
-
customErrors: Array<Validity>;
|
|
15
|
-
}
|
|
16
|
-
declare function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>): react_jsx_runtime.JSX.Element;
|
|
8
|
+
} & react.RefAttributes<unknown>>;
|
|
17
9
|
|
|
18
10
|
type Fn = (value: Value) => string;
|
|
19
11
|
interface ValidatorRule {
|
|
@@ -40,39 +32,41 @@ interface FieldParams {
|
|
|
40
32
|
type ValidatorRules = ValidatorRule[];
|
|
41
33
|
declare const rules: {
|
|
42
34
|
notEmpty: {
|
|
43
|
-
rule: (value:
|
|
35
|
+
rule: (value: string) => boolean;
|
|
44
36
|
message: string;
|
|
45
37
|
}[];
|
|
46
38
|
bool: {
|
|
47
|
-
rule: (value:
|
|
39
|
+
rule: (value: string) => boolean;
|
|
48
40
|
message: string;
|
|
49
41
|
}[];
|
|
50
42
|
password: {
|
|
51
|
-
rule: (value:
|
|
43
|
+
rule: (value: string) => boolean;
|
|
52
44
|
message: string;
|
|
53
45
|
}[];
|
|
54
46
|
email: {
|
|
55
|
-
rule: (value:
|
|
47
|
+
rule: (value: string) => boolean;
|
|
56
48
|
message: string;
|
|
57
49
|
}[];
|
|
58
|
-
min: (min:
|
|
59
|
-
rule: (value:
|
|
50
|
+
min: (min: number) => {
|
|
51
|
+
rule: (value: string) => boolean;
|
|
60
52
|
message: string;
|
|
61
53
|
}[];
|
|
62
|
-
max: (max:
|
|
63
|
-
rule: (value:
|
|
54
|
+
max: (max: number) => {
|
|
55
|
+
rule: (value: string) => boolean;
|
|
64
56
|
message: string;
|
|
65
57
|
}[];
|
|
66
|
-
length: (min:
|
|
67
|
-
rule: (value:
|
|
58
|
+
length: (min: number, max?: number) => {
|
|
59
|
+
rule: (value: string) => boolean;
|
|
68
60
|
message: string;
|
|
69
61
|
}[];
|
|
70
62
|
};
|
|
71
63
|
|
|
64
|
+
declare function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>];
|
|
65
|
+
|
|
72
66
|
declare class Field {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
protected rules: ValidatorRules;
|
|
68
|
+
protected required: boolean;
|
|
69
|
+
protected value: Value;
|
|
76
70
|
id: string | number;
|
|
77
71
|
constructor({ rules, required, value, id }: FieldParams);
|
|
78
72
|
validate(): Validity;
|
|
@@ -90,27 +84,23 @@ declare class Validator {
|
|
|
90
84
|
validate(): Validity;
|
|
91
85
|
}
|
|
92
86
|
|
|
87
|
+
interface RegisteredFieldHandle {
|
|
88
|
+
props: FieldParams;
|
|
89
|
+
validate: () => Validity;
|
|
90
|
+
}
|
|
91
|
+
|
|
93
92
|
interface ComponentProps {
|
|
94
93
|
children?: ReactNode;
|
|
95
94
|
stopAtFirstError?: boolean;
|
|
96
|
-
ref?: RefObject<ValidatorWrapper>;
|
|
97
95
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
registerField(field: any): void;
|
|
106
|
-
unregisterField(field: any): void;
|
|
107
|
-
getField(id: any): Field | null;
|
|
108
|
-
setCustomError(customError: Validity): void;
|
|
109
|
-
clearCustomErrors(): void;
|
|
110
|
-
validate(): Validity;
|
|
111
|
-
render(): ReactNode;
|
|
96
|
+
interface ValidatorWrapper {
|
|
97
|
+
validate: () => Validity;
|
|
98
|
+
getField: (id: string | number) => RegisteredFieldHandle | null;
|
|
99
|
+
registerField: (field: RegisteredFieldHandle) => void;
|
|
100
|
+
unregisterField: (field: RegisteredFieldHandle) => void;
|
|
101
|
+
setCustomError: (customError: Validity) => void;
|
|
102
|
+
clearCustomErrors: () => void;
|
|
112
103
|
}
|
|
113
|
-
|
|
114
|
-
declare function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>];
|
|
104
|
+
declare const ValidatorWrapper: react.ForwardRefExoticComponent<ComponentProps & react.RefAttributes<ValidatorWrapper>>;
|
|
115
105
|
|
|
116
106
|
export { type ErrorMessage, type FieldParams, Validator, ValidatorField, type ValidatorRule, ValidatorWrapper, type Validity, rules, useValidator };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var h=/^(([^<>()
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var h=/^(([^<>()[\]\\.,;:\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,}))$/,x={notEmpty:[{rule:r=>r!==""&&r.length>0,message:"Value is required"}],bool:[{rule:r=>!!r,message:"Value is required"}],password:[{rule:r=>r.length>0,message:"Password field cannot be empty"},{rule:r=>r.length>5,message:"Password field can not be less than 6 characters"}],email:[{rule:r=>!!r&&r!==""&&r.length!==0,message:"Email is required"},{rule:r=>h.test(String(r).toLowerCase()),message:"Email is invalid"}],min:r=>[{rule:e=>Number.parseFloat(e)>r,message:`The value must be greater than ${r}`}],max:r=>[{rule:e=>Number.parseFloat(e)<r,message:`The value must be smaller ${r}`}],length:(r,e)=>[{rule:t=>String(t).length>=r,message:`No less than ${r} symbols`},{rule:t=>e!==void 0?String(t).length<=e:true,message:`No more than ${e} symbols`}]};var V=class{rules;required;value;id;constructor({rules:e,required:t,value:s,id:i}){this.rules=e,this.required=t,this.value=s,this.id=i;}validate(){let e=true,t="",{rules:s,value:i,required:d,id:u}=this,n=!i&&Number.parseFloat(i)!==0;if(!s.length||n&&d===false)return {isValid:e,message:t,id:u};for(let a of s)e&&(e=a.rule(i),e||(typeof a.message=="function"?t=a.message(i):t=a.message));return {isValid:e,message:t,id:u}}},c=class{fields;params;constructor(e){this.params=e||null,this.fields=[];}addField(e){let t=new V(e);return this.fields.push(t),t}removeField(e){let t=this.fields.indexOf(e);t>-1&&this.fields.splice(t,1);}getField(e){return this.fields.find(t=>t.id===e)||null}validate(){let e,s=this.fields.map(i=>this.params?.stopAtFirstError&&e&&e.isValid===false?null:(e=i.validate(),e)).filter(i=>i&&i.isValid===false);if(s.length){let{isValid:i,message:d}=s[0];return {isValid:i,message:d,errors:s}}return {isValid:true,message:""}}};function b(r,e){let t=new c;t.addField({value:r,rules:e});let{isValid:s,...i}=t.validate();return [s,i]}var v=react.createContext(null);var w=react.forwardRef(function(e,t){let{children:s,value:i}=e,{customErrors:d,registerField:u,unregisterField:n}=react.useContext(v),a=react.useRef(e);a.current=e;let g=react.useRef(d);g.current=d;let p=react.useRef(null);p.current||(p.current={get props(){return a.current},validate:()=>{let m=a.current,y=g.current.find(o=>o.id===m.id);return y||new V({rules:m.rules,required:m.required,value:m.value,id:m.id}).validate()}}),react.useEffect(()=>(u(p.current),()=>{n(p.current);}),[u,n]);let F=p.current.validate();return typeof s=="function"?s(F,i):s});var S=react.forwardRef(function({children:e,stopAtFirstError:t},s){let i=react.useRef([]),[d,u]=react.useState([]),n=react.useCallback(l=>{l&&!i.current.includes(l)&&i.current.push(l);},[]),a=react.useCallback(l=>{let o=i.current.indexOf(l);o>-1&&i.current.splice(o,1);},[]),g=react.useCallback(l=>i.current.find(o=>o?.props?.id===l)||null,[]),p=react.useCallback(l=>{u(o=>[...o,l]);},[]),F=react.useCallback(()=>{u([]);},[]),m=react.useCallback(()=>{let l=new c({stopAtFirstError:t});for(let o of i.current)l.addField(o.props);return l.validate()},[t]);react.useImperativeHandle(s,()=>({validate:m,getField:g,registerField:n,unregisterField:a,setCustomError:p,clearCustomErrors:F}),[m,g,n,a,p,F]);let y=react.useMemo(()=>({customErrors:d,registerField:n,unregisterField:a}),[d,n,a]);return jsxRuntime.jsx(v.Provider,{value:y,children:e})});exports.Validator=c;exports.ValidatorField=w;exports.ValidatorWrapper=S;exports.rules=x;exports.useValidator=b;//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rules.ts","../src/context.ts","../src/validator.ts","../src/validator-field.tsx","../src/validator-wrapper.tsx","../src/use-validator.ts"],"names":["emailReg","rules","value","min","max","Context","createContext","Field","required","id","isValid","message","isEmptyValue","instance","Validator","params","field","index","prevResult","errors","inst","ValidationFieldWrapper","Component","props","customError","item","children","validity","ValidatorField","jsx","data","ValidatorWrapper","validator","comp","useValidator","validateObject"],"mappings":"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","file":"index.js","sourcesContent":["import type { ValidatorRule } from './types'\n\n// eslint-disable-next-line\nconst emailReg =\n /^(([^<>()\\[\\]\\\\.,;:\\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,}))$/\n\nexport type ValidatorRules = ValidatorRule[]\n\nexport const rules = {\n notEmpty: [\n {\n rule: (value) => value !== '' && value.length > 0,\n message: 'Value is required',\n },\n ],\n\n bool: [\n {\n rule: (value) => !!value,\n message: 'Value is required',\n },\n ],\n\n password: [\n {\n rule: (value) => value.length > 0,\n message: 'Password field cannot be empty',\n },\n {\n rule: (value) => value.length > 5,\n message: 'Password field can not be less than 6 characters',\n },\n ],\n\n email: [\n {\n rule: (value) => !!value && value !== '' && value.length !== 0,\n message: 'Email is required',\n },\n {\n rule: (value) => emailReg.test(String(value).toLowerCase()),\n message: 'Email is invalid',\n },\n ],\n\n min: (min) => [\n {\n rule: (value) => Number.parseFloat(value) > min,\n message: `The value must be greater than ${min}`,\n },\n ],\n\n max: (max) => [\n {\n rule: (value) => Number.parseFloat(value) < max,\n message: `The value must be smaller ${max}`,\n },\n ],\n\n length: (min, max?) => [\n {\n rule: (value) => String(value).length >= min,\n message: `No less than ${min} symbols`,\n },\n {\n rule: (value) => (max !== undefined ? String(value).length <= max : true),\n message: `No more than ${max} symbols`,\n },\n ],\n}\n","import { createContext } from 'react'\n\nimport type { Validity } from './types'\n\nexport const Context = createContext<{\n registerField: (field: string | number) => void\n unregisterField: (field: string | number) => void\n customErrors: Array<Validity>\n}>(null)\n","import type { ValidatorRules } from './rules'\nimport type { FieldParams, Validity } from './types'\nimport type { Value } from './validator-field'\n\nexport class Field {\n private rules: ValidatorRules\n private required: boolean\n private value: Value\n public id: string | number\n\n constructor({ rules, required, value, id }: FieldParams) {\n this.rules = rules\n this.required = required\n this.value = value\n this.id = id\n }\n\n validate(): Validity {\n let isValid = true\n let message = ''\n const { rules, value, required, id } = this\n\n const isEmptyValue = !value && Number.parseFloat(value) !== 0\n\n if (!rules.length || (isEmptyValue && required === false)) {\n return { isValid, message, id }\n }\n for (const instance of rules) {\n if (isValid) {\n isValid = instance.rule(value)\n if (!isValid) {\n if (typeof instance.message === 'function') {\n message = instance.message(value)\n } else {\n message = instance.message\n }\n }\n }\n }\n return { isValid, message, id }\n }\n}\n\nexport interface ValidatorParams {\n stopAtFirstError: boolean\n}\n\nexport class Validator {\n private fields: Field[]\n private params: ValidatorParams\n\n constructor(params?: ValidatorParams) {\n this.params = params || null\n this.fields = []\n }\n\n addField(params: FieldParams): Field {\n const field = new Field(params)\n this.fields.push(field)\n return field\n }\n\n removeField(field: Field): void {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id: Field['id']): Field {\n return this.fields.find((field) => field.id === id) || null\n }\n\n validate(): Validity {\n let prevResult: Validity | null\n const statuses = this.fields.map((field) => {\n if (this.params?.stopAtFirstError && prevResult && prevResult.isValid === false) {\n return null\n }\n prevResult = field.validate()\n return prevResult\n })\n\n const errors = statuses.filter((inst) => inst && inst.isValid === false)\n\n if (errors.length) {\n const { isValid, message } = errors[0]\n return { isValid, message, errors }\n }\n return { isValid: true, message: '' }\n }\n}\n","import { Component, type ReactNode } from 'react'\nimport type { Validity } from 'types'\n\nimport { Context } from './context'\nimport type { ValidatorRules } from './rules'\nimport { Field } from './validator'\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\nexport type Value = any\n\ntype Fn = (validity: Validity, value: Value) => ReactNode\n\ninterface Props {\n rules?: ValidatorRules\n required?: boolean\n value?: Value\n id?: string | number\n children?: ReactNode | Fn\n unregisterField: (val: Value) => void\n registerField: (val: Value) => void\n customErrors: Array<Validity>\n}\n\nclass ValidationFieldWrapper extends Component<Props> {\n componentWillUnmount() {\n this.props.unregisterField(this)\n }\n\n componentDidMount() {\n this.props.registerField(this)\n }\n\n validate(): Validity {\n const props = this.props\n const customError = props.customErrors.find((item) => item.id === props.id)\n if (customError) {\n return customError\n }\n\n const field = new Field({\n rules: props.rules,\n required: props.required,\n value: props.value,\n id: props.id,\n })\n return field.validate()\n }\n\n render() {\n const { children, value } = this.props\n const validity = this.validate()\n return typeof children === 'function' ? children(validity, value) : children\n }\n}\n\nexport function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>) {\n return (\n <Context.Consumer>\n {(data) => (\n <ValidationFieldWrapper\n {...props}\n customErrors={data.customErrors}\n registerField={data.registerField}\n unregisterField={data.unregisterField}\n />\n )}\n </Context.Consumer>\n )\n}\n","import { Component, type ReactNode, type RefObject } from 'react'\n\nimport { Context } from './context'\nimport type { Validity } from './types'\nimport { type Field, Validator } from './validator'\n\ninterface ComponentProps {\n children?: ReactNode\n stopAtFirstError?: boolean\n ref?: RefObject<ValidatorWrapper>\n}\n\nexport class ValidatorWrapper extends Component<ComponentProps> {\n fields = []\n state = {\n customErrors: [],\n }\n\n constructor(props) {\n super(props)\n this.registerField = this.registerField.bind(this)\n this.unregisterField = this.unregisterField.bind(this)\n }\n\n componentWillUnmount() {\n this.fields = []\n }\n\n registerField(field) {\n if (field && !this.fields.includes(field)) {\n this.fields.push(field)\n }\n }\n\n unregisterField(field) {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id): Field | null {\n return this.fields.find((field) => field.props.id === id) || null\n }\n\n setCustomError(customError: Validity) {\n this.setState({\n customErrors: [...this.state.customErrors, customError],\n })\n }\n\n clearCustomErrors() {\n this.setState({ customErrors: [] })\n }\n\n validate(): Validity {\n const validator = new Validator({ stopAtFirstError: this.props.stopAtFirstError })\n for (const comp of this.fields) {\n validator.addField(comp.props)\n }\n return validator.validate()\n }\n\n render(): ReactNode {\n return (\n <Context.Provider\n value={{\n customErrors: this.state.customErrors,\n registerField: this.registerField,\n unregisterField: this.unregisterField,\n }}\n >\n {this.props.children}\n </Context.Provider>\n )\n }\n}\n","import type { ValidatorRules } from './rules'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\nimport type { Value } from './validator-field'\n\nexport function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {\n const validator = new Validator()\n validator.addField({ value, rules })\n const { isValid, ...validateObject } = validator.validate()\n return [isValid, validateObject]\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/rules.ts","../src/validator.ts","../src/use-validator.ts","../src/context.ts","../src/validator-field.tsx","../src/validator-wrapper.tsx"],"names":["emailReg","rules","value","min","max","Field","required","id","isValid","message","isEmptyValue","instance","Validator","params","field","index","prevResult","errors","inst","useValidator","validator","validateObject","Context","createContext","ValidatorField","forwardRef","props","_ref","children","customErrors","registerField","unregisterField","useContext","propsRef","useRef","customErrorsRef","handleRef","curr","customError","item","useEffect","validity","ValidatorWrapper","stopAtFirstError","ref","fieldsRef","setCustomErrors","useState","useCallback","getField","setCustomError","prev","clearCustomErrors","validate","comp","useImperativeHandle","contextValue","useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import type { ValidatorRule } from './types'\n\n// eslint-disable-next-line\nconst emailReg =\n /^(([^<>()[\\]\\\\.,;:\\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,}))$/\n\nexport type ValidatorRules = ValidatorRule[]\n\nexport const rules = {\n notEmpty: [\n {\n rule: (value: string) => value !== '' && value.length > 0,\n message: 'Value is required',\n },\n ],\n\n bool: [\n {\n rule: (value: string) => !!value,\n message: 'Value is required',\n },\n ],\n\n password: [\n {\n rule: (value: string) => value.length > 0,\n message: 'Password field cannot be empty',\n },\n {\n rule: (value: string) => value.length > 5,\n message: 'Password field can not be less than 6 characters',\n },\n ],\n\n email: [\n {\n rule: (value: string) => !!value && value !== '' && value.length !== 0,\n message: 'Email is required',\n },\n {\n rule: (value: string) => emailReg.test(String(value).toLowerCase()),\n message: 'Email is invalid',\n },\n ],\n\n min: (min: number) => [\n {\n rule: (value: string) => Number.parseFloat(value) > min,\n message: `The value must be greater than ${min}`,\n },\n ],\n\n max: (max: number) => [\n {\n rule: (value: string) => Number.parseFloat(value) < max,\n message: `The value must be smaller ${max}`,\n },\n ],\n\n length: (min: number, max?: number) => [\n {\n rule: (value: string) => String(value).length >= min,\n message: `No less than ${min} symbols`,\n },\n {\n rule: (value: string) => (max !== undefined ? String(value).length <= max : true),\n message: `No more than ${max} symbols`,\n },\n ],\n}\n","import type { ValidatorRules } from './rules'\nimport type { FieldParams, Validity } from './types'\nimport type { Value } from './validator-field'\n\nexport class Field {\n protected rules: ValidatorRules\n protected required: boolean\n protected value: Value\n public id: string | number\n\n constructor({ rules, required, value, id }: FieldParams) {\n this.rules = rules\n this.required = required\n this.value = value\n this.id = id\n }\n\n validate(): Validity {\n let isValid = true\n let message = ''\n const { rules, value, required, id } = this\n\n const isEmptyValue = !value && Number.parseFloat(value) !== 0\n\n if (!rules.length || (isEmptyValue && required === false)) {\n return { isValid, message, id }\n }\n for (const instance of rules) {\n if (isValid) {\n isValid = instance.rule(value)\n if (!isValid) {\n if (typeof instance.message === 'function') {\n message = instance.message(value)\n } else {\n message = instance.message\n }\n }\n }\n }\n return { isValid, message, id }\n }\n}\n\nexport interface ValidatorParams {\n stopAtFirstError: boolean\n}\n\nexport class Validator {\n private fields: Field[]\n private params: ValidatorParams\n\n constructor(params?: ValidatorParams) {\n this.params = params || null\n this.fields = []\n }\n\n addField(params: FieldParams): Field {\n const field = new Field(params)\n this.fields.push(field)\n return field\n }\n\n removeField(field: Field): void {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id: Field['id']): Field {\n return this.fields.find((field) => field.id === id) || null\n }\n\n validate(): Validity {\n let prevResult: Validity | null\n const statuses = this.fields.map((field) => {\n if (this.params?.stopAtFirstError && prevResult && prevResult.isValid === false) {\n return null\n }\n prevResult = field.validate()\n return prevResult\n })\n\n const errors = statuses.filter((inst) => inst && inst.isValid === false)\n\n if (errors.length) {\n const { isValid, message } = errors[0]\n return { isValid, message, errors }\n }\n return { isValid: true, message: '' }\n }\n}\n","import type { ValidatorRules } from './rules'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\nimport type { Value } from './validator-field'\n\nexport function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {\n const validator = new Validator()\n validator.addField({ value, rules })\n const { isValid, ...validateObject } = validator.validate()\n return [isValid, validateObject]\n}\n","import { createContext } from 'react'\n\nimport type { FieldParams, Validity } from './types'\n\nexport interface RegisteredFieldHandle {\n props: FieldParams\n validate: () => Validity\n}\n\nexport const Context = createContext<{\n registerField: (field: RegisteredFieldHandle) => void\n unregisterField: (field: RegisteredFieldHandle) => void\n customErrors: Array<Validity>\n}>(null)\n","import { forwardRef, type ReactNode, useContext, useEffect, useRef } from 'react'\nimport type { FieldParams, Validity } from 'types'\n\nimport { Context, type RegisteredFieldHandle } from './context'\nimport { Field } from './validator'\n\n// biome-ignore lint/suspicious/noExplicitAny: <need>\nexport type Value = any\n\ntype Fn = (validity: Validity, value: Value) => ReactNode\n\ntype Props = FieldParams & {\n children?: ReactNode | Fn\n}\n\nexport const ValidatorField = forwardRef<unknown, Props>(function ValidatorField(props: Props, _ref) {\n const { children, value } = props\n const { customErrors, registerField, unregisterField } = useContext(Context)\n\n const propsRef = useRef(props)\n propsRef.current = props\n\n const customErrorsRef = useRef(customErrors)\n customErrorsRef.current = customErrors\n\n const handleRef = useRef<RegisteredFieldHandle | null>(null)\n if (!handleRef.current) {\n handleRef.current = {\n get props() {\n return propsRef.current\n },\n validate: () => {\n const curr = propsRef.current\n const customError = customErrorsRef.current.find((item) => item.id === curr.id)\n if (customError) {\n return customError\n }\n const field = new Field({\n rules: curr.rules,\n required: curr.required,\n value: curr.value,\n id: curr.id,\n })\n return field.validate()\n },\n }\n }\n\n useEffect(() => {\n registerField(handleRef.current as RegisteredFieldHandle)\n return () => {\n unregisterField(handleRef.current as RegisteredFieldHandle)\n }\n }, [registerField, unregisterField])\n\n const validity = handleRef.current.validate()\n\n return typeof children === 'function' ? (children as Fn)(validity, value) : (children as ReactNode)\n})\n","import { forwardRef, type ReactNode, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'\n\nimport { Context, type RegisteredFieldHandle } from './context'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\n\ninterface ComponentProps {\n children?: ReactNode\n stopAtFirstError?: boolean\n}\n\nexport interface ValidatorWrapper {\n validate: () => Validity\n getField: (id: string | number) => RegisteredFieldHandle | null\n registerField: (field: RegisteredFieldHandle) => void\n unregisterField: (field: RegisteredFieldHandle) => void\n setCustomError: (customError: Validity) => void\n clearCustomErrors: () => void\n}\n\nexport const ValidatorWrapper = forwardRef<ValidatorWrapper, ComponentProps>(function ValidatorWrapper(\n { children, stopAtFirstError },\n ref,\n) {\n const fieldsRef = useRef<RegisteredFieldHandle[]>([])\n const [customErrors, setCustomErrors] = useState<Validity[]>([])\n\n const registerField = useCallback((field: RegisteredFieldHandle) => {\n if (field && !fieldsRef.current.includes(field)) {\n fieldsRef.current.push(field)\n }\n }, [])\n\n const unregisterField = useCallback((field: RegisteredFieldHandle) => {\n const index = fieldsRef.current.indexOf(field)\n if (index > -1) fieldsRef.current.splice(index, 1)\n }, [])\n\n const getField = useCallback<ValidatorWrapper['getField']>((id) => {\n return fieldsRef.current.find((field) => field?.props?.id === id) || null\n }, [])\n\n const setCustomError = useCallback<ValidatorWrapper['setCustomError']>((customError) => {\n setCustomErrors((prev) => [...prev, customError])\n }, [])\n\n const clearCustomErrors = useCallback<ValidatorWrapper['clearCustomErrors']>(() => {\n setCustomErrors([])\n }, [])\n\n const validate = useCallback<ValidatorWrapper['validate']>(() => {\n const validator = new Validator({ stopAtFirstError })\n for (const comp of fieldsRef.current) {\n validator.addField(comp.props)\n }\n return validator.validate()\n }, [stopAtFirstError])\n\n useImperativeHandle(\n ref,\n () => ({\n validate,\n getField,\n registerField,\n unregisterField,\n setCustomError,\n clearCustomErrors,\n }),\n [validate, getField, registerField, unregisterField, setCustomError, clearCustomErrors],\n )\n\n const contextValue = useMemo(\n () => ({ customErrors, registerField, unregisterField }),\n [customErrors, registerField, unregisterField],\n )\n\n return <Context.Provider value={contextValue}>{children}</Context.Provider>\n})\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {createContext,
|
|
1
|
+
import {createContext,forwardRef,useContext,useRef,useEffect,useState,useCallback,useImperativeHandle,useMemo}from'react';import {jsx}from'react/jsx-runtime';var h=/^(([^<>()[\]\\.,;:\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,}))$/,x={notEmpty:[{rule:r=>r!==""&&r.length>0,message:"Value is required"}],bool:[{rule:r=>!!r,message:"Value is required"}],password:[{rule:r=>r.length>0,message:"Password field cannot be empty"},{rule:r=>r.length>5,message:"Password field can not be less than 6 characters"}],email:[{rule:r=>!!r&&r!==""&&r.length!==0,message:"Email is required"},{rule:r=>h.test(String(r).toLowerCase()),message:"Email is invalid"}],min:r=>[{rule:e=>Number.parseFloat(e)>r,message:`The value must be greater than ${r}`}],max:r=>[{rule:e=>Number.parseFloat(e)<r,message:`The value must be smaller ${r}`}],length:(r,e)=>[{rule:t=>String(t).length>=r,message:`No less than ${r} symbols`},{rule:t=>e!==void 0?String(t).length<=e:true,message:`No more than ${e} symbols`}]};var V=class{rules;required;value;id;constructor({rules:e,required:t,value:s,id:i}){this.rules=e,this.required=t,this.value=s,this.id=i;}validate(){let e=true,t="",{rules:s,value:i,required:d,id:u}=this,n=!i&&Number.parseFloat(i)!==0;if(!s.length||n&&d===false)return {isValid:e,message:t,id:u};for(let a of s)e&&(e=a.rule(i),e||(typeof a.message=="function"?t=a.message(i):t=a.message));return {isValid:e,message:t,id:u}}},c=class{fields;params;constructor(e){this.params=e||null,this.fields=[];}addField(e){let t=new V(e);return this.fields.push(t),t}removeField(e){let t=this.fields.indexOf(e);t>-1&&this.fields.splice(t,1);}getField(e){return this.fields.find(t=>t.id===e)||null}validate(){let e,s=this.fields.map(i=>this.params?.stopAtFirstError&&e&&e.isValid===false?null:(e=i.validate(),e)).filter(i=>i&&i.isValid===false);if(s.length){let{isValid:i,message:d}=s[0];return {isValid:i,message:d,errors:s}}return {isValid:true,message:""}}};function b(r,e){let t=new c;t.addField({value:r,rules:e});let{isValid:s,...i}=t.validate();return [s,i]}var v=createContext(null);var w=forwardRef(function(e,t){let{children:s,value:i}=e,{customErrors:d,registerField:u,unregisterField:n}=useContext(v),a=useRef(e);a.current=e;let g=useRef(d);g.current=d;let p=useRef(null);p.current||(p.current={get props(){return a.current},validate:()=>{let m=a.current,y=g.current.find(o=>o.id===m.id);return y||new V({rules:m.rules,required:m.required,value:m.value,id:m.id}).validate()}}),useEffect(()=>(u(p.current),()=>{n(p.current);}),[u,n]);let F=p.current.validate();return typeof s=="function"?s(F,i):s});var S=forwardRef(function({children:e,stopAtFirstError:t},s){let i=useRef([]),[d,u]=useState([]),n=useCallback(l=>{l&&!i.current.includes(l)&&i.current.push(l);},[]),a=useCallback(l=>{let o=i.current.indexOf(l);o>-1&&i.current.splice(o,1);},[]),g=useCallback(l=>i.current.find(o=>o?.props?.id===l)||null,[]),p=useCallback(l=>{u(o=>[...o,l]);},[]),F=useCallback(()=>{u([]);},[]),m=useCallback(()=>{let l=new c({stopAtFirstError:t});for(let o of i.current)l.addField(o.props);return l.validate()},[t]);useImperativeHandle(s,()=>({validate:m,getField:g,registerField:n,unregisterField:a,setCustomError:p,clearCustomErrors:F}),[m,g,n,a,p,F]);let y=useMemo(()=>({customErrors:d,registerField:n,unregisterField:a}),[d,n,a]);return jsx(v.Provider,{value:y,children:e})});export{c as Validator,w as ValidatorField,S as ValidatorWrapper,x as rules,b as useValidator};//# sourceMappingURL=index.mjs.map
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rules.ts","../src/context.ts","../src/validator.ts","../src/validator-field.tsx","../src/validator-wrapper.tsx","../src/use-validator.ts"],"names":["emailReg","rules","value","min","max","Context","createContext","Field","required","id","isValid","message","isEmptyValue","instance","Validator","params","field","index","prevResult","errors","inst","ValidationFieldWrapper","Component","props","customError","item","children","validity","ValidatorField","jsx","data","ValidatorWrapper","validator","comp","useValidator","validateObject"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ValidatorRule } from './types'\n\n// eslint-disable-next-line\nconst emailReg =\n /^(([^<>()\\[\\]\\\\.,;:\\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,}))$/\n\nexport type ValidatorRules = ValidatorRule[]\n\nexport const rules = {\n notEmpty: [\n {\n rule: (value) => value !== '' && value.length > 0,\n message: 'Value is required',\n },\n ],\n\n bool: [\n {\n rule: (value) => !!value,\n message: 'Value is required',\n },\n ],\n\n password: [\n {\n rule: (value) => value.length > 0,\n message: 'Password field cannot be empty',\n },\n {\n rule: (value) => value.length > 5,\n message: 'Password field can not be less than 6 characters',\n },\n ],\n\n email: [\n {\n rule: (value) => !!value && value !== '' && value.length !== 0,\n message: 'Email is required',\n },\n {\n rule: (value) => emailReg.test(String(value).toLowerCase()),\n message: 'Email is invalid',\n },\n ],\n\n min: (min) => [\n {\n rule: (value) => Number.parseFloat(value) > min,\n message: `The value must be greater than ${min}`,\n },\n ],\n\n max: (max) => [\n {\n rule: (value) => Number.parseFloat(value) < max,\n message: `The value must be smaller ${max}`,\n },\n ],\n\n length: (min, max?) => [\n {\n rule: (value) => String(value).length >= min,\n message: `No less than ${min} symbols`,\n },\n {\n rule: (value) => (max !== undefined ? String(value).length <= max : true),\n message: `No more than ${max} symbols`,\n },\n ],\n}\n","import { createContext } from 'react'\n\nimport type { Validity } from './types'\n\nexport const Context = createContext<{\n registerField: (field: string | number) => void\n unregisterField: (field: string | number) => void\n customErrors: Array<Validity>\n}>(null)\n","import type { ValidatorRules } from './rules'\nimport type { FieldParams, Validity } from './types'\nimport type { Value } from './validator-field'\n\nexport class Field {\n private rules: ValidatorRules\n private required: boolean\n private value: Value\n public id: string | number\n\n constructor({ rules, required, value, id }: FieldParams) {\n this.rules = rules\n this.required = required\n this.value = value\n this.id = id\n }\n\n validate(): Validity {\n let isValid = true\n let message = ''\n const { rules, value, required, id } = this\n\n const isEmptyValue = !value && Number.parseFloat(value) !== 0\n\n if (!rules.length || (isEmptyValue && required === false)) {\n return { isValid, message, id }\n }\n for (const instance of rules) {\n if (isValid) {\n isValid = instance.rule(value)\n if (!isValid) {\n if (typeof instance.message === 'function') {\n message = instance.message(value)\n } else {\n message = instance.message\n }\n }\n }\n }\n return { isValid, message, id }\n }\n}\n\nexport interface ValidatorParams {\n stopAtFirstError: boolean\n}\n\nexport class Validator {\n private fields: Field[]\n private params: ValidatorParams\n\n constructor(params?: ValidatorParams) {\n this.params = params || null\n this.fields = []\n }\n\n addField(params: FieldParams): Field {\n const field = new Field(params)\n this.fields.push(field)\n return field\n }\n\n removeField(field: Field): void {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id: Field['id']): Field {\n return this.fields.find((field) => field.id === id) || null\n }\n\n validate(): Validity {\n let prevResult: Validity | null\n const statuses = this.fields.map((field) => {\n if (this.params?.stopAtFirstError && prevResult && prevResult.isValid === false) {\n return null\n }\n prevResult = field.validate()\n return prevResult\n })\n\n const errors = statuses.filter((inst) => inst && inst.isValid === false)\n\n if (errors.length) {\n const { isValid, message } = errors[0]\n return { isValid, message, errors }\n }\n return { isValid: true, message: '' }\n }\n}\n","import { Component, type ReactNode } from 'react'\nimport type { Validity } from 'types'\n\nimport { Context } from './context'\nimport type { ValidatorRules } from './rules'\nimport { Field } from './validator'\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\nexport type Value = any\n\ntype Fn = (validity: Validity, value: Value) => ReactNode\n\ninterface Props {\n rules?: ValidatorRules\n required?: boolean\n value?: Value\n id?: string | number\n children?: ReactNode | Fn\n unregisterField: (val: Value) => void\n registerField: (val: Value) => void\n customErrors: Array<Validity>\n}\n\nclass ValidationFieldWrapper extends Component<Props> {\n componentWillUnmount() {\n this.props.unregisterField(this)\n }\n\n componentDidMount() {\n this.props.registerField(this)\n }\n\n validate(): Validity {\n const props = this.props\n const customError = props.customErrors.find((item) => item.id === props.id)\n if (customError) {\n return customError\n }\n\n const field = new Field({\n rules: props.rules,\n required: props.required,\n value: props.value,\n id: props.id,\n })\n return field.validate()\n }\n\n render() {\n const { children, value } = this.props\n const validity = this.validate()\n return typeof children === 'function' ? children(validity, value) : children\n }\n}\n\nexport function ValidatorField(props: Omit<Props, 'registerField' | 'unregisterField' | 'customErrors'>) {\n return (\n <Context.Consumer>\n {(data) => (\n <ValidationFieldWrapper\n {...props}\n customErrors={data.customErrors}\n registerField={data.registerField}\n unregisterField={data.unregisterField}\n />\n )}\n </Context.Consumer>\n )\n}\n","import { Component, type ReactNode, type RefObject } from 'react'\n\nimport { Context } from './context'\nimport type { Validity } from './types'\nimport { type Field, Validator } from './validator'\n\ninterface ComponentProps {\n children?: ReactNode\n stopAtFirstError?: boolean\n ref?: RefObject<ValidatorWrapper>\n}\n\nexport class ValidatorWrapper extends Component<ComponentProps> {\n fields = []\n state = {\n customErrors: [],\n }\n\n constructor(props) {\n super(props)\n this.registerField = this.registerField.bind(this)\n this.unregisterField = this.unregisterField.bind(this)\n }\n\n componentWillUnmount() {\n this.fields = []\n }\n\n registerField(field) {\n if (field && !this.fields.includes(field)) {\n this.fields.push(field)\n }\n }\n\n unregisterField(field) {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id): Field | null {\n return this.fields.find((field) => field.props.id === id) || null\n }\n\n setCustomError(customError: Validity) {\n this.setState({\n customErrors: [...this.state.customErrors, customError],\n })\n }\n\n clearCustomErrors() {\n this.setState({ customErrors: [] })\n }\n\n validate(): Validity {\n const validator = new Validator({ stopAtFirstError: this.props.stopAtFirstError })\n for (const comp of this.fields) {\n validator.addField(comp.props)\n }\n return validator.validate()\n }\n\n render(): ReactNode {\n return (\n <Context.Provider\n value={{\n customErrors: this.state.customErrors,\n registerField: this.registerField,\n unregisterField: this.unregisterField,\n }}\n >\n {this.props.children}\n </Context.Provider>\n )\n }\n}\n","import type { ValidatorRules } from './rules'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\nimport type { Value } from './validator-field'\n\nexport function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {\n const validator = new Validator()\n validator.addField({ value, rules })\n const { isValid, ...validateObject } = validator.validate()\n return [isValid, validateObject]\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/rules.ts","../src/validator.ts","../src/use-validator.ts","../src/context.ts","../src/validator-field.tsx","../src/validator-wrapper.tsx"],"names":["emailReg","rules","value","min","max","Field","required","id","isValid","message","isEmptyValue","instance","Validator","params","field","index","prevResult","errors","inst","useValidator","validator","validateObject","Context","createContext","ValidatorField","forwardRef","props","_ref","children","customErrors","registerField","unregisterField","useContext","propsRef","useRef","customErrorsRef","handleRef","curr","customError","item","useEffect","validity","ValidatorWrapper","stopAtFirstError","ref","fieldsRef","setCustomErrors","useState","useCallback","getField","setCustomError","prev","clearCustomErrors","validate","comp","useImperativeHandle","contextValue","useMemo","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ValidatorRule } from './types'\n\n// eslint-disable-next-line\nconst emailReg =\n /^(([^<>()[\\]\\\\.,;:\\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,}))$/\n\nexport type ValidatorRules = ValidatorRule[]\n\nexport const rules = {\n notEmpty: [\n {\n rule: (value: string) => value !== '' && value.length > 0,\n message: 'Value is required',\n },\n ],\n\n bool: [\n {\n rule: (value: string) => !!value,\n message: 'Value is required',\n },\n ],\n\n password: [\n {\n rule: (value: string) => value.length > 0,\n message: 'Password field cannot be empty',\n },\n {\n rule: (value: string) => value.length > 5,\n message: 'Password field can not be less than 6 characters',\n },\n ],\n\n email: [\n {\n rule: (value: string) => !!value && value !== '' && value.length !== 0,\n message: 'Email is required',\n },\n {\n rule: (value: string) => emailReg.test(String(value).toLowerCase()),\n message: 'Email is invalid',\n },\n ],\n\n min: (min: number) => [\n {\n rule: (value: string) => Number.parseFloat(value) > min,\n message: `The value must be greater than ${min}`,\n },\n ],\n\n max: (max: number) => [\n {\n rule: (value: string) => Number.parseFloat(value) < max,\n message: `The value must be smaller ${max}`,\n },\n ],\n\n length: (min: number, max?: number) => [\n {\n rule: (value: string) => String(value).length >= min,\n message: `No less than ${min} symbols`,\n },\n {\n rule: (value: string) => (max !== undefined ? String(value).length <= max : true),\n message: `No more than ${max} symbols`,\n },\n ],\n}\n","import type { ValidatorRules } from './rules'\nimport type { FieldParams, Validity } from './types'\nimport type { Value } from './validator-field'\n\nexport class Field {\n protected rules: ValidatorRules\n protected required: boolean\n protected value: Value\n public id: string | number\n\n constructor({ rules, required, value, id }: FieldParams) {\n this.rules = rules\n this.required = required\n this.value = value\n this.id = id\n }\n\n validate(): Validity {\n let isValid = true\n let message = ''\n const { rules, value, required, id } = this\n\n const isEmptyValue = !value && Number.parseFloat(value) !== 0\n\n if (!rules.length || (isEmptyValue && required === false)) {\n return { isValid, message, id }\n }\n for (const instance of rules) {\n if (isValid) {\n isValid = instance.rule(value)\n if (!isValid) {\n if (typeof instance.message === 'function') {\n message = instance.message(value)\n } else {\n message = instance.message\n }\n }\n }\n }\n return { isValid, message, id }\n }\n}\n\nexport interface ValidatorParams {\n stopAtFirstError: boolean\n}\n\nexport class Validator {\n private fields: Field[]\n private params: ValidatorParams\n\n constructor(params?: ValidatorParams) {\n this.params = params || null\n this.fields = []\n }\n\n addField(params: FieldParams): Field {\n const field = new Field(params)\n this.fields.push(field)\n return field\n }\n\n removeField(field: Field): void {\n const index = this.fields.indexOf(field)\n if (index > -1) this.fields.splice(index, 1)\n }\n\n getField(id: Field['id']): Field {\n return this.fields.find((field) => field.id === id) || null\n }\n\n validate(): Validity {\n let prevResult: Validity | null\n const statuses = this.fields.map((field) => {\n if (this.params?.stopAtFirstError && prevResult && prevResult.isValid === false) {\n return null\n }\n prevResult = field.validate()\n return prevResult\n })\n\n const errors = statuses.filter((inst) => inst && inst.isValid === false)\n\n if (errors.length) {\n const { isValid, message } = errors[0]\n return { isValid, message, errors }\n }\n return { isValid: true, message: '' }\n }\n}\n","import type { ValidatorRules } from './rules'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\nimport type { Value } from './validator-field'\n\nexport function useValidator(value: Value, rules: ValidatorRules): [boolean, Pick<Validity, 'message' | 'errors'>] {\n const validator = new Validator()\n validator.addField({ value, rules })\n const { isValid, ...validateObject } = validator.validate()\n return [isValid, validateObject]\n}\n","import { createContext } from 'react'\n\nimport type { FieldParams, Validity } from './types'\n\nexport interface RegisteredFieldHandle {\n props: FieldParams\n validate: () => Validity\n}\n\nexport const Context = createContext<{\n registerField: (field: RegisteredFieldHandle) => void\n unregisterField: (field: RegisteredFieldHandle) => void\n customErrors: Array<Validity>\n}>(null)\n","import { forwardRef, type ReactNode, useContext, useEffect, useRef } from 'react'\nimport type { FieldParams, Validity } from 'types'\n\nimport { Context, type RegisteredFieldHandle } from './context'\nimport { Field } from './validator'\n\n// biome-ignore lint/suspicious/noExplicitAny: <need>\nexport type Value = any\n\ntype Fn = (validity: Validity, value: Value) => ReactNode\n\ntype Props = FieldParams & {\n children?: ReactNode | Fn\n}\n\nexport const ValidatorField = forwardRef<unknown, Props>(function ValidatorField(props: Props, _ref) {\n const { children, value } = props\n const { customErrors, registerField, unregisterField } = useContext(Context)\n\n const propsRef = useRef(props)\n propsRef.current = props\n\n const customErrorsRef = useRef(customErrors)\n customErrorsRef.current = customErrors\n\n const handleRef = useRef<RegisteredFieldHandle | null>(null)\n if (!handleRef.current) {\n handleRef.current = {\n get props() {\n return propsRef.current\n },\n validate: () => {\n const curr = propsRef.current\n const customError = customErrorsRef.current.find((item) => item.id === curr.id)\n if (customError) {\n return customError\n }\n const field = new Field({\n rules: curr.rules,\n required: curr.required,\n value: curr.value,\n id: curr.id,\n })\n return field.validate()\n },\n }\n }\n\n useEffect(() => {\n registerField(handleRef.current as RegisteredFieldHandle)\n return () => {\n unregisterField(handleRef.current as RegisteredFieldHandle)\n }\n }, [registerField, unregisterField])\n\n const validity = handleRef.current.validate()\n\n return typeof children === 'function' ? (children as Fn)(validity, value) : (children as ReactNode)\n})\n","import { forwardRef, type ReactNode, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'\n\nimport { Context, type RegisteredFieldHandle } from './context'\nimport type { Validity } from './types'\nimport { Validator } from './validator'\n\ninterface ComponentProps {\n children?: ReactNode\n stopAtFirstError?: boolean\n}\n\nexport interface ValidatorWrapper {\n validate: () => Validity\n getField: (id: string | number) => RegisteredFieldHandle | null\n registerField: (field: RegisteredFieldHandle) => void\n unregisterField: (field: RegisteredFieldHandle) => void\n setCustomError: (customError: Validity) => void\n clearCustomErrors: () => void\n}\n\nexport const ValidatorWrapper = forwardRef<ValidatorWrapper, ComponentProps>(function ValidatorWrapper(\n { children, stopAtFirstError },\n ref,\n) {\n const fieldsRef = useRef<RegisteredFieldHandle[]>([])\n const [customErrors, setCustomErrors] = useState<Validity[]>([])\n\n const registerField = useCallback((field: RegisteredFieldHandle) => {\n if (field && !fieldsRef.current.includes(field)) {\n fieldsRef.current.push(field)\n }\n }, [])\n\n const unregisterField = useCallback((field: RegisteredFieldHandle) => {\n const index = fieldsRef.current.indexOf(field)\n if (index > -1) fieldsRef.current.splice(index, 1)\n }, [])\n\n const getField = useCallback<ValidatorWrapper['getField']>((id) => {\n return fieldsRef.current.find((field) => field?.props?.id === id) || null\n }, [])\n\n const setCustomError = useCallback<ValidatorWrapper['setCustomError']>((customError) => {\n setCustomErrors((prev) => [...prev, customError])\n }, [])\n\n const clearCustomErrors = useCallback<ValidatorWrapper['clearCustomErrors']>(() => {\n setCustomErrors([])\n }, [])\n\n const validate = useCallback<ValidatorWrapper['validate']>(() => {\n const validator = new Validator({ stopAtFirstError })\n for (const comp of fieldsRef.current) {\n validator.addField(comp.props)\n }\n return validator.validate()\n }, [stopAtFirstError])\n\n useImperativeHandle(\n ref,\n () => ({\n validate,\n getField,\n registerField,\n unregisterField,\n setCustomError,\n clearCustomErrors,\n }),\n [validate, getField, registerField, unregisterField, setCustomError, clearCustomErrors],\n )\n\n const contextValue = useMemo(\n () => ({ customErrors, registerField, unregisterField }),\n [customErrors, registerField, unregisterField],\n )\n\n return <Context.Provider value={contextValue}>{children}</Context.Provider>\n})\n"]}
|
package/example/example.tsx
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { Validator, ValidatorField, ValidatorWrapper, rules } from '../dist/index'
|
|
1
|
+
import React, { createRef, useState } from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom/client'
|
|
3
|
+
import { rules, Validator, ValidatorField, ValidatorWrapper } from '../dist/index'
|
|
6
4
|
|
|
7
5
|
function App() {
|
|
8
6
|
const [email, setEmail] = useState('')
|
|
@@ -44,28 +42,26 @@ function App() {
|
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
return (
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
</ValidatorWrapper>
|
|
65
|
-
</>
|
|
45
|
+
<ValidatorWrapper ref={jsxValidator}>
|
|
46
|
+
<ValidatorField rules={rules.email} value={email}>
|
|
47
|
+
{({ isValid, message }) => (
|
|
48
|
+
<>
|
|
49
|
+
<input onChange={({ target: { value } }) => setEmail(value)} />
|
|
50
|
+
<div>{isValid ? 'valid' : 'invalid'}</div>
|
|
51
|
+
<div>{message || ''}</div>
|
|
52
|
+
<button onClick={handleValidateEmail} type="button">
|
|
53
|
+
Validate email
|
|
54
|
+
</button>
|
|
55
|
+
</>
|
|
56
|
+
)}
|
|
57
|
+
</ValidatorField>
|
|
58
|
+
<button onClick={handleValidateCustomFields} type="button">
|
|
59
|
+
Validate custom fields
|
|
60
|
+
</button>
|
|
61
|
+
</ValidatorWrapper>
|
|
66
62
|
)
|
|
67
63
|
}
|
|
68
64
|
|
|
69
|
-
const root = createRoot(document.getElementById('root'))
|
|
65
|
+
const root = ReactDOM.createRoot(document.getElementById('root'))
|
|
70
66
|
|
|
71
67
|
root.render(<App />)
|
package/example/index.html
CHANGED
|
@@ -3,14 +3,9 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<title>Test template</title>
|
|
6
|
-
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
|
7
|
-
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
|
8
6
|
</head>
|
|
9
7
|
<body>
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
<script src="./dist/example.js"></script>
|
|
14
|
-
|
|
8
|
+
<div id="root"></div>
|
|
9
|
+
<script type="module" src="./dist/example.js"></script>
|
|
15
10
|
</body>
|
|
16
11
|
</html>
|
package/example/tsconfig.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "../tsconfig.json",
|
|
3
2
|
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"jsx": "react",
|
|
4
6
|
"outDir": "./dist",
|
|
5
|
-
"
|
|
6
|
-
"baseUrl": "./"
|
|
7
|
+
"allowSyntheticDefaultImports": true
|
|
7
8
|
},
|
|
8
|
-
"include": ["example.tsx"]
|
|
9
|
-
|
|
10
|
-
}
|
|
9
|
+
"include": ["example.tsx"]
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coxy/react-validator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "🚀 Simple validation form for React or NodeJS apps. useValidator are included ;)",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -23,30 +23,29 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"start": "tsup ./src/index.ts --watch",
|
|
25
25
|
"build": "tsup",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
26
|
+
"lint": "biome lint --fix",
|
|
27
|
+
"example": "NODE_ENV=production npx esbuild example/example.tsx --bundle --outfile=example/dist/example.js --minify --format=esm --target=es2020",
|
|
28
|
+
"coverage": "npx codecov",
|
|
29
|
+
"coveralls": "npx coveralls .",
|
|
29
30
|
"test": "jest"
|
|
30
31
|
},
|
|
31
32
|
"license": "MIT",
|
|
32
33
|
"peerDependencies": {
|
|
33
|
-
"react": ">=
|
|
34
|
-
},
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"react": ">=19.x.x"
|
|
34
|
+
"react": ">=18.x.x"
|
|
37
35
|
},
|
|
36
|
+
"dependencies": {},
|
|
38
37
|
"devDependencies": {
|
|
39
|
-
"
|
|
38
|
+
"react": ">=18.x.x",
|
|
39
|
+
"react-dom": ">=18.x.x",
|
|
40
|
+
"@biomejs/biome": "2.2.2",
|
|
40
41
|
"@testing-library/dom": "10.4.1",
|
|
41
42
|
"@testing-library/react": "16.3.0",
|
|
42
43
|
"@types/jest": "30.0.0",
|
|
43
44
|
"@types/node": "24.1.0",
|
|
44
|
-
"@types/react": "19.1.
|
|
45
|
-
"
|
|
46
|
-
"coveralls": "3.1.1",
|
|
45
|
+
"@types/react": "19.1.11",
|
|
46
|
+
"@types/react-dom": "19.1.7",
|
|
47
47
|
"jest": "30.0.5",
|
|
48
48
|
"jest-environment-jsdom": "30.0.5",
|
|
49
|
-
"react-dom": "19.1.1",
|
|
50
49
|
"tsup": "8.5.0",
|
|
51
50
|
"react-test-renderer": "19.1.1",
|
|
52
51
|
"ts-jest": "29.4.0",
|