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

onion-form

v0.4.0

Published

onion-form

Downloads

103

Readme

Onion Form CircleCI Dependency Status

As a developer you are assigned with creating a registration form on Registration page with fields for first name, last name, e-mail and password, validate them and then send all these fields to API. Not again? This package will make your life easier by simplifying the dealing with forms.

yarn add --save onion-form

This package is only meant to be used together with Redux!

TLDR

import { Form, Field, Submit } from 'onion-form';

<Form
  name="signIn"
  onError={({ errors }) => { console.log(errors) }}
  onSubmit={({ values }) => { console.log(values) }}
  validations={{ email: (value) => [((value && !value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)) ? 'wrongFormat' : null)]}}
>
  <Field name='email' type='email' />
  <Field name='password' type='password' />
  <Submit>Sign In</Submit>
</Form>

Usage

// Registration.react.js
import React, { Component } from 'react';
import { Form, Submit, connectField } from 'onion-form';

// validations
const isRequired = (value) => ((!value) ? 'required' : null);
const emailNeedsToContainName = (_, otherValues) => ((!otherValues.email || otherValues.email.indexOf(otherValues.name) === -1) ? 'invalidEmail' : null);
const needLetters = (value) => (value && !value.match(/[a-zA-Z]+/i ? 'needLetters' : null);
const needNumbers = (value) => (value && !value.match(/\d+/i) ? 'needNumbers' : null);

const validations = {
  lastName: [isRequired],
  email: [emailNeedsToContainName],
  password: [needLetters, needNumbers]
};

// You need to have a component which will receive all data by props
// error, hint, label, name, onBlur, onChange, onFocus, onionFormName, tooltip
const BasicInput = (props) => (<input type="text" {...props} />);

// Create your fields (can be used in different forms)
const FirstName = connectField('firstName')(BasicInput);
const LastName  = connectField('lastName')(BasicInput);
const Email     = connectField('email', { type: 'email' })(BasicInput);
const Password  = connectField('password', { type: 'password' })(BasicInput);

export default class RegistrationPage extends Component {

  onSubmit({ values: { firstName, lastName, email, password } }) {
    // apiCall('POST', { firstName, lastName, email, password })
  }

  onError({ errors: { firstName, lastName, email, password } }) {
    // alert, show flash message what ever you need to do when use tryies to
    // submit form and gets validation errors
  }

  render() {
    return (
      <div>
        <h1>Registration</h1>
        <Form
          name="myRegistrationForm"
          onSubmit={this.onSubmit.bind(this)}
          onError={this.onError.bind(this)}
          validations={validations}
        >
          <FirstName label="Your first name" />
          <LastName />
          <Email />
          <Password />
          <Submit>Register</Submit>
        </Form>
      </div>
    )
  }
}

Validations

There are three ways how you can add validations to your form:

  1. Pass an object with validations to the Form component as props (see examples above)
  2. Pass an array of validations to the connectField function: connectField('password', null, [isRequired(), password()])
  3. Specify the validations when the field component is being used:
export default class MyForm extends Component {
  render() {
    return (
      <Form name="myForm">
        <Email validations={[isRequired(), email()]} />
        <Password validations={[isRequired(), password()]}/>
        <Submit>Login</Submit>
      </Form>
    )
  }
}

All validations you specify will be used.

Redux

!You need to add onion form reducer to your reducers and it must be under onionForm first level key!

// store.js
import { createStore, combineReducers } from 'redux';
import { reducer as onionForm } from 'onion-form';

const store = createStore(combineReducers({ onionForm }), {})

Action Creators

We have multiple action creators for communication with reducer: setMultipleFields, setFormFieldProperty, clearForm, clearFormProperty, setFieldValue, setFieldLiveValidation, setFieldError, setFieldApiError All these actions accept formName as the first parameter which needs to match FORM_NAME in <Form name=FORM_NAME/>.

All connected fields get formName from context.

But sometimes you need to communicate with fields from your code and repeating name of the form can be exhausting, so we provide createFormActions(formName) which returns all the actions with formName set.

connectField(FIELD_NAME, DEFAULT_PROPS)(DECORATED_COMPONENT)

DEFAULT_PROPS: can be a plain {} or a function which receives props as the first parameter and needs to return {}. This function gets resolves in render on every rerender. (props) => ({ label: props.msg('key.to.label') })

FIELD_VALUES_FROM_STATE: By default we store these values in redux state:

{
  value: '',
  liveValidation: false,
  error: null,
  apiError: null
}

But you can use setMultipleFields(form, property, values) or setFormFieldProperty(form, field, property, value) to set custom properties which will be then passed to the decorated component as well.

ONION_PROPS: error, hint, label, name, onBlur, onChange, onFocus, onionFormName, tooltip

When you initialize a component in render you can pass the following PASSED_PROPS:

PASSED_PROPS label, onBlur, onFocus, onChange, tooltip, hint, defaultValue They will be transferred to the decorated component. Functions passed by props (onFocus, onChange, onBlur) will get called too, after onion form callbacks.

Passing order of props is: DEFAULT_PROPS -> FIELD_VALUES_FROM_STATE -> ONION_PROPS -> PASSED_PROPS

You can pass defaultValue to component by (PROPS or DEFAULT_PROPS) to set that value to state on componentDid mount when field has no value already set.

connectSubmit(DECORATED_COMPONENT)

You can use connectSubmit which will pass onClick, valid, hasValues, hasErrors and disabled as prop to the decorated component:

// CustomSubmit.react.js
import { connectSubmit } from 'onion-form';

const Button = ({ children, disabled, onClick }) => (
  <button disabled={disabled} onClick={onClick} type="submit">{children}</button>
);

export default const connectSubmit(Button);
  • onClick: callback function for submitting form
  • valid: returns true/false based on fields validations runned against state (errors doesn't need to be in store)
  • hasErrors: returns true if form is invalid (based on state from Redux)

Translations

You need to pass to component function msg('keypath') => string.

Implemetation is your thing but it needs to follow:

msg('key.foo') // returns translation for key.foo
msg(['foo', 'bar']) // returns translation for foo if exists else bar

We use this function to resolve translations for the error, hint, label, tooltip, placeholder props.

error is specific because we are trying to get text by:

const error = field.error || field.apiError;
const errorText = error
  ? msg([`form.${formName}.errors.${error}`, `form.errors.${error}`, `errors.${error}`])
  : '';

others are easier, for example label:

const labelText = label || defaultProps.label || msg([`form.${formName}.${fieldName}.label`, `form.${fieldName}.label`, `${fieldName}.label`]);

!For detailed documentation of all options do yarn test!

Commands

  • yarn test: runs mocha tests
  • yarn test:watch: runs mocha test with watch option
  • yarn coverage: create code coverage report

Made with love by