diff --git a/package.json b/package.json index c8d81796..a3c0209c 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "react": "15.5.4", "react-dom": "15.5.4", "react-intl": "2.3.0", + "react-redux": "5.0.5", "redux": "3.6.0", "redux-throttle": "0.1.1", "rimraf": "^2.6.1", diff --git a/src/components/paint-editor.jsx b/src/components/paint-editor.jsx index 16a9c877..db93953f 100644 --- a/src/components/paint-editor.jsx +++ b/src/components/paint-editor.jsx @@ -1,13 +1,18 @@ +import PropTypes from 'prop-types'; import React from 'react'; -import PaperCanvas from './paper-canvas.jsx'; +import PaperCanvas from '../containers/paper-canvas.jsx'; -export default class PaintEditorComponent extends React.Component { - render () { - return ( - - ); - } -} +const PaintEditorComponent = props => ( + +); -PaintEditorComponent.defaultProps = { +PaintEditorComponent.propTypes = { + tool: PropTypes.shape({ + name: PropTypes.string.isRequired + }) }; + + +module.exports = PaintEditorComponent; diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx new file mode 100644 index 00000000..efe05522 --- /dev/null +++ b/src/containers/paint-editor.jsx @@ -0,0 +1,48 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import PaintEditorComponent from '../components/paint-editor.jsx'; +import tools from '../reducers/tools'; +import ToolTypes from '../tools/tool-types.js'; +import {connect} from 'react-redux'; + +class PaintEditor extends React.Component { + componentDidMount () { + const onKeyPress = this.props.onKeyPress; + document.onkeydown = function (e) { + e = e || window.event; + onKeyPress(e); + }; + } + render () { + return ( + + ); + } +} + +PaintEditor.propTypes = { + onKeyPress: PropTypes.func.isRequired, + tool: PropTypes.shape({ + name: PropTypes.string.isRequired + }) +}; + +const mapStateToProps = state => ({ + tool: state.tool +}); +const mapDispatchToProps = dispatch => ({ + onKeyPress: e => { + if (e.key === 'e') { + dispatch(tools.changeTool(ToolTypes.ERASER)); + } else if (e.key === 'b') { + dispatch(tools.changeTool(ToolTypes.BRUSH)); + } + } +}); + +module.exports = connect( + mapStateToProps, + mapDispatchToProps +)(PaintEditor); diff --git a/src/components/paper-canvas.jsx b/src/containers/paper-canvas.jsx similarity index 72% rename from src/components/paper-canvas.jsx rename to src/containers/paper-canvas.jsx index e4df4b14..5d813a0f 100644 --- a/src/components/paper-canvas.jsx +++ b/src/containers/paper-canvas.jsx @@ -1,5 +1,7 @@ +import PropTypes from 'prop-types'; import React from 'react'; import paper from 'paper'; +import ToolTypes from '../tools/tool-types.js'; class PaperCanvas extends React.Component { constructor (props) { @@ -22,6 +24,11 @@ class PaperCanvas extends React.Component { // Draw the view now: paper.view.draw(); } + componentWillReceiveProps (nextProps) { + if (nextProps.tool !== this.props.tool && nextProps.tool instanceof ToolTypes) { + // TODO switch tool + } + } componentWillUnmount () { } render () { @@ -31,6 +38,10 @@ class PaperCanvas extends React.Component { } } -PaperCanvas.propTypes = {}; +PaperCanvas.propTypes = { + tool: PropTypes.shape({ + name: PropTypes.string.isRequired + }) +}; module.exports = PaperCanvas; diff --git a/src/index.js b/src/index.js index 5df3df46..699887c5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,3 @@ -import PaintEditorComponent from './components/paint-editor.jsx'; +import PaintEditor from './containers/paint-editor.jsx'; -export {PaintEditorComponent as default}; +export {PaintEditor as default}; diff --git a/src/playground/playground.jsx b/src/playground/playground.jsx index 6efcd1cd..31ad10cf 100644 --- a/src/playground/playground.jsx +++ b/src/playground/playground.jsx @@ -1,9 +1,21 @@ import React from 'react'; import ReactDOM from 'react-dom'; import PaintEditor from '..'; +import {Provider} from 'react-redux'; +import {createStore, applyMiddleware} from 'redux'; +import throttle from 'redux-throttle'; +import reducer from '../reducers/combine-reducers'; const appTarget = document.createElement('div'); document.body.appendChild(appTarget); -ReactDOM.render( - , - appTarget); +const store = applyMiddleware( + throttle(300, {leading: true, trailing: true}) +)(createStore)( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() +); +ReactDOM.render(( + + + +), appTarget); diff --git a/src/reducers/combine-reducers.js b/src/reducers/combine-reducers.js new file mode 100644 index 00000000..a533b763 --- /dev/null +++ b/src/reducers/combine-reducers.js @@ -0,0 +1,5 @@ +import {combineReducers} from 'redux'; + +module.exports = combineReducers({ + tool: require('./tools') +}); diff --git a/src/reducers/tools.js b/src/reducers/tools.js new file mode 100644 index 00000000..5a09586e --- /dev/null +++ b/src/reducers/tools.js @@ -0,0 +1,32 @@ +import ToolTypes from '../tools/tool-types.js'; + +const CHANGE_TOOL = 'scratch-paint/tools/CHANGE_TOOL'; +const initialState = ToolTypes.BRUSH; + +const reducer = function (state, action) { + if (typeof state === 'undefined') state = initialState; + switch (action.type) { + case CHANGE_TOOL: + if (action.tool instanceof ToolTypes) { + return action.tool; + } + // TODO switch to minilog + console.warn('Warning: Tool type does not exist: ${action.tool}'); + /* falls through */ + default: + return state; + } +}; + +// Action creators ================================== +reducer.changeTool = function (tool) { + return { + type: CHANGE_TOOL, + tool: tool, + meta: { + throttle: 30 + } + }; +}; + +module.exports = reducer; diff --git a/src/tools/tool-types.js b/src/tools/tool-types.js new file mode 100644 index 00000000..12c8b0f4 --- /dev/null +++ b/src/tools/tool-types.js @@ -0,0 +1,12 @@ +class ToolTypes { + constructor (name) { + this.name = name; + } + toString () { + return `ToolTypes.${this.name}`; + } +} +ToolTypes.BRUSH = new ToolTypes('BRUSH'); +ToolTypes.ERASER = new ToolTypes('ERASER'); + +module.exports = ToolTypes;