ReactCrate
Trying a new way to compose Components
by Kye Hohenberger
HTML
<script src="https://unpkg.com/preact/dist/preact.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<div id="o"></div>
CSS
html,
body,
#app,
.full-size {
font-family: sans-serif;
width: 100%;
margin: 0;
}
.child-c.list {
list-style: none;
padding: 4px;
border: 2px solid green;
}
Babel + JSX
const {
h,
render
} = preact;
/** @jsx h */
const classnames = window.classNames
console.clear();
const el = document.getElementById('o');
const isFn = test => typeof test === 'function'
const id = Component => Component
class Crate {
constructor (hoc = id) {
this.hocFn = hoc
return this
}
map (fn) {
return new Crate(fn(this.hocFn))
}
fold (fn) {
return fn(this.hocFn)
}
compile (Component) {
return this.fold(hoc => hoc(Component))
}
hoc (fn) {
return this.map(hoc => Wrapped => fn(hoc(Wrapped)))
}
// Inspect your props at a certain point
inspect () {
return this.map(hoc => Wrapped => hoc(props => {
console.log('=== inspect ===')
console.log('props', props)
console.log('this.hocFn', this.hocFn)
console.log('===============')
return h(Wrapped, props)
}))
}
// Set prop by key
prop (key, value) {
return this.map(hoc => Wrapped => hoc(props => {
const nextProps = { ...props, [key]: isFn(value) ? value(props) : value }
return h(Wrapped, nextProps)
}))
}
// Set className prop
// accepts anything that `classnames`
// https://www.npmjs.com/package/classnames
className (value) {
return this.prop('className', props => {
return classnames(props.className, isFn(value) ? value(props) : value)
})
}
// Set style
style (s) {
return this.prop('style', props => ({
...props.style,
...(isFn(s) ? s(props) : s)
}))
}
}
function crate (...args) {
return new Crate(...args)
}
const pp = obj => JSON.stringify(obj, null, 2)
function Stateless (props) {
return (
<pre style={props.style} className={props.className}>
<details open>
<summary>Stateless Component Props</summary>
{pp(props)}
</details>
{props.children}
</pre>
)
}
const buttonCrate = crate().style({
height: '1.6em',
width: '100%',
background: 'none',
color: 'white',
fontSize: '1em',
outline:...