mirror of
https://github.com/cupcakearmy/formhero.git
synced 2024-12-22 16:16:24 +00:00
added arrays of validators
This commit is contained in:
parent
f402146f87
commit
47748b568e
@ -7,10 +7,24 @@ const Index: React.FC = () => {
|
|||||||
|
|
||||||
const { auto, form, errors } = useForm({
|
const { auto, form, errors } = useForm({
|
||||||
username: '',
|
username: '',
|
||||||
|
email: '',
|
||||||
password: ''
|
password: ''
|
||||||
}, {
|
}, {
|
||||||
username: value => value.length > 3,
|
username: value => value.length > 3,
|
||||||
password: /[\d]{1,}/
|
email: {
|
||||||
|
validator: /@/,
|
||||||
|
message: 'Must contain an @',
|
||||||
|
},
|
||||||
|
password: [
|
||||||
|
{
|
||||||
|
validator: /[A-Z]/,
|
||||||
|
message: 'Must contain an uppercase letter'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: /[\d]/,
|
||||||
|
message: 'Must contain a digit'
|
||||||
|
},
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -21,8 +35,11 @@ const Index: React.FC = () => {
|
|||||||
<input {...auto('username')} placeholder="Username" />
|
<input {...auto('username')} placeholder="Username" />
|
||||||
{errors.username && 'Must be longer than 3'}
|
{errors.username && 'Must be longer than 3'}
|
||||||
|
|
||||||
|
<input {...auto('email')} placeholder="EMail" />
|
||||||
|
{errors.email}
|
||||||
|
|
||||||
<input {...auto('password')} placeholder="Password" type="password" />
|
<input {...auto('password')} placeholder="Password" type="password" />
|
||||||
{errors.password && 'Must contain a number'}
|
{errors.password}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
|
69
lib/index.ts
69
lib/index.ts
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -20,13 +20,26 @@ export type useFormValidatorObject = {
|
|||||||
|
|
||||||
export type useFormValidator = useFormValidatorMethod | useFormValidatorObject
|
export type useFormValidator = useFormValidatorMethod | useFormValidatorObject
|
||||||
|
|
||||||
|
export type useFormValidatorParameter = useFormValidator | useFormValidator[]
|
||||||
|
|
||||||
export const HTMLInputExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.value
|
export const HTMLInputExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.value
|
||||||
export const HTMLCheckboxExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.checked
|
export const HTMLCheckboxExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.checked
|
||||||
|
|
||||||
export const useForm = <T, U extends { [key in keyof T]: useFormValidator }, E extends { [key in keyof U]?: string }>(init: T, validators: Partial<U> = {}, options: useFormOptions = {}) => {
|
function isFormValidatorObject(validator: useFormValidatorMethod | useFormValidatorObject): validator is useFormValidatorObject {
|
||||||
|
return validator.constructor.name === 'Object'
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultErrorMessage = (key: any) => `Error in ${key}`
|
||||||
|
|
||||||
|
export const useForm = <T, U extends { [key in keyof T]: useFormValidatorParameter }, E extends { [key in keyof U]?: string }>(init: T, validators: Partial<U> = {}, options: useFormOptions = {}) => {
|
||||||
const [form, setForm] = useState<T>(init)
|
const [form, setForm] = useState<T>(init)
|
||||||
|
|
||||||
const [errors, setErrors] = useState<Partial<E>>({})
|
const [errors, setErrors] = useState<Partial<E>>({})
|
||||||
|
const [isValid, setIsValid] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsValid(!Object.values(errors).reduce((acc, cur) => acc || cur !== undefined, false))
|
||||||
|
}, [errors])
|
||||||
|
|
||||||
const _set = (key: keyof T, value: any) => {
|
const _set = (key: keyof T, value: any) => {
|
||||||
setForm({
|
setForm({
|
||||||
@ -35,34 +48,48 @@ export const useForm = <T, U extends { [key in keyof T]: useFormValidator }, E e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const _validateAll = async (value: any, validator: useFormValidatorMethod): Promise<boolean> => {
|
const _validateAll = async (value: any, object: useFormValidator): Promise<boolean> => {
|
||||||
if (validator.constructor.name === 'Function' || validator.constructor.name === 'AsyncFunction')
|
const validator = isFormValidatorObject(object) ? object.validator : object
|
||||||
|
|
||||||
|
if (validator.constructor.name === 'Function')
|
||||||
return (validator as useFormValidatorFunction)(value)
|
return (validator as useFormValidatorFunction)(value)
|
||||||
|
else if (validator.constructor.name === 'AsyncFunction')
|
||||||
|
return await (validator as useFormValidatorFunction)(value)
|
||||||
else if (validator.constructor.name === 'RegExp')
|
else if (validator.constructor.name === 'RegExp')
|
||||||
return (validator as RegExp).test(value)
|
return (validator as RegExp).test(value)
|
||||||
else return false
|
else return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const _getValidatorMessage = (key: keyof T): string => {
|
|
||||||
// @ts-ignore
|
|
||||||
if (validators[key] && validators[key].message) return validators[key].message
|
|
||||||
else return `Error in: ${key}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const _validate = (key: keyof T, value: any) => {
|
const _validate = (key: keyof T, value: any) => {
|
||||||
const validator: useFormValidator | undefined = validators[key]
|
const validator: useFormValidatorParameter | undefined = validators[key]
|
||||||
if (!validator) return
|
if (!validator) return
|
||||||
|
|
||||||
// @ts-ignore
|
if (Array.isArray(validator)) {
|
||||||
_validateAll(value, validator.constructor.name === 'Object' ? (validator as useFormValidatorObject).validator : validator)
|
Promise.all(validator.map(v => _validateAll(value, v)))
|
||||||
.then((valid: boolean) => {
|
.then(result => {
|
||||||
setErrors({
|
const index = result.indexOf(false)
|
||||||
...errors,
|
setErrors({
|
||||||
[key]: valid
|
...errors,
|
||||||
? undefined
|
[key]: index === -1
|
||||||
: _getValidatorMessage(key),
|
? undefined
|
||||||
|
: isFormValidatorObject(validator[index]) && (validator[index] as useFormValidatorObject).message
|
||||||
|
? (validator[index] as useFormValidatorObject).message
|
||||||
|
: defaultErrorMessage(key)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
|
_validateAll(value, validator)
|
||||||
|
.then(valid => {
|
||||||
|
setErrors({
|
||||||
|
...errors,
|
||||||
|
[key]: valid
|
||||||
|
? undefined
|
||||||
|
: isFormValidatorObject(validator) && validator.message
|
||||||
|
? validator.message
|
||||||
|
: defaultErrorMessage(key)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = (key: keyof T, extractor = options.extractor) => (value: any) => {
|
const update = (key: keyof T, extractor = options.extractor) => (value: any) => {
|
||||||
@ -76,5 +103,5 @@ export const useForm = <T, U extends { [key in keyof T]: useFormValidator }, E e
|
|||||||
[opts.setter || options.setter || 'value']: form[key] as any,
|
[opts.setter || options.setter || 'value']: form[key] as any,
|
||||||
})
|
})
|
||||||
|
|
||||||
return { form, update, auto, errors }
|
return { form, update, auto, errors, isValid }
|
||||||
}
|
}
|
@ -10,13 +10,19 @@ const TextError: React.FC<{ error?: string }> = ({ error }) => !error
|
|||||||
|
|
||||||
const Index: React.FC = () => {
|
const Index: React.FC = () => {
|
||||||
|
|
||||||
const { auto, form, errors } = useForm({
|
const { auto, form, errors, isValid } = useForm({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
type: 'formhero',
|
type: 'formhero',
|
||||||
awesome: true,
|
awesome: true,
|
||||||
}, {
|
}, {
|
||||||
username: /^test/,
|
username: [
|
||||||
|
/^test/,
|
||||||
|
{
|
||||||
|
validator: async () => { return true },
|
||||||
|
message: 'Digits please',
|
||||||
|
}
|
||||||
|
],
|
||||||
password: {
|
password: {
|
||||||
validator: /^.{3,}$/,
|
validator: /^.{3,}$/,
|
||||||
message: 'To short',
|
message: 'To short',
|
||||||
@ -26,7 +32,7 @@ const Index: React.FC = () => {
|
|||||||
|
|
||||||
const _submit = (e: React.FormEvent) => {
|
const _submit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
console.log(form, errors)
|
console.log(form, errors, isValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user