├── .gitignore
├── LICENSE
├── README.md
├── app
└── main.js
├── build
└── index.html
├── index.js
├── package.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Christian Alfoni
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cerebral-react-baobab
2 | A Cerebral package with React and Baobab
3 |
4 | ## DEPRECATED
5 |
6 | Please head over to [Cerebral website](http://www.cerebraljs.com)
7 |
--------------------------------------------------------------------------------
/app/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Controller from 'controller';
3 |
4 | const Decorator = Controller.Decorator;
5 |
6 | const controller = Controller({
7 | list: ['foo'],
8 | $list2: {
9 | cursors: {
10 | list: ['list']
11 | },
12 | get({list}) {
13 | return list.map((item) => item + ' hihihi');
14 | }
15 | },
16 | foo: 'bar'
17 | });
18 |
19 | controller.signal('test', function AddBar (args, state) {
20 | state.push('list', 'bar');
21 | });
22 |
23 | @Decorator({
24 | foo: ['foo']
25 | })
26 | class App extends React.Component {
27 | render() {
28 | console.log('Rendering app');
29 | return (
30 |
31 |
Hello world!
32 | this.props.signals.test()}>Add to list
33 |
34 |
35 | );
36 | }
37 | }
38 |
39 | @Decorator({
40 | list: ['list'],
41 | list2: ['$list2']
42 | })
43 | class List extends React.Component {
44 | render() {
45 | return {this.props.list2.map((item, i) => {item} )} ;
46 | }
47 | }
48 |
49 | React.render(controller.injectInto(App), document.body);
50 |
--------------------------------------------------------------------------------
/build/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var cerebral = require('cerebral');
2 | var React = require('react');
3 | var Baobab = require('baobab');
4 | var EventEmitter = require('events').EventEmitter;
5 |
6 | var Value = cerebral.Value;
7 | var updateTree = function (tree, state, path) {
8 | Object.keys(state).forEach(function (key) {
9 | if (key[0] === '$') {
10 | return;
11 | }
12 | path.push(key);
13 | if (!Array.isArray(state[key]) && typeof state[key] === 'object' && state[key] !== null) {
14 | updateTree(tree, state[key], path)
15 | } else {
16 | tree.set(path, state[key])
17 | }
18 | path.pop();
19 | });
20 | };
21 |
22 | var Factory = function (initialState, defaultArgs, options) {
23 |
24 | options = options || {};
25 | options.syncwrite = true;
26 |
27 | var eventEmitter = new EventEmitter();
28 | var tree = new Baobab(initialState, options);
29 | initialState = tree.get();
30 |
31 | var controller = cerebral.Controller({
32 | defaultArgs: defaultArgs,
33 | onReset: function () {
34 | updateTree(tree, initialState, [])
35 | },
36 | onGetRecordingState: function () {
37 |
38 | },
39 | onSeek: function (seek, isPlaying, currentRecording) {
40 |
41 | },
42 | onUpdate: function () {
43 | eventEmitter.emit('change', tree.get());
44 | },
45 | onRemember: function () {
46 | eventEmitter.emit('remember', tree.get());
47 | },
48 | onGet: function (path) {
49 | return tree.get(path);
50 | },
51 | onSet: function (path, value) {
52 | tree.set(path, value);
53 | },
54 | onUnset: function (path, key) {
55 | tree.unset(path.concat(key));
56 | },
57 | onPush: function (path, value) {
58 | tree.push(path, value);
59 | },
60 | onSplice: function () {
61 | tree.splice.apply(tree, arguments);
62 | },
63 | onMerge: function (path, value) {
64 | tree.merge(path, value);
65 | },
66 | onConcat: function (path, value) {
67 | tree.apply(path, function (existingValue) {
68 | return existingValue.concat(value);
69 | });
70 | },
71 | onPop: function (path) {
72 | tree.apply(path, function (existingValue) {
73 | existingValue.pop();
74 | return existingValue;
75 | });
76 | },
77 | onShift: function (path) {
78 | tree.apply(path, function (existingValue) {
79 | existingValue.shift();
80 | return existingValue;
81 | });
82 | },
83 | onUnshift: function (path, value) {
84 | tree.unshift(path, value);
85 | }
86 | });
87 |
88 | controller.injectInto = function (AppComponent) {
89 | return React.createElement(React.createClass({
90 | displayName: 'CerebralContainer',
91 | childContextTypes: {
92 | controller: React.PropTypes.object.isRequired
93 | },
94 | getChildContext: function () {
95 | return {
96 | controller: controller
97 | }
98 | },
99 | render: function () {
100 | return React.createElement(AppComponent);
101 | }
102 | }));
103 | };
104 |
105 | controller.eventEmitter = eventEmitter;
106 |
107 | return controller;
108 |
109 | };
110 |
111 | Factory.Mixin = {
112 | contextTypes: {
113 | controller: React.PropTypes.object
114 | },
115 | componentWillMount: function () {
116 | this.signals = this.context.controller.signals;
117 | this.recorder = this.context.controller.recorder;
118 | this.get = this.context.controller.get;
119 | this.context.controller.eventEmitter.on('change', this._update);
120 | this.context.controller.eventEmitter.on('remember', this._update);
121 | this._update(this.context.controller.get([]));
122 | },
123 | componentWillUnmount: function () {
124 | this._isUmounting = true;
125 | this.context.controller.eventEmitter.removeListener('change', this._update);
126 | this.context.controller.eventEmitter.removeListener('remember', this._update);
127 | },
128 | shouldComponentUpdate: function (nextProps, nextState) {
129 | var propKeys = Object.keys(nextProps);
130 | var stateKeys = Object.keys(nextState);
131 |
132 | // props
133 | for (var x = 0; x < propKeys.length; x++) {
134 | var key = propKeys[x];
135 | if (this.props[key] !== nextProps[key]) {
136 | return true;
137 | }
138 | }
139 |
140 | // State
141 | for (var x = 0; x < stateKeys.length; x++) {
142 | var key = stateKeys[x];
143 | if (this.state[key] !== nextState[key]) {
144 | return true;
145 | }
146 | }
147 |
148 | return false;
149 | },
150 | _update: function (state) {
151 | if (this._isUmounting || !this.getStatePaths) {
152 | return;
153 | }
154 | var statePaths = this.getStatePaths();
155 | var newState = Object.keys(statePaths).reduce(function (newState, key) {
156 | newState[key] = Value(statePaths[key], state);
157 | return newState;
158 | }, {});
159 | this.setState(newState);
160 | }
161 | };
162 |
163 | var Render = function (Component) {
164 | return function () {
165 | var state = this.state || {};
166 | var props = this.props || {};
167 |
168 | var propsToPass = Object.keys(state).reduce(function (props, key) {
169 | props[key] = state[key];
170 | return props;
171 | }, {});
172 |
173 | propsToPass = Object.keys(props).reduce(function (propsToPass, key) {
174 | propsToPass[key] = props[key];
175 | return propsToPass;
176 | }, propsToPass);
177 |
178 | propsToPass.signals = this.signals;
179 | propsToPass.recorder = this.recorder;
180 | propsToPass.get = this.get;
181 |
182 | return React.createElement(Component, propsToPass);
183 | };
184 | };
185 |
186 | Factory.Decorator = function (paths) {
187 | return function (Component) {
188 | return React.createClass({
189 | displayName: Component.name + 'Container',
190 | mixins: [Factory.Mixin],
191 | getStatePaths: function () {
192 | return paths || {};
193 | },
194 | render: Render(Component)
195 | });
196 | };
197 | };
198 |
199 | Factory.HOC = function (Component, paths) {
200 | return React.createClass({
201 | displayName: Component.name + 'Container',
202 | mixins: [Factory.Mixin],
203 | getStatePaths: function () {
204 | return paths || {};
205 | },
206 | render: Render(Component)
207 | });
208 | };
209 |
210 |
211 | module.exports = Factory;
212 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cerebral-react-baobab",
3 | "version": "0.4.0",
4 | "description": "A Cerebral package for React and Baobab",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack-dev-server --devtool eval --progress --colors --content-base build",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/christianalfoni/cerebral-react-baobab.git"
13 | },
14 | "keywords": [
15 | "react",
16 | "immutable",
17 | "cerebral"
18 | ],
19 | "author": "Christian Alfoni",
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/christianalfoni/cerebral-react-baobab/issues"
23 | },
24 | "homepage": "https://github.com/christianalfoni/cerebral-react-baobab",
25 | "peerDependencies": {
26 | "react": "^0.13.3",
27 | "baobab": "^2.0.0-dev13"
28 | },
29 | "dependencies": {
30 | "cerebral": "^0.15.0"
31 | },
32 | "devDependencies": {
33 | "babel-core": "^5.8.20",
34 | "babel-loader": "^5.3.2",
35 | "node-libs-browser": "^0.5.2",
36 | "webpack": "^1.10.1",
37 | "webpack-dev-server": "^1.10.1"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var node_modules = path.resolve(__dirname, 'node_modules');
3 |
4 | var config = {
5 | entry: path.resolve(__dirname, 'app/main.js'),
6 | devtool: 'eval-source-map',
7 | output: {
8 | filename: 'bundle.js'
9 | },
10 | resolve: {
11 | alias: {
12 | 'controller': path.resolve(__dirname, 'index.js')
13 | }
14 | },
15 | module: {
16 | loaders: [{
17 | test: /\.css$/,
18 | loader: 'style!css'
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel?optional=es7.decorators',
22 | exclude: node_modules
23 | }]
24 | }
25 | };
26 |
27 | module.exports = config;
28 |
--------------------------------------------------------------------------------