From cde8a78e86c372e1de71d3d4ca7dca7dd26c6d6e Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Thu, 12 Apr 2018 13:34:18 -0400 Subject: [PATCH] Hook up save and load buttons These use a technique where the save/load functionality is passed from the component to its children via a function argument. I opted for this rather than a higher order component because it is more readable and requires fewer intermediary components. This could just as easily been done with a higher order component and would be happy to change it to that instead. There is a performance implication since there is a function being defined in render. However the menu bar is not a highly re-rendered component, so I thought it would be ok in this case. --- src/components/load-button/load-button.css | 3 -- src/components/load-button/load-button.jsx | 49 ---------------------- src/components/menu-bar/menu-bar.jsx | 15 ++++++- src/containers/load-button.jsx | 26 ++++++------ src/containers/save-button.jsx | 29 ++----------- 5 files changed, 29 insertions(+), 93 deletions(-) delete mode 100644 src/components/load-button/load-button.css delete mode 100644 src/components/load-button/load-button.jsx diff --git a/src/components/load-button/load-button.css b/src/components/load-button/load-button.css deleted file mode 100644 index 527718028..000000000 --- a/src/components/load-button/load-button.css +++ /dev/null @@ -1,3 +0,0 @@ -.file-input { - display: none; -} diff --git a/src/components/load-button/load-button.jsx b/src/components/load-button/load-button.jsx deleted file mode 100644 index d437a9c02..000000000 --- a/src/components/load-button/load-button.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; - -import ButtonComponent from '../button/button.jsx'; -import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx'; - -import styles from './load-button.css'; - -const LoadButtonComponent = ({ - inputRef, - onChange, - onClick, - title, - ...props -}) => ( - - - - {title} - - - - -); - -LoadButtonComponent.propTypes = { - className: PropTypes.string, - inputRef: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onClick: PropTypes.func.isRequired, - title: PropTypes.string -}; -LoadButtonComponent.defaultProps = { - title: 'Load' -}; -export default LoadButtonComponent; diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 50c29302e..2915d7d0e 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -8,8 +8,10 @@ import Box from '../box/box.jsx'; import Button from '../button/button.jsx'; import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx'; import LanguageSelector from '../../containers/language-selector.jsx'; +import LoadButton from '../../containers/load-button.jsx'; import Menu from '../../containers/menu.jsx'; import {MenuItem} from '../menu/menu.jsx'; +import SaveButton from '../../containers/save-button.jsx'; import {openFeedbackForm} from '../../reducers/modals'; import {openFileMenu, closeFileMenu, MENU_FILE} from '../../reducers/menus'; @@ -117,8 +119,17 @@ const MenuBar = props => ( Save as a copy - Upload from your computer - Download to your computer + {(renderFileInput, loadProject) => ( + + Upload from your computer + {renderFileInput()} + + )} + {saveProject => ( + + Download to your computer + + )}
diff --git a/src/containers/load-button.jsx b/src/containers/load-button.jsx index 9364728a4..fae36861e 100644 --- a/src/containers/load-button.jsx +++ b/src/containers/load-button.jsx @@ -3,8 +3,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import {connect} from 'react-redux'; -import LoadButtonComponent from '../components/load-button/load-button.jsx'; - import { openLoadingProject, closeLoadingProject @@ -14,6 +12,7 @@ class LoadButton extends React.Component { constructor (props) { super(props); bindAll(this, [ + 'renderFileInput', 'setFileInput', 'handleChange', 'handleClick' @@ -49,26 +48,25 @@ class LoadButton extends React.Component { setFileInput (input) { this.fileInput = input; } - render () { - if (this.state.loadingError) throw new Error(`Failed to load project: ${this.state.errorMessage}`); - const { - closeLoadingState, // eslint-disable-line no-unused-vars - openLoadingState, // eslint-disable-line no-unused-vars - vm, // eslint-disable-line no-unused-vars - ...props - } = this.props; + renderFileInput () { return ( - ); } + render () { + if (this.state.loadingError) throw new Error(`Failed to load project: ${this.state.errorMessage}`); + return this.props.children(this.renderFileInput, this.handleClick); + } } LoadButton.propTypes = { + children: PropTypes.func, closeLoadingState: PropTypes.func, openLoadingState: PropTypes.func, vm: PropTypes.shape({ diff --git a/src/containers/save-button.jsx b/src/containers/save-button.jsx index fc8bcf40a..6458de5ba 100644 --- a/src/containers/save-button.jsx +++ b/src/containers/save-button.jsx @@ -3,18 +3,14 @@ import PropTypes from 'prop-types'; import React from 'react'; import {connect} from 'react-redux'; -import ButtonComponent from '../components/button/button.jsx'; -import {ComingSoonTooltip} from '../components/coming-soon/coming-soon.jsx'; - - class SaveButton extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'handleClick' + 'saveProject' ]); } - handleClick () { + saveProject () { const saveLink = document.createElement('a'); document.body.appendChild(saveLink); @@ -27,7 +23,6 @@ class SaveButton extends React.Component { // File name: project-DATE-TIME const date = new Date(); const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`; - // TODO change extension to sb3 saveLink.download = `untitled-project-${timestamp}.sb3`; saveLink.click(); window.URL.revokeObjectURL(url); @@ -35,28 +30,12 @@ class SaveButton extends React.Component { }); } render () { - const { - vm, // eslint-disable-line no-unused-vars - ...props - } = this.props; - return ( - - - Save - - - ); + return this.props.children(this.saveProject); } } SaveButton.propTypes = { + children: PropTypes.func, vm: PropTypes.shape({ saveProjectSb3: PropTypes.func })