Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a compose export #3

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
109 changes: 92 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const myView = () =>
- [Dynamic Selectors](#dynamic-selectors)
- [Argument Transformation](#argument-transformation)
- [Point-free](#point-free)
- [Example Refactoring](#example-refactoring)
- [Working with older versions](#working-with-older-versions)
- [Contributions](#contributions)
- [License](#license)
Expand Down Expand Up @@ -303,32 +304,106 @@ If you rather all your arguments to just be interpreted as they are, you can dis

## Point-free

Think point-free composition in your render function is a `pipe` dream? Think again, you can use `njsx` to compose components in a point-free style to help with the readability of deeply nested react components:
Think point-free composition in your render is a `pipe` dream? Think again! You can use `njsx` to compose components in a point-free style to increase the readability of deeply nested components:

```jsx
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
</PersistGate>
</Provider>
const Root = ({ store }) => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Router history={history}>
<Route path='/' component={App} />
</Router>
</PersistGate>
</Provider>
)
```

Becomes:

```js
import { compose } from 'rambda'

compose(
Provider({ store }),
PersistGate({ loading: null, persistor }),
BrowserRouter,
Route
)({ path: '/', component: App })()
import { nest } from 'njsx'

const Root = ({ store }) =>
nest(
Provider({ store }),
PersistGate({ loading: null, persistor }),
Router({ history }),
Route({ path: '/', component: App })
)()
```

## Example Refactoring
JSX:
```jsx
export const Loading = () => (
<Row style={{marginTop: '10em'}}>
<Col sm={7} style={{float: 'none', margin: 'auto'}}>
<Well bsSize='lg' style={{paddingTop: '0px'}}>
<Row style={{marginTop: 0, marginBottom: 10}}>
<Col sm={12}>
<h2>Welcome back!</h2>
</Col>
</Row>

<Row>
<Col sm={12}>
<p>Please hang tight while we load your app.</p>
</Col>
</Row>

<Row>
<Col sm={12}>
<div className='pull-right'>
<Spinner style={{top: 16, width: 42}} />
</div>
</Col>
</Row>
</Well>
</Col>
</Row>
)
```
NJSX nested:
```js
export const Loading = () =>
Row ({style: {marginTop: '10em'}}) (
Col ({sm: 7, style: {float: 'none', margin: 'auto'}}) (
Well ({bsSize: 'lg', style: {paddingTop: '0px'}}) (
Row ({style: {marginTop: 0, marginBottom: 10}}) (
Col ({sm: 12}) (h2 ('Welcome back!'))
),
Row (Col ({sm: 12}) (p ('Please hang tight while we load your app.'))),
Row (
Col ({sm: 12}) (
div ({className: 'pull-right'}) (Spinner ({style: {top: 16, width: 42}}))
)
)
)
)
) ()
```
NJSX composed:
```js
export const Loading = () =>
nest (
Row ({style: {marginTop: '10em'}}),
Col ({sm: 7, style: {float: 'none', margin: 'auto'}}),
Well ({bsSize: 'lg', style: {paddingTop: '0px'}}) (
nest (
Row ({style: {marginTop: 0, marginBottom: 10}}),
Col ({sm: 12}),
h2 ('Welcome back!')
),
nest (Row, Col ({sm: 12}), p ('Please hang tight while we load your app.')),
nest (
Row,
Col ({sm: 12}),
div ({className: 'pull-right'}) (Spinner ({style: {top: 16, width: 42}}))
)
)
) ()

Please note that `compose` and `pipe` functions vary in implementation and not all will work with `njsx`, for example, `lodash/fp` seems to have issues at the moment, while `rambda` is working without issue.
```

## Working with older versions

Expand Down
29 changes: 22 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { createElement, ReactChild, ReactElement, ReactNode, ReactType } from 'r
const { assign } = Object
const { isArray } = Array

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════
// CONFIGURATION
// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════

export type ArgumentTransformation = (arg: any) => any

Expand All @@ -21,9 +21,9 @@ export const NJSXConfig: {
},
}

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════
// BUILDERS
// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════

export interface Builder<P> {
(): ReactElement<P>,
Expand All @@ -47,9 +47,9 @@ export type BuilderState<P> = Partial<P & { children: ReactNode[] }>

export type BuilderRefinement<P> = (state: BuilderState<P>) => BuilderState<P>

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════
// FACADE
// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════

export type NJSX = <P>(type: ReactType<P>) => Builder<P>
const njsx = <P>(type: ReactType<P>, baseState: BuilderState<P> = {}): Builder<P> => {
Expand Down Expand Up @@ -98,4 +98,19 @@ function addChild<P>(state: BuilderState<P>, child: ReactNode) {
return assign({}, state, { children: [...state.children || [], child] })
}

export default njsx as NJSX
// ══════════════════════════════════════════════════════════════════════════════════════
// Compose (nest)
// ══════════════════════════════════════════════════════════════════════════════════════

type nest = <A>(x: Builder<A>, ...xs: Builder<any>[]) => Builder<A>

export const nest: nest = <A>(...xs: Builder<any | A>[]): Builder<A> =>
xs
.slice(0, -1)
.reverse()
.reduce(
<A>(r: Builder<any>, y: Builder<any | A>): Builder<any | A> => y(r),
xs.slice(-1)[0]
)

export default njsx as NJSX