UNPKG

@eaze/input

Version:

React components:

172 lines (153 loc) 5.5 kB
# Automated inputs and forms This is a new (as of Jan 2017) set of input/form components. ```js import { Checkbox, Password, Email, Zipcode, PhoneNumber, Form, Input, InputWithLabel, TextField, Select } from '@eaze/input' ``` ## Motivation We need a set of controlled inputs and forms that allow for autocompletion in mobile and enough built-in management that forms come with the following: - Field-level errors - Float labels - Self-managed submit buttons that correctly trigger the `Go` on Safari mobile keyboards and manage their disabled states ## Changes Changes from old inputs (made by @ghigo): - Form state is now in React state, not in Redux - Inputs are not copied using React's `cloneElement`, so they are safe to modify after construction - Inputs self-register and update through [React's context methods](https://facebook.github.io/react/docs/context.html) - Because the inputs require the context methods, these inputs are not usable outside of the `Form` component ## How to use Here are some examples of how to use/create the new inputs and forms. ### Creating a Form Example: ```jsx <Form // define an onSubmit, which will receive an object with // keys equal to the `name` supplied to each input // ex: {email: { value: 'john@smith.com', valid: true }, password: { value: '123', valid: false }} onSubmit={this.onSubmit} // This submit text will appear on the submit button // automatically included with and managed by the form // unless you set the `includeButton` prop to false, // in which case you'll have to supply your own button. submitText={'Sign up'} // `includeButton` defaults to true. // If you set it to false, supply your own buttons, as in this example includeButton={false} > // A higher level component that consumes `./input-with-label.js` <EmailInput name='email' placeholder='Email' eagerValidate required /> // ... Other inputs like EmailInput // Because we declared `includeButton` prop as false, we set buttons here <div className={style.buttons}> // Use FormButton when making custom form buttons // This consumes EazeButton and overwrites props with // the correct props taken in through React `context` methods <FormButton buttonProps={{ loading: this.props.loading, title: 'Sign up', type: buttonTypes.PRIMARY }} /> <div className={style.border}> <Border /> </div> <div className={style.logIn}> Already have an account? <div className={style.logInButton}> <FormButton buttonProps={{ title: 'Log In', type: buttonTypes.TERTIARY }} /> </div> </div> </div> </Form> ``` ### Creating a new input Inputs self-register through context methods. Required methods/properties for a new higher-level input include the following: - `<Component>.contextTypes`: Must include #register and #onChange context methods to be used in the constructor and when the input updates. - Validators: in the constructor, make a `this.validators` array of functions that are used by the consumed Input - `#componentDidMount`: Must register using the `this.context.register` function - `#onChange`: Must make a function that takes the `input`'s change event and abstracts its value into the `context.onChange` method Generally you'll want to consume and use `InputWithLabel`, as that comes with float labels. Example: ```jsx import React from 'react' import PropTypes from 'prop-types' import zip from 'zippo' import InputWithLabel from './input-with-label' class Zipcode extends React.Component { constructor () { super() this.onChange = this.onChange.bind(this) // This array should have functions that either return null when there are no errors // and return strings of error messages when there are errors this.validators = [ // check for null if required (value) => { if (!this.props.required) return null if (!value) return 'Zipcode is required.' }, (value) => { if (!value) return null return zip.validate(value) ? null : 'Please enter a valid zipcode' } ] } onChange (e) { this.context.onChange(this.props.name, e.target.value, this.wrapper.inputContainer.isValid()) } componentDidMount () { this.context.register(this.props.name, this.props.initialValue) } // if you want to provide a parser to be used by Input, define it here and pass it down. // Make it a function that takes and returns a string. parser (value) { return zip.parse(value || '') } render () { // Use phone type input to force number keyboard on mobile devices return ( <InputWithLabel {...this.props} name={this.props.name} type='phone' parser={this.parser} validators={this.validators} onChange={this.onChange} ref={(wrapper) => { this.wrapper = wrapper }} eagerValidate /> ) } } Zipcode.contextTypes = { onChange: PropTypes.func, register: PropTypes.func } export default Zipcode ``` ## Where is @eaze/input used? Disclaimer: This is not a complete list - [eaze.com](https://github.com/eaze/eaze.com) - signup - login - profile