1.0.33 • Published 3 months ago

react-compinators v1.0.33

Weekly downloads
-
License
ISC
Repository
github
Last release
3 months ago

λ⚛ React Compinators

A tiny library of functional utilities for composing React components: compinators = Component Combinators.

Synopsis

Create three new components by partially applying the <Label> component color prop, one for each member of the COLORS union:

import {String} from 'effect'
import {unionVariants} from 'react-compinators'

const [ GreenLabel, YellowLabel, RedLabel ] = unfoldProp(
  Label,             // Component that we will wrap three times.
  'color',           // Prop that we will partially apply.
)(
  COLORS,            // Array of union members.
  String.capitalize, // Optional function will be used to compute variant
                     // displayName from its `color` prop.
) 

See the tutorial for more info.

Quick Start

> pnpm add react-compinators

You can then import any of the exported functions from the package react-compinators. For example to import the assume function in your component:

import {assume} from 'react-compinators'

Why?

React offers Far More Than One Way to compose and repurpose components. For example, you can fiddle with their props and wrap them in various ways. Whatever you do, eventually you will end up with a new component. The functions here provide a lighter alternative, via functions that React calls Higher Order Components (HOCs).

Consider a colored <Label> component with props of type:

interface LabelProps {
  text: string
  color: 'red' | 'yellow' | 'green'
}

If we find ten yellow labels in our code, we could create a new <YellowLabel> component, where the color is fixed on yellow:

const YellowLabel = ({text: string}) => (
  <Label {...{text}} color='yellow' />
)
// Using:
<YellowLabel text='Hello World!' />

Using the assumeProp combinator from this library, we have lighter alternative that avoids JSX:

import {assumeProp} from 'react-compinators'
import type {FC} from 'react'
// Note correct computed type for YellowLabel props.
const YellowLabel: FC<{text: string}> = assumeProp(Label, {color: 'yellow'})
// Using:
<YellowLabel text='Hello World!' />

The result is exactly the same. The style of HOCs you will find here is supported by React Dev Tools so the debug experience of the <YellowLabel> should similar, except it will appear under the name <Yellow(Label)>.

I have found these functions helpful in all kinds of situations:

  1. Cross-cutting concerns.
    • For example when different parts of an application require functionality such as:
      1. Authentication guards.
      2. Memoizing component props in local storage, lest they be lost on browser refresh.
      3. Logging
    • But you would rather not touch the source code of components involved.
  2. When more components but fewer props is preferable to fewer components but more props.
    • For example, when writing components for a design-system driven library, it is common to create a highly configurable component, for example a <Button>, and then derive various variants from it, for example: <PrimaryButton> or <SecondaryButton>.
      • These variants are often just different combinations of values for the props of the <Button>.
      • Functions like withVariants reduce boilerplate and clarify intent for such tasks.
    • Describing changes to components as plain old data lets you manipulate definitions as data, for example to customize a color, or to add a debug panel overlay to all children of a component.
  3. The functions here are all well-known higher-order functions, for example curry, that have been specialized for React components.
    • This helps you take pieces of components out of JSX, and into your regular functional programming pipelines. When a simple function would suffice, these combinators help your stay in a single “world”, and leave the JSX more focused on its UI concerns.
    • Just as a curry combinator for functions is useful enough to deserve its own name, so too for assumeProps when dealing with React components.

Features

A Contravariant instance for Effect and a bunch of combinators. If you squint hard you will see they are all just specializations of mapProps:

The Combinators

  1. appendChildren
  2. assumeProp
  3. assumeProps
  4. modCssVar
  5. mapProp
  6. mapProps
  7. modChildren
  8. modProp
  9. modStyle
  10. omitProps
  11. prependChildren
  12. renameProp
  13. renameProps
  14. requireProp
  15. unfoldProp
  16. withDefault
  17. withDefaultStyle
  18. withStyle
  19. withVariants

Roadmap

  1. Guards and branches
  2. Layout and children
  3. Debug and pointcuts

See Also

  1. Tutorial
  2. API Reference
  3. recompose
1.0.33

3 months ago

1.0.27

4 months ago

1.0.24

4 months ago

1.0.23

4 months ago

1.0.22

4 months ago

1.0.21

4 months ago

1.0.20

4 months ago

1.0.19

4 months ago

1.0.18

4 months ago

1.0.16

4 months ago

1.0.15

4 months ago

1.0.14

4 months ago

1.0.13

4 months ago

1.0.12

4 months ago

1.0.9

4 months ago

1.0.7

4 months ago

1.0.6

4 months ago

1.0.5

4 months ago

1.0.3

4 months ago

1.0.2

4 months ago