1.3.22 • Published 1 year ago

@codewizard-dt/use-form-hook v1.3.22

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

Dynamic React Forms

License: MIT

A Form component exposed by a hook

Hooking up forms in React can be a real pain in the butt, but this package makes it EASY. It automatically handles form data in a way that prevents unnecessary component re-renders and helps you write the LEAST CODE possible. This package also relies on Semantic UI.

Table of Contents

Installation

npm i @codewizard-dt/use-form-hook
  • Run npm install
  • Install peer dependencies
    • semantic-ui-css
    • semantic-ui-react
    • lodash
    • path
    • react of course

Usage

This is a reusable React form template, complete with buttons and submission/response handling. The logic is built in, so all you need to provide is the names and attributes of the form fields.

Import Semantic UI Global Css

First off, you need to install the Semantic UI style sheet. After installing via npm, make sure you import the file into a top-level component. In NextJs, you need to add this line in _app.(tsx|jsx).

import "semantic-ui-css/semantic.min.css";

Put FormProvider in your app layout

The FormProvider gives a reusable context that stores the state of the form data, form errors, and the methods to update them. You MUST have the FormProvider in your DOM in order to use the hook. You can only have one active form at a time. If you need more, you'll have to provide multiple FormProviders.

import { FormProvider } from "@codewizard-dt/use-form-hook";
<FormProvider>
  ...
  {children} // Any child of `FormProvider` can use the hook */
  ...
</FormProvider>

Call useForm hook to expose the Form component

Any child component of FormProvider will have access to the form logic. Just use the hook by calling useForm. It return an object, the most important part of which is the Form component. Render the Form component and provide an array of fields.

There are defaults for the submit and respond properties. If you don't include them initially, the Form will console.log your data for you.

import { useForm } from "@codewizard-dt/use-form-hook";
const ChildComponent = (props) => {
  const { Form } = useForm();
  return <Form fields={[]} submit={submitHandler} respond={responseHandler} />;
};

Provide the Form element with fields, submit, and respond properties

Form propertyDescriptionRequired
fieldsArray(object) an array of objects with properties that will be mapped onto FormField components from Semantic UItrue
submit(function) called with the form data when the form is submittedfalse
respond(function) called with the API response when the request is finished. Can contain data or errorsfalse
buttonsArray(object) an array of objects with properties that will be mapped onto Button components from Semantic UI. Accepts all properties of the Button componentfalse
submitBtnText(string) custom text for the submit buttonfalse

Provide fields property as an array of objects

The smallest object that can render an input field is just a name. The Form component will construct all of the components and connect them for you.

// Example.. Notice all you need is a `name`
fields={[
  { name: "username" }, 
  { name: "password", type: "password" },
  { name: "address", fields: [
    {name: "street", width: "6"},
    {name: "city", width: "3"},
    {name: "state", width: "3"}
  ]}
]}

Example

Creating Fields

The fields property is an array. It can include any number of Fields and/or FieldGroups, in any order. The form data object will reflect any nested structures that you create.

Field Properties

A field object can use any property that a FormField component from Semantic UI can use. | Field Property | Description | Required | | ----------- | ----------- | ----------- | | name | (string) used as a string key for form data | true | | initial | (string) initial field value | false | | type | (string) describes data type, ie 'text', 'number', 'password' | false | | label | (string) a label to display alongside | false | | useLabel | (boolean) if true and label not given, name is used | false | | required | (boolean) shows indicator and affects form behavior as normal | false | | control | (any) HTML tag (ie 'input', 'select') or a Semantic UI form control component | false | | options | Array(string|object) rendered as <option> for <select> tags | false | | disabled | (boolean) | false | | width | (SemanticWIDTHS) width as determined by Semantic UI | false |

Field Group Properties

A field group object can use any property that a FormGroup component from Semantic UI can use. | Property | Description | Required | | ----------- | ----------- | ----------- | | name | (string) used as a string key for form data. If you use an empty string, the form data object will not be nested. | true | | fields | Array(Field) creates nested form groups | false | | widths | (SemanticWIDTHS) determines width for nested form fields | false |

The Form Data Object

Automatically constructed data object for all fields in the form. If the form fields are nested, the data is nested too.

// Example, no nested fields
fields = {[
  { name: "username" }, 
  { name: "password", type: "password" },
]}

...

data = {
  username: '',
  password: ''
}

Example

// Example, nested fields
fields = {[
  { 
    name: "city",
    widths: "two",
    fields: [
      { name: 'best_restaurant' },
      { name: 'worst_restaurant' }
    ] 
  }
]}

...

data = {
  city: {
    best_restaurant: '',
    worst_restaurant: ''
  }
}

Example

// Example, nested fields but the group has no name
// When group has no name, data is flattened
// You might want to do this for styling but don't want the data nested
fields = {[
  { 
    name: "",
    fields: [
      { name: 'best_restaurant' },
      { name: 'worst_restaurant' }
    ] 
  }
]}

...

data = {
  best_restaurant: '',
  worst_restaurant: ''
}

Example

Provide submit property as a function

/**
 * Defines the `submit` property which sends the form data to the Api 
 * Must return a promise
 */

export type OnSubmitHandler = (data: DataMap) => Promise<ApiResponse<any>>

const submit:FormSubmitHanlder = (data) =>{
  return post('url',data)
}

Provide respond property as a function

/**
 * Defines the `respond` property which receives the ApiResponse
 * Where <T> is the data type you expect from the API
 */
export type ApiResponse<T> = {
  data?: T,
  error?: any,
  errors?: {
    [key: string]: string
  }
}
export type ApiResponseHandler<T> = (response: ApiResponse<T>) => void

const respond:ApiResponseHandler<YourDataType> = (response) =>{
  // data = your API data
  // error = generic error or specific form error, either way automatically displayed under the form
  // errors = specific form errors, validation for instance. Displayed under any Field whose name matches one of the objects' keys
  let { data, error, errors } = response
}

License

This project is provisioned under the MIT License

Contributing

Repo link

Do you want to help make this project better? Visit the the repo to check out existing issues or create a new branch to start working on a suggested feature

Tests

None yet!

Questions

If you have any questions, please contact me on Github or email.

Gimme Readme

This file was initialized by the Gimme Readme command line README generator

1.2.0

2 years ago

1.2.7

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.3.9

1 year ago

1.3.8

1 year ago

1.2.12

2 years ago

1.2.13

2 years ago

1.2.10

2 years ago

1.2.11

2 years ago

1.2.16

2 years ago

1.2.14

2 years ago

1.2.15

2 years ago

1.2.9

2 years ago

1.3.10

1 year ago

1.3.13

1 year ago

1.3.14

1 year ago

1.3.11

1 year ago

1.3.12

1 year ago

1.3.17

1 year ago

1.3.18

1 year ago

1.3.15

1 year ago

1.3.16

1 year ago

1.3.19

1 year ago

1.3.20

1 year ago

1.3.21

1 year ago

1.3.22

1 year ago

1.2.18

2 years ago

1.2.19

2 years ago

1.3.7

1 year ago

1.3.6

2 years ago

1.3.5

2 years ago

1.3.4

2 years ago

1.3.3

2 years ago

1.3.2

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.20

2 years ago

1.2.23

2 years ago

1.2.24

2 years ago

1.2.21

2 years ago

1.2.22

2 years ago

1.2.27

2 years ago

1.2.28

2 years ago

1.2.25

2 years ago

1.2.26

2 years ago

1.1.52

2 years ago

1.1.51

2 years ago

1.1.50

2 years ago

1.1.56

2 years ago

1.1.55

2 years ago

1.1.54

2 years ago

1.1.53

2 years ago

1.1.57

2 years ago

1.1.29

2 years ago

1.1.28

2 years ago

1.1.30

2 years ago

1.1.34

2 years ago

1.1.33

2 years ago

1.1.32

2 years ago

1.1.31

2 years ago

1.1.38

2 years ago

1.1.37

2 years ago

1.1.36

2 years ago

1.1.35

2 years ago

1.1.39

2 years ago

1.1.41

2 years ago

1.1.40

2 years ago

1.1.45

2 years ago

1.1.44

2 years ago

1.1.43

2 years ago

1.1.42

2 years ago

1.1.49

2 years ago

1.1.48

2 years ago

1.1.47

2 years ago

1.1.46

2 years ago

1.1.27

2 years ago

1.1.26

2 years ago

1.1.25

2 years ago

1.1.24

2 years ago

1.1.23

2 years ago

1.1.22

2 years ago

1.1.21

2 years ago

1.1.20

2 years ago

1.1.19

2 years ago

1.1.18

2 years ago

1.1.17

2 years ago

1.1.16

2 years ago

1.1.15

2 years ago

1.1.14

2 years ago

1.1.13

2 years ago

1.1.12

2 years ago

1.1.11

2 years ago

1.1.10

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.1.7

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.1.3

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago