From cba7ab98395ae292e0a5561e60c9c9e79451915a Mon Sep 17 00:00:00 2001 From: andrewcapodieci Date: Thu, 25 May 2017 16:17:29 -0400 Subject: [PATCH] initial commit of files --- .babelrc | 3 ++ package.json | 46 ++++++++++++++++++ src/ActionCreators.js | 18 +++++++ src/components/DecrementButton.jsx | 16 ++++++ src/components/GoldenLayoutWrapper.jsx | 67 ++++++++++++++++++++++++++ src/components/IncrementButton.jsx | 20 ++++++++ src/components/TestComponent.jsx | 24 +++++++++ src/core.js | 11 +++++ src/index.html | 18 +++++++ src/index.jsx | 15 ++++++ src/reducer.js | 21 ++++++++ webpack.config.babel.js | 44 +++++++++++++++++ 12 files changed, 303 insertions(+) create mode 100644 .babelrc create mode 100644 package.json create mode 100644 src/ActionCreators.js create mode 100644 src/components/DecrementButton.jsx create mode 100644 src/components/GoldenLayoutWrapper.jsx create mode 100644 src/components/IncrementButton.jsx create mode 100644 src/components/TestComponent.jsx create mode 100644 src/core.js create mode 100644 src/index.html create mode 100644 src/index.jsx create mode 100644 src/reducer.js create mode 100644 webpack.config.babel.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..3731e22 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [ "es2015", "react" ], +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dec19e1 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "golden-layout-react-redux", + "version": "1.0.0", + "description": "example showing how to use react-redux with golden-layout", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack", + "dev": "webpack-dev-server" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/andrewcapodieci/golden-layout-react-redux.git" + }, + "keywords": [ + "react", + "redux", + "react-redux", + "golden-layout" + ], + "author": "Andrew Capodieci ", + "license": "UNLICENSED", + "bugs": { + "url": "https://github.com/andrewcapodieci/golden-layout-react-redux/issues" + }, + "homepage": "https://github.com/andrewcapodieci/golden-layout-react-redux#readme", + "dependencies": { + "babel": "^6.23.0", + "babel-cli": "^6.24.1", + "babel-core": "^6.24.1", + "babel-loader": "^7.0.0", + "babel-preset-env": "^1.5.1", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "golden-layout": "^1.5.8", + "html-webpack-plugin": "^2.28.0", + "immutable": "^3.8.1", + "prop-types": "^15.5.10", + "react": "^15.5.4", + "react-dom": "^15.5.4", + "react-redux": "^5.0.5", + "redux": "^3.6.0", + "webpack": "^2.6.1", + "webpack-dev-server": "^2.4.5" + } +} diff --git a/src/ActionCreators.js b/src/ActionCreators.js new file mode 100644 index 0000000..919b311 --- /dev/null +++ b/src/ActionCreators.js @@ -0,0 +1,18 @@ +export function setState(state) { + return { + type: 'SET_STATE', + state + }; +} + +export function incrementCount() { + return { + type: 'INCREMENT_COUNT' + }; +} + +export function decrementCount() { + return { + type: 'DECREMENT_COUNT' + }; +} diff --git a/src/components/DecrementButton.jsx b/src/components/DecrementButton.jsx new file mode 100644 index 0000000..d7df949 --- /dev/null +++ b/src/components/DecrementButton.jsx @@ -0,0 +1,16 @@ +// Pure react component. Should not be connected to redux store; its container +// should be connected to the store. +import {decrementCount} from '../ActionCreators'; +import {connect} from 'react-redux'; + +class DecrementButton extends React.Component { + render() { + return ( + + ); + } +} + +export const DecrementButtonContainer = connect( + decrementCount +)(DecrementButton); diff --git a/src/components/GoldenLayoutWrapper.jsx b/src/components/GoldenLayoutWrapper.jsx new file mode 100644 index 0000000..a47269c --- /dev/null +++ b/src/components/GoldenLayoutWrapper.jsx @@ -0,0 +1,67 @@ +import GoldenLayout from 'golden-layout'; +import {Provider} from 'react-redux'; +import {IncrementButtonContainer} from './IncrementButton'; +import {DecrementButtonContainer} from './DecrementButton'; +import {TestComponentContainer} from './TestComponent'; + +class GoldenLayoutWrapper extends React.Component { + componentDidMount() { + // Build basic golden-layout config + const config = { + content: [{ + type: 'row', + content: [{ + type: 'react-component', + component: 'TestComponentContainer' + },{ + type: 'react-component', + component: 'IncrementButtonContainer' + },{ + type: 'react-component', + component: 'DecrementButtonContainer' + }] + }] + }; + + function wrapComponent(component, store) { + class Wrapped extends React.Component { + render() { + return ( + + + + ); + } + } + return Wrapped; + }; + + var layout = new GoldenLayout(config, '#goldenLayout'); + layout.registerComponent('IncrementButtonContainer', + wrapComponent(IncrementButtonContainer, this.context.store) + ); + layout.registerComponent('DecrementButtonContainer', + wrapComponent(DecrementButtonContainer, this.context.store) + ); + layout.registerComponent('TestComponentContainer', + wrapComponent(TestComponentContainer, this.context.store) + ); + layout.init(); + } + + render() { + return ( +
+ ); + } +} + +// ContextTypes must be defined in order to pass the redux store to exist in +// "this.context". The redux store is given to GoldenLayoutWrapper from its +// surrounding in index.jsx. +GoldenLayoutWrapper.contextTypes = { + store: React.PropTypes.object.isRequired +}; + + +export default GoldenLayoutWrapper; diff --git a/src/components/IncrementButton.jsx b/src/components/IncrementButton.jsx new file mode 100644 index 0000000..11a0b3e --- /dev/null +++ b/src/components/IncrementButton.jsx @@ -0,0 +1,20 @@ +import {incrementCount} from '../ActionCreators'; +import {connect} from 'react-redux'; + +// Pure react component. Should not be connected to redux store; its container +// should be connected to the store. +class IncrementButton extends React.Component { + render() { + return ( + + ); + } +} + +function mapDispatchToProps(dispatch) { + decrementCount: dispatch(decrementCount()) +} + +export const IncrementButtonContainer = connect( + incrementCount +)(IncrementButton); diff --git a/src/components/TestComponent.jsx b/src/components/TestComponent.jsx new file mode 100644 index 0000000..aea1297 --- /dev/null +++ b/src/components/TestComponent.jsx @@ -0,0 +1,24 @@ +import PropTypes from 'prop-types'; +import {connect} from 'react-redux'; + +// Pure react component. Should not be connected to redux store; its container +// should be connected to the store. +export class TestComponent extends React.Component { + render() { + return ( +

{this.props.label}

+ ); + } +} + +TestComponent.PropTypes = { + label: PropTypes.number.isRequired +} + +function mapStateToProps(state) { + return { + label: state.get('count') + } +} + +export const TestComponentContainer = connect(mapStateToProps)(TestComponent); diff --git a/src/core.js b/src/core.js new file mode 100644 index 0000000..76edac8 --- /dev/null +++ b/src/core.js @@ -0,0 +1,11 @@ +import {Map} from 'immutable'; + +export function incrementCount(state) +{ + return state.update('count', count => count+1); +} + +export function decrementCount(state) +{ + return state.update('count', count => count-1); +} diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..09d7248 --- /dev/null +++ b/src/index.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + React-Redux with GoldenLayout + + +
+ + + diff --git a/src/index.jsx b/src/index.jsx new file mode 100644 index 0000000..53a855f --- /dev/null +++ b/src/index.jsx @@ -0,0 +1,15 @@ +import GoldenLayoutWrapper from './components/GoldenLayoutWrapper'; +import {createStore} from 'redux'; +import {Provider} from 'react-redux'; +import reducer from './reducer'; +import {setState} from './ActionCreators'; + +const store = createStore(reducer); +store.dispatch(setState({ 'count': 0 })); + +ReactDOM.render( + + + , + document.getElementById('root') +); diff --git a/src/reducer.js b/src/reducer.js new file mode 100644 index 0000000..957c614 --- /dev/null +++ b/src/reducer.js @@ -0,0 +1,21 @@ +import {Map} from 'immutable'; +import { + incrementCount, + decrementCount +} from './core'; + +function setState(state, newState) { + return state.merge(newState); +} + +export default function(state = Map(), action) { + switch(action.type) { + case 'SET_STATE': + return setState(state, action.state); + case 'INCREMENT_COUNT': + return incrementCount(state); + case 'DECREMENT_COUNT': + return decrementCount(state); + } + return state; +} diff --git a/webpack.config.babel.js b/webpack.config.babel.js new file mode 100644 index 0000000..cc1c63b --- /dev/null +++ b/webpack.config.babel.js @@ -0,0 +1,44 @@ +import path from 'path'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; + +export default () => ({ + entry: [ + 'webpack-dev-server/client?http://localhost:8080', // webpack dev server host and port + path.join(__dirname, 'src/index.jsx'), // entry point of app + ], + output: { + path: path.join(__dirname + '/dist'), + filename: 'bundle.js', + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: 'index.html', + template: './src/index.html' + }) + ], + module: { + rules: [{ + test: /\.jsx?$/, + exclude: /node_modules/, + include: path.join(__dirname, 'src'), + use: [{ + loader: 'babel-loader', + options: { + babelrc: false, // Tells webpack not to use the .babelrc file + presets: [ + ['babel-preset-env', { + "targets": { "firefox": 52, "chrome": 55 }, + "modules": false, + "loose": true + }], + 'react' // Transform JSX into React.createElement calls + ] + } + }] + }] + }, + resolve: { + extensions: ['.js', '.jsx'] + }, + devtool: 'source-map' +});