@coxy/react-validator 2.0.7 → 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.
Files changed (49) hide show
  1. package/README.md +145 -120
  2. package/biome.json +34 -0
  3. package/dist/index.d.mts +106 -0
  4. package/dist/index.d.ts +106 -6
  5. package/dist/index.js +2 -28
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +2 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/example/example.tsx +26 -26
  10. package/example/index.html +2 -7
  11. package/example/tsconfig.json +6 -11
  12. package/package.json +26 -36
  13. package/src/context.ts +8 -3
  14. package/src/custom-errors.test.tsx +73 -0
  15. package/src/index.test.ts +19 -4
  16. package/src/index.ts +4 -3
  17. package/src/rules.test.ts +15 -10
  18. package/src/rules.ts +15 -15
  19. package/src/types.ts +3 -2
  20. package/src/use-validator.test.tsx +4 -7
  21. package/src/use-validator.ts +3 -3
  22. package/src/validator-field.test.tsx +45 -18
  23. package/src/validator-field.tsx +44 -53
  24. package/src/validator-wrapper.test.tsx +41 -27
  25. package/src/validator-wrapper.tsx +60 -57
  26. package/src/validator.test.tsx +10 -0
  27. package/src/validator.ts +10 -10
  28. package/tsconfig.json +6 -16
  29. package/tsup.config.ts +14 -0
  30. package/.eslintignore +0 -2
  31. package/.eslintrc.js +0 -5
  32. package/.prettierrc.js +0 -10
  33. package/CHANGELOG.md +0 -49
  34. package/dist/context.d.ts +0 -7
  35. package/dist/context.js +0 -5
  36. package/dist/rules.d.ts +0 -32
  37. package/dist/rules.js +0 -60
  38. package/dist/types.d.ts +0 -24
  39. package/dist/types.js +0 -2
  40. package/dist/use-validator.d.ts +0 -4
  41. package/dist/use-validator.js +0 -22
  42. package/dist/validator-field.d.ts +0 -17
  43. package/dist/validator-field.js +0 -38
  44. package/dist/validator-wrapper.d.ts +0 -24
  45. package/dist/validator-wrapper.js +0 -57
  46. package/dist/validator.d.ts +0 -21
  47. package/dist/validator.js +0 -72
  48. package/src/jest.d.ts +0 -1
  49. package/tsconfig.build.json +0 -12
@@ -0,0 +1 @@
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 ADDED
@@ -0,0 +1,2 @@
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
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
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"]}
@@ -1,14 +1,12 @@
1
- /* eslint no-console: [0] */
2
- import { useState, createRef } from 'react'
3
- import { createRoot } from 'react-dom/client'
1
+ import React, { createRef, useState } from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import { rules, Validator, ValidatorField, ValidatorWrapper } from '../dist/index'
4
4
 
5
- import { ValidatorWrapper, rules, ValidatorField, Validator } from '../dist/index'
6
-
7
- function App () {
5
+ function App() {
8
6
  const [email, setEmail] = useState('')
9
7
  const jsxValidator = createRef<ValidatorWrapper>()
10
8
 
11
- function handleValidateEmail () {
9
+ function handleValidateEmail() {
12
10
  const { isValid, message, errors } = jsxValidator.current.validate()
13
11
  if (!isValid) {
14
12
  console.log(isValid, message, errors)
@@ -17,12 +15,12 @@ function App () {
17
15
  console.log('success')
18
16
  }
19
17
 
20
- function handleValidateCustomFields () {
18
+ function handleValidateCustomFields() {
21
19
  const validator = new Validator({ stopAtFirstError: true })
22
20
  const fieldPassword = validator.addField({
23
21
  rules: rules.password,
24
22
  value: '',
25
- id: 'for-remove'
23
+ id: 'for-remove',
26
24
  })
27
25
 
28
26
  const fieldSearchPassword = validator.getField('for-remove')
@@ -32,7 +30,7 @@ function App () {
32
30
 
33
31
  validator.addField({
34
32
  rules: rules.password,
35
- value: 'testpassword'
33
+ value: 'testpassword',
36
34
  })
37
35
 
38
36
  const { isValid, message, errors } = validator.validate()
@@ -44,24 +42,26 @@ function App () {
44
42
  }
45
43
 
46
44
  return (
47
- <>
48
- <ValidatorWrapper ref={jsxValidator}>
49
- <ValidatorField rules={rules.email} value={email}>
50
- {({ isValid, message }) => (
51
- <>
52
- <input onChange={({ target: { value } }) => setEmail(value)} />
53
- <div>{isValid ? 'valid' : 'invalid'}</div>
54
- <div>{message || ''}</div>
55
- <button onClick={handleValidateEmail} type="button">Validate email</button>
56
- </>
57
- )}
58
- </ValidatorField>
59
- <button onClick={handleValidateCustomFields} type="button">Validate custom fields</button>
60
- </ValidatorWrapper>
61
- </>
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>
62
62
  )
63
63
  }
64
64
 
65
- const root = createRoot(document.getElementById('root'))
65
+ const root = ReactDOM.createRoot(document.getElementById('root'))
66
66
 
67
67
  root.render(<App />)
@@ -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
- <div id="root"></div>
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>
@@ -1,15 +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
- "rootDir": ".",
6
- "baseUrl": "./",
7
+ "allowSyntheticDefaultImports": true
7
8
  },
8
- "include": [
9
- "example.tsx"
10
- ],
11
- "exclude": [
12
- "node_modules",
13
- "dist"
14
- ]
15
- }
9
+ "include": ["example.tsx"]
10
+ }
package/package.json CHANGED
@@ -1,8 +1,10 @@
1
1
  {
2
2
  "name": "@coxy/react-validator",
3
- "version": "2.0.7",
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
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
6
8
  "repository": {
7
9
  "type": "git",
8
10
  "url": "https://github.com/dsshard/react-validator.git"
@@ -19,47 +21,35 @@
19
21
  ],
20
22
  "author": "dsshard",
21
23
  "scripts": {
22
- "start": "ts-node . --watch",
23
- "build": "NODE_ENV=production tsc --project tsconfig.build.json",
24
- "example": "tsc --project ./example/tsconfig.json",
25
- "coverage": "codecov",
26
- "coveralls": "coveralls .",
24
+ "start": "tsup ./src/index.ts --watch",
25
+ "build": "tsup",
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 .",
27
30
  "test": "jest"
28
31
  },
29
32
  "license": "MIT",
30
33
  "peerDependencies": {
31
34
  "react": ">=18.x.x"
32
35
  },
33
- "dependencies": {
34
- "react": ">=18.x.x"
35
- },
36
+ "dependencies": {},
36
37
  "devDependencies": {
37
- "@coxy/eslint-config": "1.0.6",
38
- "@testing-library/react": "13.4.0",
39
- "@types/jest": "29.1.2",
40
- "@types/node": "18.8.3",
41
- "@types/react": "18.0.21",
42
- "@typescript-eslint/eslint-plugin": "5.*",
43
- "@typescript-eslint/parser": "5.*",
44
- "codecov": "3.8.3",
45
- "coveralls": "3.1.1",
46
- "eslint": "8.25.0",
47
- "eslint-config-standard": "17.0.0",
48
- "eslint-config-prettier": "8.8.0",
49
- "eslint-plugin-import": "2.26.0",
50
- "eslint-plugin-jsx-a11y": "6.6.1",
51
- "eslint-plugin-n": "15.3.0",
52
- "eslint-plugin-promise": "6.0.1",
53
- "eslint-plugin-filename-rules": "1.2.0",
54
- "eslint-plugin-react": "7.31.8",
55
- "eslint-plugin-prettier": "4.2.1",
56
- "jest": "29.1.2",
57
- "jest-environment-jsdom": "29.1.2",
58
- "prettier": "2.8.7",
59
- "react-dom": "18.2.0",
60
- "react-test-renderer": "18.2.0",
61
- "ts-jest": "29.0.3",
62
- "ts-node": "10.9.1",
63
- "typescript": "4.8.4"
38
+ "react": ">=18.x.x",
39
+ "react-dom": ">=18.x.x",
40
+ "@biomejs/biome": "2.2.2",
41
+ "@testing-library/dom": "10.4.1",
42
+ "@testing-library/react": "16.3.0",
43
+ "@types/jest": "30.0.0",
44
+ "@types/node": "24.1.0",
45
+ "@types/react": "19.1.11",
46
+ "@types/react-dom": "19.1.7",
47
+ "jest": "30.0.5",
48
+ "jest-environment-jsdom": "30.0.5",
49
+ "tsup": "8.5.0",
50
+ "react-test-renderer": "19.1.1",
51
+ "ts-jest": "29.4.0",
52
+ "ts-node": "10.9.2",
53
+ "typescript": "5.8.3"
64
54
  }
65
55
  }
package/src/context.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import { createContext } from 'react'
2
2
 
3
- import { Validity } from './types'
3
+ import type { FieldParams, Validity } from './types'
4
+
5
+ export interface RegisteredFieldHandle {
6
+ props: FieldParams
7
+ validate: () => Validity
8
+ }
4
9
 
5
10
  export const Context = createContext<{
6
- registerField: (field: string | number) => void
7
- unregisterField: (field: string | number) => void
11
+ registerField: (field: RegisteredFieldHandle) => void
12
+ unregisterField: (field: RegisteredFieldHandle) => void
8
13
  customErrors: Array<Validity>
9
14
  }>(null)
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+
5
+ import { act, render } from '@testing-library/react'
6
+ import { createRef } from 'react'
7
+
8
+ import { rules } from './rules'
9
+ import { ValidatorField } from './validator-field'
10
+ import { ValidatorWrapper, type ValidatorWrapper as ValidatorWrapperHandle } from './validator-wrapper'
11
+
12
+ it('setCustomError overrides field validation result and clearCustomErrors restores it', () => {
13
+ const validator = createRef<ValidatorWrapperHandle>()
14
+
15
+ render(
16
+ <ValidatorWrapper ref={validator}>
17
+ <ValidatorField id="email-field" rules={rules.email} value="user@example.com" />
18
+ </ValidatorWrapper>,
19
+ )
20
+
21
+ // Initially valid
22
+ const fieldBefore = validator.current.getField('email-field')
23
+ const validityBefore = fieldBefore.validate()
24
+ expect(validityBefore.isValid).toBe(true)
25
+ expect(validityBefore.message).toBe('')
26
+
27
+ // Set a custom error
28
+ act(() => {
29
+ validator.current.setCustomError({ id: 'email-field', isValid: false, message: 'Custom error' })
30
+ })
31
+
32
+ const fieldWithCustom = validator.current.getField('email-field')
33
+ const validityWithCustom = fieldWithCustom.validate()
34
+ expect(validityWithCustom.isValid).toBe(false)
35
+ expect(validityWithCustom.message).toBe('Custom error')
36
+
37
+ // Clear custom errors
38
+ act(() => {
39
+ validator.current.clearCustomErrors()
40
+ })
41
+ const fieldAfter = validator.current.getField('email-field')
42
+ const validityAfter = fieldAfter.validate()
43
+ expect(validityAfter.isValid).toBe(true)
44
+ expect(validityAfter.message).toBe('')
45
+ })
46
+
47
+ it('custom error is used inside ValidatorField render-prop child', () => {
48
+ const validator = createRef<ValidatorWrapperHandle>()
49
+ const messages: string[] = []
50
+
51
+ render(
52
+ <ValidatorWrapper ref={validator}>
53
+ <ValidatorField id="field-x" rules={rules.password} value="strongpassword">
54
+ {({ message }) => {
55
+ messages.push(message)
56
+ return null
57
+ }}
58
+ </ValidatorField>
59
+ </ValidatorWrapper>,
60
+ )
61
+
62
+ // Initially valid → message pushed should be ''
63
+ expect(messages[messages.length - 1]).toBe('')
64
+
65
+ // After setting custom error, the render-prop should see the custom message.
66
+ act(() => {
67
+ validator.current.setCustomError({ id: 'field-x', isValid: false, message: 'Injected' })
68
+ })
69
+ const field = validator.current.getField('field-x')
70
+ const res = field.validate()
71
+ expect(res.isValid).toBe(false)
72
+ expect(res.message).toBe('Injected')
73
+ })
package/src/index.test.ts CHANGED
@@ -1,7 +1,22 @@
1
- import { ValidatorWrapper, ValidatorField, rules } from './index'
1
+ import { rules, useValidator, Validator, ValidatorField, ValidatorWrapper } from './index'
2
2
 
3
- it('renders with or without a name', () => {
4
- expect(typeof ValidatorWrapper).toBe('function')
5
- expect(typeof ValidatorField).toBe('function')
3
+ it('exports surface is available', () => {
4
+ expect(typeof ValidatorWrapper).toBe('object')
5
+ expect(typeof ValidatorField).toBe('object')
6
6
  expect(typeof rules).toBe('object')
7
+ expect(typeof Validator).toBe('function')
8
+ expect(typeof useValidator).toBe('function')
9
+ })
10
+
11
+ it('use exports to execute a basic validation flow', () => {
12
+ // use Validator (class)
13
+ const validator = new Validator()
14
+ validator.addField({ value: 'test@example.com', rules: rules.email })
15
+ const res = validator.validate()
16
+ expect(res.isValid).toBe(true)
17
+
18
+ // use useValidator (hook-like util function)
19
+ const [isValid, { message }] = useValidator('bad-email', rules.email)
20
+ expect(isValid).toBe(false)
21
+ expect(message).toBe('Email is invalid')
7
22
  })
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { rules } from './rules'
2
+
3
+ export type { ErrorMessage, FieldParams, ValidatorRule, Validity } from './types'
4
+ export { useValidator } from './use-validator'
5
+ export { Validator } from './validator'
2
6
  export { ValidatorField } from './validator-field'
3
7
  export { ValidatorWrapper } from './validator-wrapper'
4
- export { Validator } from './validator'
5
- export { useValidator } from './use-validator'
6
- export * from './types'
package/src/rules.test.ts CHANGED
@@ -3,7 +3,7 @@ import { rules } from './rules'
3
3
  it('check rule email', () => {
4
4
  expect(rules.email.length).toBe(2)
5
5
 
6
- let result
6
+ let result: boolean
7
7
  // email.length > 0
8
8
  result = rules.email[0].rule('test')
9
9
  expect(result).toBe(true)
@@ -20,7 +20,7 @@ it('check rule email', () => {
20
20
  it('check rule password', () => {
21
21
  expect(rules.password.length).toBe(2)
22
22
 
23
- let result
23
+ let result: boolean
24
24
  // password.length > 0
25
25
  result = rules.password[0].rule('test')
26
26
  expect(result).toBe(true)
@@ -33,6 +33,7 @@ it('check rule password', () => {
33
33
  it('check rule bool', () => {
34
34
  expect(rules.bool.length).toBe(1)
35
35
 
36
+ // @ts-expect-error
36
37
  const result = rules.bool[0].rule(true)
37
38
  expect(result).toBe(true)
38
39
  })
@@ -40,7 +41,7 @@ it('check rule bool', () => {
40
41
  it('check rule notEmpty', () => {
41
42
  expect(rules.notEmpty.length).toBe(1)
42
43
 
43
- let result
44
+ let result: boolean
44
45
  result = rules.notEmpty[0].rule('')
45
46
  expect(result).toBe(false)
46
47
 
@@ -52,22 +53,24 @@ it('check rule min', () => {
52
53
  expect(rules.min(1).length).toBe(1)
53
54
  expect(typeof rules.min).toBe('function')
54
55
 
55
- let result
56
+ let result: boolean
56
57
  result = rules.min(10)[0].rule('')
57
58
  expect(result).toBe(false)
58
59
 
59
- result = rules.min(9)[0].rule('testtesttest')
60
+ result = rules.min(9)[0].rule('test-test-test')
60
61
  expect(result).toBe(false)
61
62
 
62
63
  result = rules.min(9)[0].rule('11')
63
64
  expect(result).toBe(true)
64
65
 
66
+ // @ts-expect-error
65
67
  result = rules.min(9)[0].rule(10)
66
68
  expect(result).toBe(true)
67
69
 
68
70
  result = rules.min(9)[0].rule('8')
69
71
  expect(result).toBe(false)
70
72
 
73
+ // @ts-expect-error
71
74
  result = rules.min(9)[0].rule(7)
72
75
  expect(result).toBe(false)
73
76
 
@@ -76,22 +79,24 @@ it('check rule min', () => {
76
79
  })
77
80
 
78
81
  it('check rule max', () => {
79
- let result
82
+ let result: boolean
80
83
  result = rules.max(10)[0].rule('')
81
84
  expect(result).toBe(false)
82
85
 
83
- result = rules.max(9)[0].rule('testtesttest')
86
+ result = rules.max(9)[0].rule('test-test-test')
84
87
  expect(result).toBe(false)
85
88
 
86
89
  result = rules.max(9)[0].rule('11')
87
90
  expect(result).toBe(false)
88
91
 
92
+ // @ts-expect-error
89
93
  result = rules.max(9)[0].rule(10)
90
94
  expect(result).toBe(false)
91
95
 
92
96
  result = rules.max(9)[0].rule('5')
93
97
  expect(result).toBe(true)
94
98
 
99
+ // @ts-expect-error
95
100
  result = rules.max(9)[0].rule(5)
96
101
  expect(result).toBe(true)
97
102
 
@@ -100,17 +105,17 @@ it('check rule max', () => {
100
105
  })
101
106
 
102
107
  it('check rule length', () => {
103
- let result
108
+ let result: boolean
104
109
  result = rules.length(1)[0].rule('')
105
110
  expect(result).toBe(false)
106
111
 
107
112
  result = rules.length(1)[0].rule('1')
108
113
  expect(result).toBe(true)
109
114
 
110
- result = rules.length(1, 10)[0].rule('testtesttest')
115
+ result = rules.length(1, 10)[0].rule('test-test-test')
111
116
  expect(result).toBe(true)
112
117
 
113
- result = rules.length(1, 10)[1].rule('testtesttest')
118
+ result = rules.length(1, 10)[1].rule('test-test-test')
114
119
  expect(result).toBe(false)
115
120
 
116
121
  result = rules.length(1, 10)[0].rule('lol')
package/src/rules.ts CHANGED
@@ -1,69 +1,69 @@
1
- import { ValidatorRule } from './types'
1
+ import type { ValidatorRule } from './types'
2
2
 
3
3
  // eslint-disable-next-line
4
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
+ /^(([^<>()[\]\\.,;:\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,}))$/
6
6
 
7
7
  export type ValidatorRules = ValidatorRule[]
8
8
 
9
9
  export const rules = {
10
10
  notEmpty: [
11
11
  {
12
- rule: (value) => value !== '' && value.length > 0,
12
+ rule: (value: string) => value !== '' && value.length > 0,
13
13
  message: 'Value is required',
14
14
  },
15
15
  ],
16
16
 
17
17
  bool: [
18
18
  {
19
- rule: (value) => !!value,
19
+ rule: (value: string) => !!value,
20
20
  message: 'Value is required',
21
21
  },
22
22
  ],
23
23
 
24
24
  password: [
25
25
  {
26
- rule: (value) => value.length > 0,
26
+ rule: (value: string) => value.length > 0,
27
27
  message: 'Password field cannot be empty',
28
28
  },
29
29
  {
30
- rule: (value) => value.length > 5,
30
+ rule: (value: string) => value.length > 5,
31
31
  message: 'Password field can not be less than 6 characters',
32
32
  },
33
33
  ],
34
34
 
35
35
  email: [
36
36
  {
37
- rule: (value) => !!value && value !== '' && value.length !== 0,
37
+ rule: (value: string) => !!value && value !== '' && value.length !== 0,
38
38
  message: 'Email is required',
39
39
  },
40
40
  {
41
- rule: (value) => emailReg.test(String(value).toLowerCase()),
41
+ rule: (value: string) => emailReg.test(String(value).toLowerCase()),
42
42
  message: 'Email is invalid',
43
43
  },
44
44
  ],
45
45
 
46
- min: (min) => [
46
+ min: (min: number) => [
47
47
  {
48
- rule: (value) => parseFloat(value) > min,
48
+ rule: (value: string) => Number.parseFloat(value) > min,
49
49
  message: `The value must be greater than ${min}`,
50
50
  },
51
51
  ],
52
52
 
53
- max: (max) => [
53
+ max: (max: number) => [
54
54
  {
55
- rule: (value) => parseFloat(value) < max,
55
+ rule: (value: string) => Number.parseFloat(value) < max,
56
56
  message: `The value must be smaller ${max}`,
57
57
  },
58
58
  ],
59
59
 
60
- length: (min, max?) => [
60
+ length: (min: number, max?: number) => [
61
61
  {
62
- rule: (value) => String(value).length >= min,
62
+ rule: (value: string) => String(value).length >= min,
63
63
  message: `No less than ${min} symbols`,
64
64
  },
65
65
  {
66
- rule: (value) => (max !== undefined ? String(value).length <= max : true),
66
+ rule: (value: string) => (max !== undefined ? String(value).length <= max : true),
67
67
  message: `No more than ${max} symbols`,
68
68
  },
69
69
  ],
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { ValidatorRules } from './rules'
2
- import { Value } from './validator-field'
1
+ import type { ValidatorRules } from './rules'
2
+ import type { Value } from './validator-field'
3
+
3
4
  type Fn = (value: Value) => string
4
5
 
5
6
  export interface ValidatorRule {