diff --git a/README.md b/README.md index 9079184..30c64ff 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ npm i formhero ### 👁 Demos -- [__*Live Web*__](https://cupcakearmy.github.io/formhero/) -- [__*Live Codesandbox*__](https://codesandbox.io/embed/formhero-simple-bdcx2?expanddevtools=1&fontsize=14) -- [__*Live React-Native*__](https://snack.expo.io/@cupcakearmy/useform) +- [**_Live Web_**](https://cupcakearmy.github.io/formhero/) +- [**_Live Codesandbox_**](https://codesandbox.io/embed/formhero-simple-bdcx2?expanddevtools=1&fontsize=14) +- [**_Live React-Native_**](https://snack.expo.io/@cupcakearmy/useform) ### Links @@ -35,7 +35,7 @@ npm i formhero - [Validators](#validators) - [Options](#options) - Returns - - [auto](#auto) + - [field](#field) - [form](#form) - [errors](#errors) - [isValid](#isvalid) @@ -43,7 +43,7 @@ npm i formhero ## 🤔 Motivation -So why write yet another form utility you might ask? First off, I don't like the Formik approach. In my humble opition formik is very verbose and requires lots of boilerplate. Also does not work with hooks. [react-hook-form](https://react-hook-form.com/) is a very cool library and it is the main inspiration for formhero. It does almost everything right... typescript, no deps, small, concise. +So why write yet another form utility you might ask? First off, I don't like the Formik approach. In my humble opition formik is very verbose and requires lots of boilerplate. Also does not work with hooks. [react-hook-form](https://react-hook-form.com/) is a very cool library and it is the main inspiration for formhero. It does almost everything right... typescript, no deps, small, concise. The problem that I found while using it was that 3rd party ui libs like [Ant Design](https://ant.design/) or [Fabric UI](https://developer.microsoft.com/en-us/fabric#/controls/web) do not always have the standart `onChange` or `value` props in their components. That is where react-hook-form starts falling apart. This is what formhero tries to address in the most minimalistic way possible, with as little code as needed. All in pure typescript and no deps. @@ -54,8 +54,7 @@ import ReactDOM from 'react-dom' import { useForm } from 'formhero' const Form = () => { - - const { auto, form } = useForm({ + const { field, form } = useForm({ username: '', password: '', }) @@ -68,9 +67,8 @@ const Form = () => { return (
- - - + +
@@ -85,43 +83,43 @@ const Form = () => { ```typescript const Form = () => { - - const { auto, form, errors } = useForm({ - username: '', - email: '', - password: '' - }, { - username: value => value.length > 3, - email: { - validator: /@/, - message: 'Must contain an @', + const { field, form, errors } = useForm( + { + username: '', + email: '', + password: '', }, - password: [ - { - validator: /[A-Z]/, - message: 'Must contain an uppercase letter' + { + username: value => value.length > 3, + email: { + validator: /@/, + message: 'Must contain an @', }, - { - validator: /[\d]/, - message: 'Must contain a digit' - }, - ] - }) + password: [ + { + validator: /[A-Z]/, + message: 'Must contain an uppercase letter', + }, + { + validator: /[\d]/, + message: 'Must contain a digit', + }, + ], + } + ) return (
-

Errors & Validation

- + {errors.username && 'Must be longer than 3'} - + {errors.email} - + {errors.password} -
) } @@ -133,30 +131,32 @@ Often it happens that you use a specific input or framework, so the default gett ```typescript const Form = () => { - - const { auto, form, errors } = useForm({ + const { field, form, errors } = useForm({ awesome: true, }) return ( -
{ - e.preventDefault() - console.log(form) - }}> - + { + e.preventDefault() + console.log(form) + }} + >

Custom

+ -
) } @@ -167,7 +167,7 @@ const Form = () => { ### `useForm` ```typescript -const {auto, errors, update, form, isValid} = useForm(initial, validators, options) +const { field, errors, update, form, isValid } = useForm(initial, validators, options) ``` ### Initial @@ -192,7 +192,7 @@ A validator is an object that taked in either a `RegExp` or a `Function` (can be ```javascript const validators = { - // Only contains letters. + // Only contains letters. // This could also be a (also async) function that returns a boolean. username: /^[A-z]*$/, } @@ -213,7 +213,7 @@ const validators = { username: { validator: /^[A-z]*$/, message: 'My custom error message', - } + }, } ``` @@ -227,12 +227,12 @@ const validators = { message: 'My custom error message', }, /[\d]/, - async (value) => value.length > 0, + async value => value.length > 0, { - validator: (value) => true, + validator: value => true, message: 'Some other error', - } - ] + }, + ], } ``` @@ -245,33 +245,30 @@ Sometimes it's practical to have some different default values when using for ex [Check the Expo Snack for a live preview](https://snack.expo.io/@cupcakearmy/useform) ```javascript -import * as React from 'react'; -import { Text, SafeAreaView, TextInput } from 'react-native'; -import { useForm } from 'formhero'; +import * as React from 'react' +import { Text, SafeAreaView, TextInput } from 'react-native' +import { useForm } from 'formhero' const initial = { username: 'i am all lowercase', -}; -const validators = {}; +} +const validators = {} const options = { setter: 'value', // This is not stricly necessarry as 'value' would already be the default. getter: 'onChangeText', extractor: text => text.toLowerCase(), -}; +} export default () => { - const { form, auto } = useForm(initial, validators, options); + const { form, field } = useForm(initial, validators, options) return ( - + {form.username} - ); -}; + ) +} ``` ###### Example: React Native (Method 2 - Local overwrite) @@ -280,15 +277,15 @@ export default () => { // ... export default () => { - const { form, auto } = useForm({ + const { form, field } = useForm({ username: 'i am all lowercase', - }); + }) return ( text.toLowerCase(), @@ -296,44 +293,41 @@ export default () => { /> {form.username} - ); -}; - + ) +} ``` -### Auto - -The `auto` object is used to bind the form state to the input. +### field +The `field` object is used to bind the form state to the input. ###### Example: Simple ```javascript -const { auto } = useForm() +const { field } = useForm() - + ``` - ###### Example: With custom options All are optional. ```javascript -const { auto } = useForm() +const { field } = useForm() - e.target.value })} /> ``` -## Form +## Form This is the form state that you can use when submitting the data -###### Example +###### Example ```javascript diff --git a/examples/custom.tsx b/examples/custom.tsx index 5fe6ac3..78dbcf3 100644 --- a/examples/custom.tsx +++ b/examples/custom.tsx @@ -4,32 +4,34 @@ import ReactDOM from 'react-dom' import { useForm } from '../dist' const Index: React.FC = () => { + const { field, form, errors } = useForm({ + awesome: true, + }) - const { auto, form, errors } = useForm({ - awesome: true, - }) + return ( +
{ + e.preventDefault() + console.log(form) + }} + > +

Custom

- return ( - { - e.preventDefault() - console.log(form) - }}> + -

Custom

- - - - - -
- ) + + + ) } -ReactDOM.render(, document.getElementById('custom')) \ No newline at end of file +ReactDOM.render(, document.getElementById('custom')) diff --git a/examples/errorsAndValidation.tsx b/examples/errorsAndValidation.tsx index f69ee8f..644b762 100644 --- a/examples/errorsAndValidation.tsx +++ b/examples/errorsAndValidation.tsx @@ -4,50 +4,52 @@ import ReactDOM from 'react-dom' import { useForm } from '../' const Index: React.FC = () => { + const { field, form, errors, isValid } = useForm( + { + username: '', + email: '', + password: '', + }, + { + username: value => value.length > 3, + email: { + validator: /@/, + message: 'Must contain an @', + }, + password: [ + { + validator: /[A-Z]/, + message: 'Must contain an uppercase letter', + }, + { + validator: /[\d]/, + message: 'Must contain a digit', + }, + ], + } + ) - const { auto, form, errors, isValid } = useForm({ - username: '', - email: '', - password: '' - }, { - username: value => value.length > 3, - email: { - validator: /@/, - message: 'Must contain an @', - }, - password: [ - { - validator: /[A-Z]/, - message: 'Must contain an uppercase letter' - }, - { - validator: /[\d]/, - message: 'Must contain a digit' - }, - ] - }) + return ( +
{ + e.preventDefault() + if (isValid) console.log(form) + }} + > +

Errors & Validation

- return ( - { - e.preventDefault() - if (isValid) console.log(form) - }}> + + {errors.username && 'Must be longer than 3'} -

Errors & Validation

+ + {errors.email} - - {errors.username && 'Must be longer than 3'} + + {errors.password} - - {errors.email} - - - {errors.password} - - - -
- ) + + + ) } -ReactDOM.render(, document.getElementById('errors')) \ No newline at end of file +ReactDOM.render(, document.getElementById('errors')) diff --git a/examples/index.html b/examples/index.html index b712881..907d348 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,67 +1,64 @@ + + + + Form Hero + + - input[type="submit"] { - cursor: pointer; - } + +
+

Open the console to see the submitted data

+
+
+
+
+
- input[type="checkbox"] { - display: inline; - width: initial; - } - - - - -
-

Open the console to see the submitted data

-
-
-
-
-
- - - - - - - - \ No newline at end of file + + + + + + diff --git a/examples/select.tsx b/examples/select.tsx index 6a5534b..f1742c9 100644 --- a/examples/select.tsx +++ b/examples/select.tsx @@ -4,30 +4,29 @@ import ReactDOM from 'react-dom' import { useForm } from '../dist' const Index: React.FC = () => { + const { field, form, errors } = useForm({ + type: 'formhero', + }) - const { auto, form, errors } = useForm({ - type: 'formhero', - }) + return ( +
{ + e.preventDefault() + console.log(form) + }} + > +

Select

- return ( - { - e.preventDefault() - console.log(form) - }}> + -

Select

- - - - - -
- ) + + + ) } -ReactDOM.render(, document.getElementById('select')) \ No newline at end of file +ReactDOM.render(, document.getElementById('select')) diff --git a/examples/simple.tsx b/examples/simple.tsx index f8449d9..9194830 100644 --- a/examples/simple.tsx +++ b/examples/simple.tsx @@ -4,27 +4,26 @@ import ReactDOM from 'react-dom' import { useForm } from '../dist' const Index: React.FC = () => { + const { field, form, errors } = useForm({ + username: 'unicorn', + password: '', + }) - const { auto, form, errors } = useForm({ - username: 'unicorn', - password: '', - }) + return ( +
{ + e.preventDefault() + console.log(form) + }} + > +

Simple

- return ( - { - e.preventDefault() - console.log(form) - }}> + + -

Simple

- - - - - - -
- ) + + + ) } -ReactDOM.render(, document.getElementById('simple')) \ No newline at end of file +ReactDOM.render(, document.getElementById('simple')) diff --git a/lib/index.ts b/lib/index.ts index f26f159..499c408 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -88,10 +88,10 @@ export const useForm = ({ + const field = (key: keyof T, opts: useFormOptions = {}) => ({ [opts.getter || options.getter || 'onChange']: update(key, opts.extractor), [opts.setter || options.setter || 'value']: form[key] as any, }) - return { form, update, auto, errors, isValid } + return { form, update, field, errors, isValid } } diff --git a/test/test.tsx b/test/test.tsx index 3432bee..87909be 100644 --- a/test/test.tsx +++ b/test/test.tsx @@ -6,7 +6,7 @@ import { useForm } from '../' const TextError: React.FC<{ error?: string }> = ({ error }) => (!error ? null :
{error}
) const Index: React.FC = () => { - const { auto, form, errors, isValid } = useForm( + const { field, form, errors, isValid } = useForm( { username: '', password: '', @@ -40,20 +40,20 @@ const Index: React.FC = () => {
Username
- +

Password
- +

Which one to choose?
- @@ -66,7 +66,7 @@ const Index: React.FC = () => {