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

formfish

v0.6.15

Published

React Context Form Engine

Downloads

12

Readme

FormFish 🐠

This project represents an idea to bring React into the world of HTML forms. Our approach uses such technologies like hooks and context, thus making it easy to interact with the Form and allowing it to be built by itself.

Installation

formfish is being distributed by npm package registry. Make sure to have react and react-dom installed to get it properly working (of course).

$ npm i formfish
# or
$ yarn add formfish

Usage

This package has three components exposed. Each of them could be imported from the root (named import) or from the respective component's folder (default import).

import { Field } from 'formfish';
// or
import Field from 'formfish/components/Field';

To use formfish properly, first, make a form!

import { Form, Field } from 'formfish';

const App = () => (
  <Form name="My lovely form" onSubmit={handleSubmit}>
    <Field name="First field">
      <input type="text" />
    </Field>
  </Form>
);

With such a setup our form state should automatically build itself in an object with the following scheme:

{
    myLovelyForm: {
        firstField: {
            name: 'First field',
            value: '' // or any defaultValue you pass to the input
        }
    }
}

After you are done with this form, submit it by passing a callback to the onSubmit Form prop. The callback signature of this function is better explained in the Validation section.

Note, that onSubmit fires upon native form's submission, so you could just place a button inside a form it works just right!

Also, don't bother with not wrapping your form components as we use context to provide them with needed state. Use any level of depth - it won't break!

Validation

If you'd like to somehow validate your form - use any method you find fit. Form component has a built-in method onValidate that accepts a special callback with form's state.

Make sure to throw an Error when handling your validation as this will cause onSubmit to not be called if something goes wrong.

FieldSet

FieldSet is a wrapper around multiple fields at a time. It can be used as an object-like structure:

<FieldSet name="Object of fields">
  <Field name="Field one">...</Field>

  <Field name="Field two">...</Field>
</FieldSet>

This will produce a state with the following interface:

{
    objectOfFields: {
        fieldOne: { ... },
        fieldTwo: { ... }
    }
}

Also, it can be represented as an array of fields or field sets (don't forget to pass index to each one of those Fields/FieldSets!):

<FieldSet name="Array of fields">
  {['fieldOne', 'fieldTwo'].map((fieldName, index) => (
    <Field name={fieldName} index={index}>
      ...
    </Field>
  ))}
</FieldSet>

This will result in an array within your state:

{
    arrayOfFields: [{...}, {...}]
}

Field

Field is a wrapper around your input. It automatically registers an input in the form, providing it with context about its value.

<Field name="my-lovely-field">
  <input type="text" />
</Field>

Instead of passing a child component inside, it is also possible to pass a renderInput prop to the Field, which is called with value and setValue props, that you later use on your input.

<Field
  name="my-lovely-field"
  renderInput={({ value, setValue }) => (
    <input type="text" value={value} onBlur={({ target: { value: inputValue } }) => setValue(inputValue)} />
  )}
/>

If you are using a native input, make sure to pass some default values to the callback functions, as otherwise it will throw a controlled/uncontrolled input error.

Also, note that renderInput is not affected by Common customization props.

watch

Every component in a formfish has build-in watch method that grants access to its state.

It accepts a function with a state argument to grab needed state and interact with it freely.

<Form watch={(state) => console.log(state)}> // Whole Form state
    <FieldSet watch={(state) => console.log(state)}> // This particular FieldSet only
        <Field watch={(state) => console.log(state)}> // This specific Field
            // ...
        </Form>
    </FieldSet>
</Form>

useForm

Another method to grab a state of a certain component is to use our useForm hook inside your components that dwell inside the Form.

It exposes the getState function from the context that accepts lodash-like path and returns the state of a component by this path.

Common customization props

Every component here has some props in common. What we are interested in, though, are those which are used for behaviour customization:

  • nameSeparator - custom separator for the names. For example, by default we use ' ' to convert field name to fieldName.
  • getters - names of props we access on the input:
    • value
    • defaultValue
    • event
    • id
  • getValue - a function that helps getting a proper value from an input when needed event fires.
  • setValue - a function that sets proper value on the input after it's been updated in the state.

On the GIF below, we getValue from the input, convert it to Base64, put it in the form, then setValue to the input converted back to UTF-8.

Example

<Field getValue={value => btoa(value)} setValue={value => atob(value)}>
  <input type="text" />
</Field>

By default, getValue's signature already uses that of a native event's callback.

initialState

Form component accepts another valuable prop - initialState. You can pass an object that represents the state you build in the JSX markup that gets populated onto the inputs.

<Form
    name="form"
    initialState={
        form: {
            initiate: {
                value: 'Initiated!'
            }
        }
    }
>
    <Field name="initiate">
        <input type="text" /> // input here gets the 'Initiated!' value
    </Field>
</Form>

Contributing

If you are willing to become a contributor to this project or just have questions, fell free to come visit our Contributing guide that will lead you further.