From 992eb209c389e8fb7bc2a01193c4684e2d8e9e79 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Tue, 25 Apr 2017 15:56:44 -0400 Subject: [PATCH] Add prompt for variable creation --- src/components/prompt/prompt.css | 71 ++++++++++++++++++++++++++++++ src/components/prompt/prompt.jsx | 74 ++++++++++++++++++++++++++++++++ src/containers/blocks.jsx | 43 +++++++++++++++---- 3 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 src/components/prompt/prompt.css create mode 100644 src/components/prompt/prompt.jsx diff --git a/src/components/prompt/prompt.css b/src/components/prompt/prompt.css new file mode 100644 index 000000000..e7a12d9d9 --- /dev/null +++ b/src/components/prompt/prompt.css @@ -0,0 +1,71 @@ +@import "../../css/colors.css"; +@import "../../css/units.css"; + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + background-color: rgba(94, 102, 125, .95); +} + +.modal-content { + width: 360px; + margin: 100px auto; + outline: none; + border: 3px solid rgb(126, 133, 151); + padding: 0; + border-radius: $space; + user-select: none; + + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #5d647a; + overflow: hidden; +} + +.body { + background: $ui-pane-gray; + padding: 1.5rem 2.25rem; +} + +.label { + font-weight: 500; + margin: 0 0 0.75rem; +} + +.input { + margin-bottom: 1.5rem; + width: 100%; + border: 1px solid rgba(0,0,0,.1); + border-radius: 5px; + padding: 0 1rem; + height: 3rem; + color: #6b6b6b; + font-size: .875rem; +} + +.button-row { + font-weight: bolder; + text-align: right; +} + +.button-row button { + padding: 0.75rem 1rem; + border-radius: 0.25rem; + background: white; + border: 1px solid $ui-pane-border; + font-weight: 600; + font-size: 0.85rem; +} + +.button-row button.ok-button { + background: $blue; + border: $blue; + color: white; +} + +.button-row button + button { + margin-left: 0.5rem; +} diff --git a/src/components/prompt/prompt.jsx b/src/components/prompt/prompt.jsx new file mode 100644 index 000000000..d2411468b --- /dev/null +++ b/src/components/prompt/prompt.jsx @@ -0,0 +1,74 @@ +const React = require('react'); +const ReactModal = require('react-modal'); +const bindAll = require('lodash.bindall'); +const Box = require('../box/box.jsx'); + +const styles = require('./prompt.css'); + +class PromptComponent extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleOk', + 'handleKeyPress' + ]); + } + handleKeyPress (event) { + if (event.key === 'Enter') this.handleOk(); + } + handleOk () { + this.props.onOk(this.input.value); + } + render () { + return ( + + + + {this.props.label} + + + (this.input = el)} + onKeyPress={this.handleKeyPress} + /> + + + + + + + + ); + } +} + +PromptComponent.propTypes = { + label: React.PropTypes.string.isRequired, + onCancel: React.PropTypes.func.isRequired, + onOk: React.PropTypes.func.isRequired, + placeholder: React.PropTypes.string +}; + +PromptComponent.defaultProps = { + placeholder: '...' +}; + +module.exports = PromptComponent; diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index 69ae0bf1d..e319c920f 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -4,7 +4,7 @@ const PropTypes = require('prop-types'); const React = require('react'); const VMScratchBlocks = require('../lib/blocks'); const VM = require('scratch-vm'); - +const Prompt = require('../components/prompt/prompt.jsx'); const BlocksComponent = require('../components/blocks/blocks.jsx'); const addFunctionListener = (object, property, callback) => { @@ -23,6 +23,8 @@ class Blocks extends React.Component { bindAll(this, [ 'attachVM', 'detachVM', + 'handlePromptCallback', + 'handlePromptClose', 'onScriptGlowOn', 'onScriptGlowOff', 'onBlockGlowOn', @@ -32,20 +34,27 @@ class Blocks extends React.Component { 'onWorkspaceMetricsChange', 'setBlocks' ]); - this.state = {workspaceMetrics: {}}; + this.state = { + workspaceMetrics: {}, + prompt: null + }; } componentDidMount () { const workspaceConfig = defaultsDeep({}, Blocks.defaultOptions, this.props.options); this.workspace = this.ScratchBlocks.inject(this.blocks, workspaceConfig); + this.ScratchBlocks.prompt = (message, defaultValue, callback) => { + this.setState({prompt: {callback, message, defaultValue}}); + }; + // @todo change this when blockly supports UI events addFunctionListener(this.workspace, 'translate', this.onWorkspaceMetricsChange); addFunctionListener(this.workspace, 'zoom', this.onWorkspaceMetricsChange); this.attachVM(); } - shouldComponentUpdate () { - return false; + shouldComponentUpdate (nextProps, nextState) { + return this.state.prompt !== nextState.prompt; } componentWillUnmount () { this.detachVM(); @@ -72,6 +81,7 @@ class Blocks extends React.Component { this.props.vm.removeListener('VISUAL_REPORT', this.onVisualReport); this.props.vm.removeListener('workspaceUpdate', this.onWorkspaceUpdate); } + onWorkspaceMetricsChange () { const target = this.props.vm.editingTarget; if (target && target.id) { @@ -124,6 +134,13 @@ class Blocks extends React.Component { setBlocks (blocks) { this.blocks = blocks; } + handlePromptCallback (data) { + this.state.prompt.callback(data); + this.handlePromptClose(); + } + handlePromptClose () { + this.setState({prompt: null}); + } render () { const { options, // eslint-disable-line no-unused-vars @@ -131,10 +148,20 @@ class Blocks extends React.Component { ...props } = this.props; return ( - +
+ + {this.state.prompt ? ( + + ) : null} +
); } }