fix(hooks): usage of useForm

This commit is contained in:
Divlo 2022-08-26 00:30:54 +02:00
parent 17656c149a
commit a2edafdc22
No known key found for this signature in database
GPG Key ID: 8F9478F220CE65E9
7 changed files with 103 additions and 104 deletions

View File

@ -1,9 +1,11 @@
# For more information see: https://editorconfig.org/
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -41,7 +41,7 @@ import React from 'react'
import { Form } from 'react-component-form'
import type { HandleForm } from 'react-component-form'
const Example = () => {
export const Example = () => {
const handleSubmit: HandleForm = (formData, formElement) => {
console.log(formData) // { inputName: 'value of the input' }
formElement.reset()
@ -72,27 +72,30 @@ You can see a more detailled example in the [./example](./example) folder.
```tsx
import React from 'react'
import { Form, useForm } from 'react-component-form'
import type { HandleSubmitCallback } from 'react-component-form'
import type { HandleUseFormCallback } from 'react-component-form'
const schema = {
inputName: {
type: 'string',
required: true,
minLength: 3,
maxLength: 10
maxLength: 20
}
}
const Example = () => {
const { errors, handleSubmit } = useForm(schema)
export const Example = () => {
const { errors, handleUseForm } = useForm(schema)
const onSubmit: HandleSubmitCallback<typeof schema> = (formData, formElement) => {
console.log(formData) // { inputName: 'value of the input' }
const onSubmit: HandleUseFormCallback<typeof schema> = (
formData,
formElement
) => {
console.log(formData) // { inputName: 'value of the input validated' }
formElement.reset()
return null
}
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<Form onSubmit={handleUseForm(onSubmit)}>
<input type='text' name='inputName' />
{errors.inputName != null && <p>{errors.inputName[0].message}</p>}

View File

@ -1,65 +1,38 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Form, HandleForm } from 'react-component-form'
import React from 'react'
import { Form, useForm } from 'react-component-form'
import type { HandleUseFormCallback } from 'react-component-form'
import './index.css'
import GitHubLogo from 'url:./github.jpg'
const App: React.FC = () => {
const handleSubmit: HandleForm = (formData, formElement) => {
console.clear()
console.log('onSubmit: ', formData)
formElement.reset()
const schema = {
inputName: {
type: 'string',
minLength: 3,
maxLength: 20
}
}
const handleChange: HandleForm = (formData) => {
console.log('onChange: ', formData)
export const Example = () => {
const { errors, handleUseForm } = useForm(schema)
const onSubmit: HandleUseFormCallback<typeof schema> = (
formData,
formElement
) => {
console.log(formData) // { inputName: 'value of the input validated' }
formElement.reset()
return null
}
return (
<div className='container'>
<h2>{'<Form />'}</h2>
<h5 className='title-install'>npm install --save react-component-form</h5>
<Form onSubmit={handleUseForm(onSubmit)}>
<input type='text' name='inputName' />
{errors.inputName != null && <p>{errors.inputName[0].message}</p>}
<Form onSubmit={handleSubmit} onChange={handleChange}>
<div className='form-group'>
<label htmlFor='name'>Name :</label>
<input
className='form-control'
type='text'
name='name'
id='name'
placeholder='name'
/>
</div>
<button type='submit' className='btn btn-primary'>
Submit
</button>
</Form>
<div className='result-container'>
<h4>
Try the form and Inspect the console{' '}
<span role='img' aria-label='smiley'>
😃
</span>
</h4>
</div>
<div className='github-logo'>
<a
target='_blank'
rel='noopener noreferrer'
href='https://github.com/Divlo/react-component-form'
>
<img width='30px' alt='github' src={GitHubLogo} />
</a>
</div>
</div>
<button type='submit'>Submit</button>
</Form>
)
}
const container = document.getElementById('root') as HTMLElement
const root = createRoot(container)
root.render(<App />)
root.render(<Example />)

View File

@ -15,6 +15,7 @@
"@types/react": "18.0.17",
"@types/react-dom": "18.0.6",
"parcel": "2.7.0",
"process": "^0.11.10",
"typescript": "4.7.4"
}
},
@ -2505,6 +2506,15 @@
"node": ">=12"
}
},
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"dev": true,
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/react": {
"resolved": "../node_modules/react",
"link": true
@ -4350,6 +4360,12 @@
"is-json": "^2.0.1"
}
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"dev": true
},
"react": {
"version": "file:../node_modules/react",
"requires": {

View File

@ -8,14 +8,15 @@
},
"dependencies": {
"react": "file:../node_modules/react",
"react-dom": "file:../node_modules/react-dom",
"react-component-form": "file:.."
"react-component-form": "file:..",
"react-dom": "file:../node_modules/react-dom"
},
"devDependencies": {
"@parcel/transformer-image": "2.7.0",
"@types/react": "18.0.17",
"@types/react-dom": "18.0.6",
"parcel": "2.7.0",
"process": "^0.11.10",
"typescript": "4.7.4"
}
}

View File

@ -1,5 +1,5 @@
import { useMemo, useState } from 'react'
import { Static, TObject, TProperties, Type } from '@sinclair/typebox'
import { SchemaOptions, Static, TObject, Type } from '@sinclair/typebox'
import type { ErrorObject } from 'ajv'
import type { HandleForm } from '../components/Form'
@ -8,19 +8,21 @@ import { ajv } from '../utils/ajv'
import { handleCheckboxBoolean } from '../utils/handleCheckboxBoolean'
import { handleOptionalEmptyStringToNull } from '../utils/handleOptionalEmptyStringToNull'
export type Schema = SchemaOptions
export type Error = ErrorObject
export type ErrorsObject<K extends TProperties> = {
export type ErrorsObject<K extends Schema> = {
[key in keyof Partial<K>]: Error[] | undefined
}
export type HandleSubmitCallback<K extends TProperties> = (
export type HandleUseFormCallback<K extends Schema> = (
formData: Static<TObject<K>>,
formElement: HTMLFormElement
) => Promise<Message<K> | null>
) => Promise<Message<K> | null> | Message<K> | null
export type HandleSubmit<K extends TProperties> = (
callback: HandleSubmitCallback<K>
export type HandleUseForm<K extends Schema> = (
callback?: HandleUseFormCallback<K>
) => HandleForm
export interface GlobalMessage {
@ -29,18 +31,16 @@ export interface GlobalMessage {
properties?: undefined
}
export interface PropertiesMessage<K extends TProperties> {
export interface PropertiesMessage<K extends Schema> {
type: 'error'
value?: string
properties: { [key in keyof Partial<K>]: string }
}
export type Message<K extends TProperties> =
| GlobalMessage
| PropertiesMessage<K>
export type Message<K extends Schema> = GlobalMessage | PropertiesMessage<K>
export interface UseFormResult<K extends TProperties> {
handleSubmit: HandleSubmit<K>
export interface UseFormResult<K extends Schema> {
handleUseForm: HandleUseForm<K>
readonly fetchState: FetchState
setFetchState: React.Dispatch<React.SetStateAction<FetchState>>
@ -61,7 +61,7 @@ export interface UseFormResult<K extends TProperties> {
readonly errors: ErrorsObject<K>
}
export const useForm = <K extends TProperties>(
export const useForm = <K extends Schema>(
validationSchema: K
): UseFormResult<typeof validationSchema> => {
const validationSchemaObject = useMemo(() => {
@ -78,7 +78,7 @@ export const useForm = <K extends TProperties>(
return ajv.compile(validationSchemaObject)
}, [validationSchemaObject])
const handleSubmit: HandleSubmit<typeof validationSchema> = (callback) => {
const handleUseForm: HandleUseForm<typeof validationSchema> = (callback) => {
return async (formData, formElement) => {
setErrors({} as any)
setMessage(null)
@ -103,30 +103,33 @@ export const useForm = <K extends TProperties>(
setErrors(errors)
} else {
setErrors({} as any)
setFetchState('loading')
const message = await callback(
formData as Static<TObject<typeof validationSchema>>,
formElement
)
if (message != null) {
const { value = null, type, properties } = message
setMessage(value)
setFetchState(type)
if (type === 'error') {
const propertiesErrors: ErrorsObject<typeof validationSchema> =
{} as any
for (const property in properties) {
propertiesErrors[property] = [
{
keyword: 'message',
message: properties[property],
instancePath: `/${property}`,
schemaPath: `#/properties/${property}/message`,
params: {}
}
]
if (callback != null) {
setFetchState('loading')
const message = await callback(
formData as Static<TObject<typeof validationSchema>>,
formElement
)
if (message != null) {
const { value = null, type, properties } = message
setMessage(value)
setFetchState(type)
if (type === 'error') {
const propertiesErrors: ErrorsObject<typeof validationSchema> =
{} as any
for (const property in properties) {
propertiesErrors[property] = [
{
keyword: 'message',
message: properties[property],
instancePath: `/${property}`,
schemaPath: `#/properties/${property}/message`,
params: {},
data: formData[property]
}
]
}
setErrors(propertiesErrors)
}
setErrors(propertiesErrors)
}
}
}
@ -134,7 +137,7 @@ export const useForm = <K extends TProperties>(
}
return {
handleSubmit,
handleUseForm,
fetchState,
setFetchState,
message,

View File

@ -3,7 +3,8 @@ import Ajv from 'ajv'
export const ajv = addFormats(
new Ajv({
allErrors: true
allErrors: true,
verbose: true
}),
[
'date-time',