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

create-redux-form

v0.1.2

Published

A lightweight schema constructor for redux-form with a configurable UI-Kit.

Downloads

80

Readme

What is This?

Redux Form is a great library for creating and managing forms and their state in redux applications. But, it leaves a lot of common boilerplate code up for the user to implement. This library aims to remove this duplication of code while at the same time keeping the ability to define your own custom form components.

Install

To install, run yarn add create-redux-form or npm install create-redux-form.

Create Your Form Generator

First, you'll need redux-form compatible input components. See Redux Form Field Usage. Once you have the components you need you can go ahead and create your custom generator like this:

/* form-generator.js */
import createReduxForm from 'create-redux-form'
import FormHeader from './components/form-header'
import FormInfo from './components/form-info'
import TextInput from './components/text-input'
import NumberInput from './components/number-input'

export const { form, wizardForm } = createReduxForm({
  header: FormHeader,
  info: FormInfo,
  text: TextInput,
  number: NumberInput
})

The object passed in as the first parameter will be the UIKit used to generate your forms.

Generate a Form or Wizard Form

This is how you would then use your generator to generate a form. Both form and wizardForm take two parameters, a formName and a schema.

/* validation.js */
export const required = name => v => (v ? undefined : `${name} is required.`)
export const number = name => v =>
  Number.isNaN(Number(v)) ? `${name} must be a number.` : undefined
/* buy-pnk-form.js */
import { form } from './form-generator'
import { required, number } from './validation'

export const {
  Form: BuyPNKForm, // The form react component
  isInvalid: getBuyPNKFormIsInvalid, // A redux state selector that returns true if the form's validation passed and false otherwise
  submit: submitBuyPNKForm // An action creator that returns an action object that submits the form when dispatched
} = form('buyPNKForm', {
  header: {
    type: 'header',
    props: { title: 'BUY PNK' }
  },
  rate: {
    type: 'info'
  },
  amount: {
    type: 'text',
    validate: [required, number]
  }
})

If you wanted a wizard form instead, all you need to do is nest the schema one level deeper with components grouped in "steps". E.g.

/* buy-pnk-wizard-form.js */
import { form } from './form-generator'
import { required, number } from './validation'

export const {
  Form: BuyPNKForm,
  isInvalid: getBuyPNKFormIsInvalid,
  submit: submitBuyPNKForm
} = form('buyPNKForm', {
  // The names of the steps are irrelevant
  info: {
    header: {
      type: 'header',
      props: { title: 'BUY PNK' }
    },
    rate: {
      type: 'info'
    }
  },
  pay: {
    amount: {
      type: 'text',
      validate: [required, number]
    }
  }
})

Breaking Down The Form Schema

These are all the properties you can have in a schema.

const schema: {
  // The key gets passed to your component as the prop `placeholder` after being converted from `camelCase` to `TitleCase`. E.g. accountUsername => Account Username
  [placeholder]: {
    type: string, // This is the component you want to use from the `UIKit` passed in to `createReduxForm`
    // Validator functions or functions that take the field's placeholder and return a validator function, like the examples above, (`required`, `number`). Validator functions should return undefined if the checks passed or a string with an error message for the failure
    validate: (
      | ((placeholder: string) => (value: string) => undefined | string)
      | ((value: string) => undefined | string)
    )[],
    visibleIf: string, // Only render this field if the value of the specified field is truthy or falsy. I.e. `visibleIf: 'email'` or `visibleIf: '!email'`
    // `redux-form` [formValues](https://redux-form.com/7.2.3/docs/api/formvalues.md/)
    formValues: boolean,
    props: object, // Props to pass down to your component
    reduxFormFieldProps: object // Props to pass to `redux-form`'s [Field](https://redux-form.com/7.2.3/docs/api/field.md/) component
  }
} = {
  email: {
    type: 'text',
    validate: [v => (v ? undefined : `${name} is required.`)],
    visibleIf: 'username',
    formValues: { currentUsername: 'username' },
    props: { placeholder: 'Secondary Email' }, // You can override the default placeholder, `camelToTitleCase(key)`, like this too
    reduxFormFieldProps: { normalize: v => v.replace(' ', '') }
  }
}

Rendering the Form and WizardForm

This is how you would render and use the Form.

import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

import {
  BuyPNKForm,
  getBuyPNKFormIsInvalid,
  submitBuyPNKForm
} from './buy-pnk-form'

const Component = ({ buyPNKFormIsInvalid, submitBuyPNKForm }) => (
  <div>
    {/* In addition to these props, you can also pass in any prop that a `redux-form` [form](https://redux-form.com/7.2.3/docs/api/reduxform.md/) takes */}
    <BuyPNKForm
      onSubmit={formData => `We submitted! ${formData}`} // Do what you need to do with the data
      className="BuyPNKForm" // Inner `fieldset` will have class name `BuyPNKForm-fieldset` and inner `fields` will have class name `BuyPNKForm-fieldset-fields`
      disabled={false}
    />
    <button onClick={submitBuyPNKForm} disabled={buyPNKFormIsInvalid}>
      Submit
    </button>
  </div>
)

export default connect(
  state => (
    {
      buyPNKFormIsInvalid: getBuyPNKFormIsInvalid(state)
    },
    {
      submitBuyPNKForm
    }
  )
)(Component)

This is how you would render and use the WizardForm.

import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

import {
  BuyPNKForm,
  getBuyPNKFormIsInvalid,
  submitBuyPNKForm
} from './buy-pnk-form'

class Component extends PureComponent {
  state = {
    currentPage: 0,
    hasPrevPage: false,
    hasNextPage: false,
    totalPages: 0
  }

  getBackHandlerRef = ref => (this.backHandlerRef = ref)

  handlePageChange = (wizardFormState, formData) => {
    console.log(`This is what we have entered so far ${formData}!`)
    this.setState(wizardFormState)
  }

  render() {
    const { buyPNKFormIsInvalid, submitBuyPNKForm } = this.props
    const { hasPrevPage, hasNextPage } = this.state
    return (
      <div>
        {/* In addition to these props, you can also pass in any prop that a `create-redux-form` Form takes and they will be applied to the current page in the wizard */}
        <BuyPNKForm
          onSubmit={formData => `We submitted! ${formData}`} // Do what you need to do with the data
          backHandlerRef={this.getBackHandlerRef}
          onPageChange={this.handlePageChange}
          transitionName="someCSSAnimation" // Default is `carousel` and can be imported from the module, i.e. `@import '~create-redux-form/animations/carousel.css';`
          className="BuyPNKWizardForm" // Inner `Form` will have class name `BuyPNKWizardForm-form`
        />
        {hasPrevPage && <button onClick={this.backHandlerRef}>Go Back</button>}
        <button onClick={submitBuyPNKForm} disabled={buyPNKFormIsInvalid}>
          {hasNextPage ? 'Next' : 'Submit'}
        </button>
      </div>
    )
  }
}

export default connect(
  state => (
    {
      buyPNKFormIsInvalid: getBuyPNKFormIsInvalid(state)
    },
    {
      submitBuyPNKForm
    }
  )
)(Component)

Rendering Decorational/Informational Components

Because you create your own UIKit to pass into the createReduxForm, it is very easy to extend your schema to support purely decorational components. Here is how you would make a simple info box.

import React from 'react'
import PropTypes from 'prop-types'

import './form-info.css'

const FormInfo = ({ input: { value } }) => (
  <div className="FormInfo">
    <h5 className="FormInfo-text">{value}</h5>
  </div>
)

FormInfo.propTypes = {
  input: PropTypes.shape({ value: PropTypes.string.isRequired }).isRequired
}

export default FormInfo

Then, when rendering the form that contains this field, you pass in the value in the redux-form initialValues prop.

<SomeForm
  enableReinitialize // Enable this if the value is dynamic, so the form rerenders when it changes
  keepDirtyOnReinitialize // This lets you keep the value of the other fields when the form reinitializes
  initialValues={{
    yourFieldSchemaKey: `Here is your info: ${someDynamicInfo}`
  }}
/>