npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@glueit/forms

v0.0.37

Published

Glue It - Dead Simple, but powerful forms

Downloads

31

Readme

Glue It - Forms · GitHub license npm version PRs Welcome gzip size Code Coverage

Build React forms declaratively.

Table of Contents

Prerequisites

Forms is built on top of React. At the minimum you will need:

Installation

$ npm i @glueit/forms

Sample forms

Sample Form on Code Sandbox

You can run a sample form by cloning this repo and running these commands.

npm i
npm run start

Then open your browser at localhost:3000.

Hydration

You can hydrate the form (i.e. for editing data that was already saved).

<Form
  data={{ age: '17' }}
>
  <CustomInput
    name="age"
    label="Age"
    helperText="What is your age?"
    required
  />
</Form>

Custom fields

Custom fields are created using the asField higher order component.

Imports

import React from 'react'
import Form, {
  Form,
  asField
} from '@glueit/forms'

The custom field

const CustomInput = asField({
  onChange,
  onBlur = () => {},
  name,
  value,
  errors,
  label,
  helperText,
  required = false
}) => {
  return (
    <input
      id={name}
      value={value}
      onChange={e => onChange(e)}
      onBlur={e => onBlur(e)}
      label={label}
      required={required}
    />
  )
})

The form

<Form>
  <CustomInput
    name="age"
    label="Age"
    helperText="What is your age?"
    required
  />
</Form>

Custom observers

You can have observers in your Form that can then render based on the form state.

Imports

import React from 'react'
import Form, {
  Form,
  withFormState
} from '@glueit/forms'

The observer

const SimpleStates = withFormState(({ form, stateStrs }) => (
  <>
    The current state of the form is:
    <span>{stateStrs[form.state]}</span>
  </>
))

The form

<Form>
  <SimpleStates />
</Form>

Submit handling

Create your submit handler function.

const handleSubmit = async (e, body, actions) => {
  e.preventDefault()
  console.log(body)
  console.log(actions)
  // This is just for example...
  const result = await new Promise(res => {
    setTimeout(() => {
      // actions.pristine('success')
      //actions.clear('success')
      actions.error('server')
      res('done')
    }, 3000)
  })
  console.log(result)
}

Pass that function to your Form.

<Form onSubmit={(e, form, acitons) => handleSubmit(e, form, actions)}>

Submit handler actions

Your submit handler gets three params.

  • e: This is the synthetic event. Be sure to call e.preventDefault() if you want to handle to submission yourself.
  • body: This is the data for your form in field name and value pair.
  • actions: This is an object containing functions that you can call to update the form state when you are done.

Optional update

  • actions.updates([{ path: "...", value: "..." }]): Allows you to update a list of fields.

Expected to call one of the following

  • actions.clear([type]): This will clear the form and all data.
  • actions.pristine([type]): This will leave the data in place but will set the form to pristine. Which means that there are no unsaved changes. It is useful if you are allowing ongoing edits with periodic saves.
  • actions.error([type]): When an error occurs.

For all three of these actions you can specify your own type. For example, maybe you want to have error_server as shown above. In this case you would call with actions.error('server').

Built-in validators

Apply any or all of the following to your fields as needed.

  • required (any)
  • maxLength (string, array)
  • minLength (string, array)
  • max (numeric)
  • min (numeric)
  • match (regexp)

Custom validators

Create a function that takes a value:

const range20to30 = ({ value }) => {
  return value >= 20 && value <= 30
}

Pass that function to your Form and apply that validator to a field.

<Form validators={{ range20to30 }}>
  <Input
    name="age"
    label="Age"
    helperText="What is your age?"
    required
    range20to30
  />
</Form>

Custom messages

Create an object with your messages.

const messages = {
  range20to30: 'You must be between 20 and 30 years of age to participate.'
}

Pass that object to your Form.

<Form messages={messages}>

Form states

There are three states.

  • pristine: A form that is pristine means that it has no modifications to its state. It can have data, but there are no [unsaved] modifications to its data.
  • error: A form that has errors such as a required field or invalid data. A form can also be in error state if the submission fails on the server side such as a 500 error.
  • dirty: A form that has unsaved changes.

You can override the messages for any of these or create custom states.

Custom states

Create an object with your states. Make sure each state is prefixed with one of the allowed states.

  • pristine_
  • error_
const stateStrs = {
  pristine_success: 'Your submission was a success!',
  error_server: 'There was a server error.'
}

Pass that object to your Form.

<Form stateStrs={stateStrs}>

Object Scoping

Object scoping allows your output to have nested objects.

<Input name="name" label="Name" required />
<Input name="skills.first" label="Your Best Skill" required />
<Input name="skills.second" label="Your Second Skill" required />

<Input name="references[0].name" label="Your Reference Name #1" required />
<Input name="references[0].phone" label="Phone" required />
<Input name="references[1].name" label="Your Reference Name #2" required />
<Input name="references[1].phone" label="Phone" required />

Will create the following in your form output:

{
  name: 'John Doe',
  skills: {
    first: '...',
    second: '...
  },
  references: [
    {
      name: "...",
      phone: "...
    },
    {
      name: "...",
      phone: "...
    }
  ]
}

Lists

You can create lists that are arbitrarily deep. For example, employment history would be a list.

Import lists

import { List, withListActions } from '@glueit/forms'

Add and Remove Components

These can be any component that you want. Just wrap with the withListActions HOC.

const AddListItem = withListActions(({ text, to, listActions }) => {
  return <Link onClick={() => listActions.addItemToList(to)}>{text}</Link>
})

const RemoveListItem = withListActions(({ text, from, index, listActions }) => {
  return (
    <Link onClick={() => listActions.removeItemFromList(from, index)}>
      {text}
    </Link>
  )
})

Add the List to your form

Notice that we create a List with name of employers. The value of this field will now be an array instead of a string. Each element in the employers array will be an object containing employer, title, duration, and a sub list of managers.

<Form>
  <h3>Your Employment History</h3>
  <List minLength="2" maxLength="5" name="employers">
    <h5>Employer Entry</h5>
    <RemoveListItem from text="Remove Employer" />
    <Input name="employer" label="Employer" required />
    <Input name="title" label="Your Title" required />
    <Input name="duration" label="Years / months duration" />
    <h6>Your Managers</h6>
    <List name="managers" minLength="1" maxLength="2">
      <Input name="name" label="Manager" />
      <RemoveListItem from text="Remove Manager" />
    </List>
    <br />
    <br />
    <AddListItem to="managers" text="Add Manager" />
    <hr />
  </List>
</Form>

Visibility

You can control visibility of Fields by using the VisibilityGroup component. Only fields that are visible will carry to the onSubmit event of the form.

import Form, {
  VisibilityGroup
} from '@glueit/forms'

Then wrap your field(s) as needed. Use the isVisible prop to tell the group if it is visible or not.

<VisibilityGroup isVisible={form => form.fields.age && form.fields.age.value > 21}>
...
</VisibilityGroup>

Scope

You can control scope of child Fields by using the Scope component.

import Form, {
  Scope
} from '@glueit/forms'

Then wrap your field(s) and provide a path to your Scope. In this example you are wrapping a user object with name and email.

<Scope path="user">
  <Input name="name" label="Name" required />
  <Input name="email" label="Email" required />
</Scope>

Set Field

Use set field to declaratively set the value of a field. This will only run once unless you change the value attribute OR destroy the field and re-create it.

import Form, {
  SetField
} from '@glueit/forms'

<SetField name="firstName" value="Jeff">

State management

State is handled using the context hook. You can access the form state from onSubmit property on Form or using observers as described above.