sonhanguyen
10/17/2015 - 3:58 AM

esnextb.in

esnextb.in

import React, { PropTypes as t } from 'react'

var inject = (selector = pass => pass ) =>
  connect(
    ({ pass  }) => selector(pass),
    { pass: t.object }
  )

var Context = Object.assign(
	({ children, ...props }, { pass = {} }) =>
	  <Provider
	      pass={{ ...pass, ...props }}
	      contextTypes={{ pass: t.object }}>
	    <children.type {...props} {...children.props} />
	  </Provider>
	, { pass: t.object }
)

import { observable } from 'mobservable'
var model = Object.assign(observable([]), {
  add(item) {
    this.push(item)
  }
})

var View = ({ store }) =>
  <div>
    { store.map(item =>
      <div>{ item }</div>
    )}
    <button onClick={e =>
      store.add(Math.random())
    }>ADD</button>
  </div>

import { observer } from 'mobservable-react'
View = 
  inject()(observer (View)
)

export default props => 
  <Context store={ model }>
    <View/>
  </Context>

// my DI library
function Provider ({ contextTypes, children, ...context }) {
  var Container = React.createClass({
    childContextTypes: contextTypes,
    getChildContext() { return context },
    render() { return this.props.children } // expect single child
  })
  
  return <Container>{ children }</Container>
}

function connect(selector, contextTypes) {
  if(typeof selector != 'function') {
    contextTypes = selector
    return connect(context => context, contextTypes)
  }
  return Component => Object.assign(
    (props, context) => // props supersede context, easier to test
      <Component { ...selector(context) } { ...props }/>
    , { contextTypes }
  )
}