0.3.0 • Published 1 year ago

react-cascade-component v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

React-Cascade-Component

Introducing CSS cascading to React components with first-class Typescript support right out of the box.

DRY out your code. Repeat yourself less with less hassle.

Installation

npmyarn
npm install react-cascade-componentyarn add react-cascade-component

Example Use Case

import Cascade from 'react-cascade-component';

const App = () => {
  const onClickHandler: React.MouseEventHandler<HTMLButtonElement> = (e) => {
    alert(`Button ${e.currentTarget.id} was clicked!`);
  };

  return (
    <Cascade cascadeTo="button" cascadeProps={{ onClick: onClickHandler }}>
      <div />
      <div />
      <button id="1" />
      <button id="2" />
      <button id="3" />
    </Cascade>
  );
};

Cascade by default is a div element but can be of any JSX.IntrinsicElement by setting the as prop value or using Cascade.[JSX.IntrinsicElement] .

<Cascade as="span">{/* ... */}</Cascade>
<Cascade.span>{/* ... */}</Cascade.span>

API

Demos

CascadeTo Callback

The <Cascade> component has a callback parameter on cascadeTo which means you can specify handling, by default the callback is (callbackProps, originalProps) => {...callbackProps, ...originalProps}, ie. a shallow merge.

<Cascade
  cascadeTo={[
    ['button', (c, o) => ({ ...c.buttonProps, ...o })],
    [MyCustomComponent, (c, o) => ({ ...c.customProps, ...o })],
  ]}
  cascadeProps={{
    buttonProps: {
      onClick: onClickHandler,
    },
    customProps: {
      className: 'foobar'
    }
  }}
>
  <button />
  <div />
  <MyCustomComponent />
</Cascade>

You can also specify a function instead:

<Cascade
  cascadeTo={(t, c, o) => {
    if (t === 'button') {
      return {...c.buttonProps, ...o}
    }
    if (t === MyCustomComponent) {
      return {...c.customProps, ...o}
    }
  }}
  cascadeProps={{
    buttonProps: {
      onClick: onClickHandler,
    },
    customProps: {
      className: 'foobar'
    }
  }}
>
  <button />
  <div />
  <MyCustomComponent />
</Cascade>

Nested Cascades

The <Cascade> component can pass through to each other. By default it will both absorb and pass properties. Nested <Cascade> components will cascadeTo the same constrained types. <Cascade absorbProps={false} /> will disable absorbing props but will still pass through through properties.

<Cascade className="foo" cascadeProps={{ className: 'bar' }}>
  <Cascade 
    className="bang" 
    cascadeTo={[Cascade, 'span']}
  >
    <Cascade.span>                {/* Cascade.span !== 'span' */}         
      <div />
      <div />
      <span />                    
      <label />
    </Cascade.span>
    <Cascade 
      cascadeTo={null}
    >                     
      <span />                    {/* className="bar" */}
      <label />                   {/* className="bar" */}
    </Cascade>
    <Cascade>                     {/* className="bar" */}
      <span />                    {/* className="bar" */}
      <label />                   
    </Cascade>
    <Cascade                      /* className=undefined */
      absorbProps={false}
      cascadeTo="label"
    > 
      <span />                    
      <label />                   {/* className="bar" */}
    </Cascade>
    <div>
      <span />
      <label />
    </div>
  </Cascade>
</Cascade>;

View the test cases for more example usages

Alternatives

If you are simply using react-cascade-component as a means to transfer props deeply in your component, instead consider using React's built-in useContext .

Contribute

Contributions are welcome!

License

Licensed under the MIT License, Copyright © 2023-present Cody Duong.

See LICENSE for more information.