UNPKG

react-motherboard

Version:

A simple flux-like concept react component container framework.

168 lines (144 loc) 4.01 kB
var React = require('react'); var Motherboard = function(options) { this.layout = null; this.chipInstances = []; // [{name: '', instance: null}] this.ACTIONS = options.ACTIONS || {}; this.SLOTS = options.SLOTS || {}; this.callbacks = {}; console.log('new Motherboard', this.ACTIONS, this.SLOTS); }; Motherboard.prototype.register = function(actionType, cb) { if(this.callbacks[actionType]) this.callbacks[actionType].push(cb); else this.callbacks[actionType] = [cb]; }; Motherboard.prototype.emit = function(action) { this.callbacks[action.type].forEach(function(cb) { cb(action.payload); }); }; Motherboard.prototype.addLayout = function(layout /* ReactClass */) { console.log('MB.addLayout', layout); // inject motherboard reference to layout layout.prototype.MB = this; var didMountFunc = layout.prototype.componentDidMount, that = this; layout.prototype.componentDidMount = function() { var layout_this = this; didMountFunc(); that.chipInstances.forEach(function(instance) { var name = instance.name; React.render(instance.instance, layout_this.refs[name].getDOMNode()); }); }; this.layout = layout; }; Motherboard.prototype.addChip = function(name /* slot name */, chip /* ReactElement */) { console.log('MB.addChip', name, chip); if(this.SLOTS[name]) { // inject motherboard reference to chip instance var reactType = chip.type; reactType.prototype.MB = this; this.chipInstances.push({name: name, instance: chip}); } else { console.err('MB', 'can not find the slot: ' + name); } }; Motherboard.prototype.run = function(mountNode) { console.log('MB.run'); React.render(React.createElement(this.layout), mountNode); }; // test code Motherboard.test = function() { console.log('running test'); var mb = new Motherboard({ ACTIONS: {CLICK: 'CLICK', STOREUPDATE: 'STOREUPDATE'}, SLOTS: {SIDEBAR: 'SIDEBAR', CONTENT: 'CONTENT', STORE: 'STORE'}, }); var Sidebar = React.createClass({ handleClick: function(e) { console.log('Sidebar handleClick', this.MB.ACTIONS.CLICK); this.MB.emit({type: this.MB.ACTIONS.CLICK, payload: 'hello'}); }, render: function() { return ( <div> <button onClick={this.handleClick}>{this.props.value}</button> </div> ); } }); var Content = React.createClass({ getInitialState: function() { return { content: 'placeholder' }; }, componentDidMount: function() { this.MB.register(this.MB.ACTIONS.CLICK, function(payload) { console.log('i got it!!! ' + payload); }); var that = this; this.MB.register(this.MB.ACTIONS.STOREUPDATE, function(payload) { that.setState({content: payload}); }); }, render: function() { return ( <div> <p>{this.state.content}</p> </div> ); } }); var Store = React.createClass({ getInitialState: function() { return { store: ' ' }; }, componentDidMount: function() { var that = this; this.MB.register(this.MB.ACTIONS.CLICK, function(payload) { that.setState({store: that.state.store + ',' + payload}); that.MB.emit({type: that.MB.ACTIONS.STOREUPDATE, payload: that.state.store}); }); }, render: function() { return ( <div></div> ); } }); mb.addLayout(React.createClass({ componentDidMount: function() { console.log('layout existing componentDidMount'); }, render: function() { var style = { border: '1px solid black', padding: '5px' }, layoutStyle = { display: 'flex', flexDirection: 'row' }; return ( <div> <h4>motherboard layout</h4> <div style={layoutStyle}> <div style={style} ref={mb.SLOTS.SIDEBAR}></div> <div style={style} ref={mb.SLOTS.CONTENT}></div> <div ref={mb.SLOTS.STORE}></div> </div> </div> ); } })); mb.addChip(mb.SLOTS.SIDEBAR, <Sidebar value='new button 2' />); mb.addChip(mb.SLOTS.CONTENT, <Content />); mb.addChip(mb.SLOTS.STORE, <Store />); mb.run(mountNode); } module.exports = Motherboard;