Skip to content

redbmk/react-powerplug

 
 

Repository files navigation

React PowerPlug

npm stars tweet


React PowerPlug is a set of pluggable renderless components and helpers that provides different types of state and logics so you can use with your dumb components. It creates a state and pass down the logic to the children, so you can handle your data. Read about Render Props pattern.

Highlights

  • 👌 Dependency free
  • 🔌 Plug and play
  • 🔮 Tree shaking friendly (ESM, no side effects)
  • 📦 Super tiny (~3kb)
  • 📚 Well documented
  • 🍻 Bunch of awesome utilities
See quick examples
import { State, Toggle } from 'react-powerplug'
import { Pagination, Tabs, Checkbox } from './MyDumbComponents'

<State initial={{ offset: 0, limit: 10, totalCount: 200 }}>
  {({ state, setState }) => (
    <Pagination {...state} onChange={(offset) => setState({ offset })} />
  )}
</State>

<Toggle initial={true}>
  {({ on, toggle }) => (
    <Checkbox checked={on} onChange={toggle} />
  )}
</Toggle>

// You can also use a `render` prop instead

<Toggle
  initial={false}
  render={({ on, toggle }) => (
    <Checkbox checked={on} onChange={toggle} />
  )}
/>

⚠️ Master is unstable

This branch is unstable and is in active development.
For the latest stable version go to 0.1-stable branch

Components

Note This is a kind of a cheat sheet for fast search.
If you want a more detailed API Reference and examples for each component see full docs

Component Component Props Render Props
STATE CONTAINERS
<State> { initial, onChange } { state, setState } 👇 📚
<Toggle> { initial, onChange } { on, toggle, set } 👇 📚
<Counter> { initial, onChange } { count, inc, dec, incBy, decBy, set } 👇 📚
<Value> { initial, onChange } { value, setValue, set } 👇 📚
<Map> { initial, onChange } { set, get, over, values } 👇 📚
<Set> { initial, onChange } { values, add, clear, remove, has } 👇 📚
<List> { initial, onChange } { list, first, last, push, pull, sort, set } 👇 📚
FEEDBACK CONTAINERS
<Hover> { onChange } { isHovered, bind } 👇 📚
<Active> { onChange } { isActive, bind } 👇 📚
<Focus> { onChange } { isFocused, bind } 👇 📚
<Touch> { onChange } { isTouched, bind } 👇 📚
<FocusManager> { onChange } { isFocused, blur, bind } 👇 📚
FORM CONTAINERS
<Input> { initial, onChange } { set, value, bind } 👇 📚
<Form> { initial, onChange } { input, values } 👇 📚
OTHER
<Interval> { delay } { stop, start, toggle } 👇 📚
<Compose> { components } depends on components prop 👇 📚

Utilities

Name
compose(...components) 📚
composeEvents(...objOfEvents) 📚

Examples

State

<State initial={{ isLoading: false, data: null }}>
  {({ state, setState }) => (
    <DataReceiver
      data={state.data}
      onStart={() => setState({ isLoading: true })}
      onFinish={data => setState({ data, isLoading: false })}
    />
  )}
</State>

Toggle

<Toggle initial={true}>
  {({ on, toggle }) => <Checkbox checked={on} onChange={toggle} />}
</Toggle>

Counter

<Counter initial={0}>
  {({ count, inc, dec }) => (
    <CartItem
      productName="Lorem ipsum"
      unitPrice={19.9}
      count={count}
      onAdd={inc}
      onRemove={dec}
    />
  )}
</Counter>

Value

<Value initial="React">
  {({ value, setValue }) => (
    <Select
      label="Choose one"
      options={['React', 'Angular', 'Vue']}
      value={value}
      onChange={setValue}
    />
  )}
</Value>

Map

<Map initial={{ sounds: true, graphics: 'medium' }}>
  {({ set, get }) => (
    <Settings>
      <ToggleCheck checked={get('sounds')} onChange={c => set('sounds', c)}>
        Game Sounds
      </ToggleCheck>
      <Select
        label="Graphics"
        options={['low', 'medium', 'high']}
        selected={get('graphics')}
        onSelect={value => set('graphics', value)}
      />
    </Settings>
  )}
</Map>

Set

<Set initial={['react', 'babel']}>
  {({ values, remove, add }) => (
    <TagManager>
      <FormInput onSubmit={add} />
      {values.map(tag => (
        <Tag onRemove={() => remove(tag)}>{tag}</Tag>
      )}
    </TagManager>
  )}
</Set>

List

<List initial={['Buy new shoes']}>
  {({ list, pull, push }) => (
    <Todo>
      <TodoFormInput onSubmit={push} />
      {list.map(todo => (
        <TodoItem onDelete={() => pull(i => i === todo)}>
          {todo}
        </TodoItem>
      )}
    </Todo>
  )}
</List>

Hover

<Hover>
  {({ isHovered, bind }) => (
    <div {...bind}>
      You are {isHovered ? 'hovering' : 'not hovering'} this div.
    </div>
  )}
</Hover>

Active

<Active>
  {({ isActive, bind }) => (
    <div {...bind}>
      You are {isActive ? 'clicking' : 'not clicking'} this div.
    </div>
  )}
</Active>

Touch

<Touch>
  {({ isTouched, bind }) => (
    <div {...bind}>
      You are {isTouched ? 'touching' : 'not touching'} this div.
    </div>
  )}
</Touch>

Focus

<Focus>
  {({ isFocused, bind }) => (
    <div>
      <input {...bind} placeholder="Focus me" />
      <div>You are {isFocused ? 'focusing' : 'not focusing'} input.</div>
    </div>
  )}
</Focus>

Input

<Input initial="hello world">
  {({ bind, value }) => (
    <div>
      <ControlledInput {...bind} />
      <div>You typed {value}</div>
    </div>
  )}
</Input>

Form

<Form initial={{ subject: '', message: '' }}>
  {({ input, values }) => (
    <form
      onSubmit={e => {
        e.preventDefault()
        console.log(values)
      }}
    >
      <ControlledInput placeholder="Subject" {...input('subject').bind} />
      <ControlledTextArea placeholder="Message" {...input('message').bind} />
      <Submit>Send</Submit>
    </form>
  )}
</Form>

Interval

<Interval delay={1000}>
  {({ stop, start }) => (
    <>
      <div>The time is now {new Date().toLocaleTimeString()}</div>
      <button onClick={() => stop()}>Stop interval</button>
      <button onClick={() => start()}>Start interval</button>
    </>
  )}
</Interval>

Composing Components

If you want to avoid 'render props hell' you can compose two or more components in a single one.
📚 For complete guide, see docs

import { Compose } from 'react-powerplug'

<Compose components={[Toggle, Counter]}>
  {(toggle, counter) => (/* ... */)}
</Compose>
import { compose } from 'react-powerplug'

const ToggleCounter = compose(
  <Counter initial={5} />,
  <Toggle initial={false} />
)

<ToggleCounter>
  {(toggle, counter) => (
    <ProductCard {...} />
  )}
</ToggleCounter>

Watch 'Rapid Prototyping with React PowerPlug' by Andrew Del Prete on egghead.io


Install

Node Module

yarn add react-powerplug
npm i react-powerplug

UMD

<script src="https://unpkg.com/react-powerplug/dist/react-powerplug.min.js"></script>

exposed as ReactPowerPlug

Contributors

Thanks goes to these wonderful people (emoji key):


Renato Ribeiro

💻 🎨 📖 ⚠️

Bogdan Chadkin

💻 📖 ⚠️ 🚇

Travis Arnold

💻 📖 🐛

Max Graey

💻

Mateusz Burzyński

🐛

Andy Edwards

💻

Andrea Vanini

🐛

Ivan Starkov

🐛

Sean Roberts

📖

This project follows the all-contributors specification. Contributions of any kind welcome!

Contribute

You can help improving this project sending PRs and helping with issues.
Also you can ping me at Twitter

About

🔌 Renderless Containers

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%