3.0.0 • Published 5 years ago

uniform-react-components v3.0.0

Weekly downloads
2
License
MIT
Repository
github
Last release
5 years ago

uniform-react-components

Travis npm version Conventional Commits semantic-release code style: prettier linter: lynt

HOC for creating components with the same simple interface to handle onChange events on react components

Also exports Input and Select components using this pattern to help with implementation of forms and such

Features

  • Generate efficient onChange handlers, so you don't have to make every one of them manually
  • Easy form creation with components with the same interface
  • Great typescript support

Usage

For a class component

import { UniformComponent, UniformProps } from "uniform-react-components"

const MyUniformComponent = UniformComponent(
  class MyComponent extends React.Component<
    UniformProps<{ foo: string }> & { customProp: string }
  > {
    render() {
      return (
        <div>
          Custom prop: {this.props.customProp}
          <input
            name={this.props.data.path.foo.join(".")}
            type="text"
            value={this.props.data.value.foo || "undef"}
          />
        </div>
      )
    }
  },
)

For a SFC (stateless functional component)

import { UniformComponent, UniformProps } from "uniform-react-components"

const MyUniformComponent = UniformComponent(
  (props: UniformProps<{ foo: string }> & { customProp: string }) => (
    <div>
      Custom prop: {props.customProp}
      <input
        name={props.data.path.foo.join(".")}
        type="text"
        value={props.data.value.foo || "undef"}
      />
    </div>
  ),
)

UniformComponent

The UniformComponent is the main component of uniform-react-components, it's a HOC which is used to make simple components for handling forms and subforms, or anything that holds a value and can be changed.

All components created with 'UniformComponent' receive the props specified, plus a data which holds this helpers:

interface IData {
  path
  value
  onChange
}

For example, for this type

interface ISimpleData {
  age: number
  password: string
  username: string
}

The component will receive in the props.data handlers like if you did:

props.data = {
  value: {
    age: 3,
    password: "myPassword",
    username: "myUsername",
  },
  change: {
    age: newAge => {
      /* dispatch this.props.onChange({ ...previousData, age: newAge })*/
    },
    password: newPassword => {
      /* dispatch this.props.onChange({ ...previousData, password: newPassword })*/
    },
    username: newUsername => {
      /* dispatch this.props.onChange({ ...previousData, username: newUsername })*/
    },
  },
  path: {
    age: ["previousPath", "otherPreviousPath", "age"],
    password: ["previousPath", "otherPreviousPath", "password"],
    username: ["previousPath", "otherPreviousPath", "username"],
  },
}

Full example:

interface IData {
  foo?: string
  bar: number
}

interface IProps {
  hidden?: boolean
}

const MyUniformComponent = UniformComponent(
  class MyComponent extends React.Component<UniformProps<IData> & IProps> {
    render() {
      return (
        <div>
          {this.props.hidden ? "is hidden" : "is visible"}
          <input
            name={this.props.data.path.foo.join(".")}
            type="text"
            value={this.props.data.value.foo || "undef"}
          />
          <input
            name={this.props.data.path.bar.join(".")}
            type="text"
            value={this.props.data.value.bar}
          />
        </div>
      )
    }
  },
)

const MyUniForm = UniformComponent((props: UniformProps<{ a: IData; b: IData }>) => (
  <form action="">
    <MyUniformComponent value={props.data.value.a} />
    <MyUniformComponent hidden={true} value={props.data.value.b} />
  </form>
))

Then mount MyUniForm component:

  <MyUniForm onChange={(data) => console.log(data} value={{a: { bar: 3}, b: { bar: 5}}} />

and every time the user types in the inputs, it will be outputted the value

Built-in helpers

uniform-react-components exports two input helpers ( UniformInput and UniformInputNumber ) and a select helper that have the same interface, it only changes the onChange ( and defaultValue which is the case of UniformInputNumber ) properties, and accepts all the properties of a plain input element. This only saves you the trouble of implementing these components, but you could implement them if you want to, and even add some more.

UniformInput

The same as the plain input element, but the onChange property returns an string instead of a change input event

<UniformInput
  onChange={newValue => console.log(`This is my value ${newValue}`)} // newValue is string
  defaultValue="hello"
  // you can add all the other properties such as type, className, style...
/>

UniformInputNumber

The same as the plain input element, but the onChange property returns an number instead of a change input event, and the defaultValue accepts an number too. You must still set the type="number" property if you want a number input

<UniformInputNumber
  onChange={newValue => console.log(`This is my value ${newValue}`)} // newValue is number
  defaultValue={3} // typescript complains if it's string
  type="number"
  // you can add all the other properties such as className, style...
/>

UniformSelect

import { UniformSelect, UniformOptionProps } from "./index"
    type MaleOrFemale = "male" | "female"
    const options: UniformOptionProps<MaleOrFemale>[] = [
      {
        value: "male",
        children: "Male",
      },
      {
        value: "female",
        children: "Female",
      },
    ]
    let changed: MaleOrFemale | null = null
    const el = <UniformSelect options={options} onChange={(newValue) => console.log(newValue)} defaultValue={"male"} />, // newValue is MaleOrFemale
/>

The options is an array of Options, which has all the properties the option element takes, but value is restricted to the specified type, so it enforces type safety

3.0.0

5 years ago

2.0.2

6 years ago

2.0.1

6 years ago

2.0.0

6 years ago

1.5.0

6 years ago

1.4.1

6 years ago

1.4.0

6 years ago

1.3.0

6 years ago

1.2.0

6 years ago

1.1.0

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago