mirror of
https://github.com/cupcakearmy/formhero.git
synced 2024-12-22 16:16:24 +00:00
prettier
This commit is contained in:
parent
d7a3d73512
commit
544dada3c4
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
semi: false
|
||||||
|
singleQuote: true
|
||||||
|
trailingComma: es5
|
||||||
|
tabWidth: 2
|
||||||
|
printWidth: 200
|
132
lib/index.ts
132
lib/index.ts
@ -1,21 +1,19 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type useFormExtractor = (from: any) => any
|
export type useFormExtractor = (from: any) => any
|
||||||
|
|
||||||
export type useFormOptions = {
|
export type useFormOptions = {
|
||||||
extractor?: useFormExtractor,
|
extractor?: useFormExtractor
|
||||||
getter?: string,
|
getter?: string
|
||||||
setter?: string,
|
setter?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type useFormValidatorFunction = ((s: any) => boolean | Promise<boolean>)
|
export type useFormValidatorFunction = (s: any) => boolean | Promise<boolean>
|
||||||
export type useFormValidatorMethod = useFormValidatorFunction | RegExp
|
export type useFormValidatorMethod = useFormValidatorFunction | RegExp
|
||||||
|
|
||||||
export type useFormValidatorObject = {
|
export type useFormValidatorObject = {
|
||||||
validator: useFormValidatorMethod,
|
validator: useFormValidatorMethod
|
||||||
message?: string,
|
message?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type useFormValidator = useFormValidatorMethod | useFormValidatorObject
|
export type useFormValidator = useFormValidatorMethod | useFormValidatorObject
|
||||||
@ -26,82 +24,74 @@ export const HTMLInputExtractor: useFormExtractor = (e: React.FormEvent<HTMLInpu
|
|||||||
export const HTMLCheckboxExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.checked
|
export const HTMLCheckboxExtractor: useFormExtractor = (e: React.FormEvent<HTMLInputElement>) => e.currentTarget.checked
|
||||||
|
|
||||||
function isFormValidatorObject(validator: useFormValidatorMethod | useFormValidatorObject): validator is useFormValidatorObject {
|
function isFormValidatorObject(validator: useFormValidatorMethod | useFormValidatorObject): validator is useFormValidatorObject {
|
||||||
return validator.constructor.name === 'Object'
|
return validator.constructor.name === 'Object'
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultErrorMessage = (key: any) => `Error in ${key}`
|
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 = {}) => {
|
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);
|
const [isValid, setIsValid] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsValid(!Object.values(errors).reduce((acc, cur) => acc || cur !== undefined, false))
|
setIsValid(!Object.values(errors).reduce((acc, cur) => acc || cur !== undefined, false))
|
||||||
}, [errors])
|
}, [errors])
|
||||||
|
|
||||||
const _set = (key: keyof T, value: any) => {
|
const _set = (key: keyof T, value: any) => {
|
||||||
setForm({
|
setForm({
|
||||||
...form,
|
...form,
|
||||||
[key]: value,
|
[key]: value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const _validateAll = async (value: any, object: useFormValidator): Promise<boolean> => {
|
const _validateAll = async (value: any, object: useFormValidator): Promise<boolean> => {
|
||||||
const validator = isFormValidatorObject(object) ? object.validator : object
|
const validator = isFormValidatorObject(object) ? object.validator : object
|
||||||
|
|
||||||
if (validator.constructor.name === 'Function')
|
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 === 'AsyncFunction')
|
else if (validator.constructor.name === 'RegExp') return (validator as RegExp).test(value)
|
||||||
return await (validator as useFormValidatorFunction)(value)
|
else return false
|
||||||
else if (validator.constructor.name === 'RegExp')
|
}
|
||||||
return (validator as RegExp).test(value)
|
|
||||||
else return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const _validate = (key: keyof T, value: any) => {
|
const _validate = (key: keyof T, value: any) => {
|
||||||
const validator: useFormValidatorParameter | undefined = validators[key]
|
const validator: useFormValidatorParameter | undefined = validators[key]
|
||||||
if (!validator) return
|
if (!validator) return
|
||||||
|
|
||||||
if (Array.isArray(validator)) {
|
if (Array.isArray(validator)) {
|
||||||
Promise.all(validator.map(v => _validateAll(value, v)))
|
Promise.all(validator.map(v => _validateAll(value, v))).then(result => {
|
||||||
.then(result => {
|
const index = result.indexOf(false)
|
||||||
const index = result.indexOf(false)
|
setErrors({
|
||||||
setErrors({
|
...errors,
|
||||||
...errors,
|
[key]:
|
||||||
[key]: index === -1
|
index === -1
|
||||||
? undefined
|
? undefined
|
||||||
: isFormValidatorObject(validator[index]) && (validator[index] as useFormValidatorObject).message
|
: isFormValidatorObject(validator[index]) && (validator[index] as useFormValidatorObject).message
|
||||||
? (validator[index] as useFormValidatorObject).message
|
? (validator[index] as useFormValidatorObject).message
|
||||||
: defaultErrorMessage(key)
|
: defaultErrorMessage(key),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
_validateAll(value, validator)
|
_validateAll(value, validator).then(valid => {
|
||||||
.then(valid => {
|
setErrors({
|
||||||
setErrors({
|
...errors,
|
||||||
...errors,
|
[key]: valid ? undefined : isFormValidatorObject(validator) && validator.message ? validator.message : defaultErrorMessage(key),
|
||||||
[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) => {
|
||||||
const extracted = extractor ? extractor(value) : HTMLInputExtractor(value)
|
const extracted = extractor ? extractor(value) : HTMLInputExtractor(value)
|
||||||
_set(key, extracted)
|
_set(key, extracted)
|
||||||
_validate(key, extracted)
|
_validate(key, extracted)
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto = (key: keyof T, opts: useFormOptions = {}) => ({
|
const auto = (key: keyof T, opts: useFormOptions = {}) => ({
|
||||||
[opts.getter || options.getter || 'onChange']: update(key, opts.extractor),
|
[opts.getter || options.getter || 'onChange']: update(key, opts.extractor),
|
||||||
[opts.setter || options.setter || 'value']: form[key] as any,
|
[opts.setter || options.setter || 'value']: form[key] as any,
|
||||||
})
|
})
|
||||||
|
|
||||||
return { form, update, auto, errors, isValid }
|
return { form, update, auto, errors, isValid }
|
||||||
}
|
}
|
@ -1,22 +1,19 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
|
<title>Form Hero</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="UTF-8">
|
<div id="root"></div>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<script src="./test.tsx"></script>
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
</body>
|
||||||
<title>Form Hero</title>
|
|
||||||
<link rel="stylesheet" type="text/css"
|
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css" />
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
padding: 1em
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
<script src="./test.tsx"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -3,32 +3,33 @@ import ReactDOM from 'react-dom'
|
|||||||
|
|
||||||
import { useForm } from '../'
|
import { useForm } from '../'
|
||||||
|
|
||||||
|
const TextError: React.FC<{ error?: string }> = ({ error }) => (!error ? null : <div className="has-text-danger">{error}</div>)
|
||||||
const TextError: React.FC<{ error?: string }> = ({ error }) => !error
|
|
||||||
? null
|
|
||||||
: <div className="has-text-danger">{error}</div>
|
|
||||||
|
|
||||||
const Index: React.FC = () => {
|
const Index: React.FC = () => {
|
||||||
|
const { auto, form, errors, isValid } = useForm(
|
||||||
const { auto, form, errors, isValid } = useForm({
|
{
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
type: 'formhero',
|
type: 'formhero',
|
||||||
awesome: true,
|
awesome: true,
|
||||||
}, {
|
|
||||||
username: [
|
|
||||||
/^test/,
|
|
||||||
{
|
|
||||||
validator: async () => { return true },
|
|
||||||
message: 'Digits please',
|
|
||||||
}
|
|
||||||
],
|
|
||||||
password: {
|
|
||||||
validator: /^.{3,}$/,
|
|
||||||
message: 'To short',
|
|
||||||
},
|
},
|
||||||
awesome: (value) => !!value
|
{
|
||||||
})
|
username: [
|
||||||
|
/^test/,
|
||||||
|
{
|
||||||
|
validator: async () => {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
message: 'Digits please',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
password: {
|
||||||
|
validator: /^.{3,}$/,
|
||||||
|
message: 'To short',
|
||||||
|
},
|
||||||
|
awesome: value => !!value,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const _submit = (e: React.FormEvent) => {
|
const _submit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@ -41,12 +42,14 @@ const Index: React.FC = () => {
|
|||||||
<div>Username</div>
|
<div>Username</div>
|
||||||
<input className="input" {...auto('username')} />
|
<input className="input" {...auto('username')} />
|
||||||
<TextError error={errors.username} />
|
<TextError error={errors.username} />
|
||||||
<br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
<div>Password</div>
|
<div>Password</div>
|
||||||
<input className="input" {...auto('password')} />
|
<input className="input" {...auto('password')} />
|
||||||
<TextError error={errors.password} />
|
<TextError error={errors.password} />
|
||||||
<br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
<div>Which one to choose?</div>
|
<div>Which one to choose?</div>
|
||||||
<div className="select">
|
<div className="select">
|
||||||
@ -57,21 +60,27 @@ const Index: React.FC = () => {
|
|||||||
<option value="formhero">FormHero</option>
|
<option value="formhero">FormHero</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
<label className="checkbox">
|
<label className="checkbox">
|
||||||
<input type="checkbox" {...auto('awesome', {
|
<input
|
||||||
setter: 'checked',
|
type="checkbox"
|
||||||
getter: 'onChange',
|
{...auto('awesome', {
|
||||||
extractor: (e) => e.target.checked
|
setter: 'checked',
|
||||||
})} />
|
getter: 'onChange',
|
||||||
|
extractor: e => e.target.checked,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
Is it awesome?
|
Is it awesome?
|
||||||
</label>
|
</label>
|
||||||
<TextError error={errors.awesome} />
|
<TextError error={errors.awesome} />
|
||||||
<br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
<button className="button" type="submit">Go 🚀</button>
|
<button className="button" type="submit">
|
||||||
|
Go 🚀
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -79,5 +88,5 @@ const Index: React.FC = () => {
|
|||||||
|
|
||||||
ReactDOM.render(<Index />, document.getElementById('root'))
|
ReactDOM.render(<Index />, document.getElementById('root'))
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// if (module.hot) module.hot.accept()
|
// if (module.hot) module.hot.accept()
|
Loading…
Reference in New Issue
Block a user