react-cascade-component v0.3.0
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
npm | yarn |
---|---|
npm install react-cascade-component | yarn 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.