Merge pull request #871 from paulkaplan/ask-answer-events

Wire up ask/answer components to the stage
This commit is contained in:
Paul Kaplan authored and GitHub committed 2017-11-13 08:57:45 -05:00
commit cd6de7f005
6 files changed
+181 -6

No files matched your search

+57
View File
@@ -0,0 +1,57 @@
@import "../../css/units.css";
@import "../../css/colors.css";
.question-wrapper {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.question-container {
margin: $space;
border: 1px solid $form-border;
border-radius: $space;
border-width: 2px;
padding: 1rem;
background: white;
}
.question-label {
font-size: 0.75rem;
font-weight: bold;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: $text-primary;
padding-bottom: $space;
}
.question-input {
display: flex; /* Keeps the input from going outside this container */
position: relative;
}
.question-submit-button {
position: absolute;
top: calc($space / 2);
right: calc($space / 2);
width: calc(2rem - $space);
height: calc(2rem - $space);
border: none;
border-radius: 100%;
color: white;
background: $motion-primary;
}
/* Input overrides: width, font-weight, focus outline and padding */
.question-input > input {
width: 100%;
padding: 0 2rem 0 0.75rem; /* To make room for the submit button */
font-weight: normal;
}
.question-input > input:focus {
box-shadow: 0px 0px 0px 3px $motion-transparent;
}
+47
View File
@@ -0,0 +1,47 @@
import PropTypes from 'prop-types';
import React from 'react';
import styles from './question.css';
import Input from '../forms/input.jsx';
const QuestionComponent = props => {
const {
answer,
question,
onChange,
onClick,
onKeyPress
} = props;
return (
<div className={styles.questionWrapper}>
<div className={styles.questionContainer}>
{question ? (
<div className={styles.questionLabel}>{question}</div>
) : null}
<div className={styles.questionInput}>
<Input
autoFocus
value={answer}
onChange={onChange}
onKeyPress={onKeyPress}
/>
<button
className={styles.questionSubmitButton}
onClick={onClick}
>
✔︎
</button>
</div>
</div>
</div>
);
};
QuestionComponent.propTypes = {
answer: PropTypes.string,
onChange: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
onKeyPress: PropTypes.func.isRequired,
question: PropTypes.string
};
export default QuestionComponent;
+11
View File
@@ -5,6 +5,7 @@ import classNames from 'classnames';
import Box from '../box/box.jsx';
import Loupe from '../loupe/loupe.jsx';
import MonitorList from '../../containers/monitor-list.jsx';
import Question from '../../containers/question.jsx';
import styles from './stage.css';
const StageComponent = props => {
@@ -15,6 +16,8 @@ const StageComponent = props => {
colorInfo,
onDeactivateColorPicker,
isColorPicking,
question,
onQuestionAnswered,
...boxProps
} = props;
return (
@@ -40,6 +43,12 @@ const StageComponent = props => {
<Loupe colorInfo={colorInfo} />
</Box>
) : null}
{question === null ? null : (
<Question
question={question}
onQuestionAnswered={onQuestionAnswered}
/>
)}
</Box>
{isColorPicking ? (
<Box
@@ -56,6 +65,8 @@ StageComponent.propTypes = {
height: PropTypes.number,
isColorPicking: PropTypes.bool,
onDeactivateColorPicker: PropTypes.func,
onQuestionAnswered: PropTypes.func,
question: PropTypes.string,
width: PropTypes.number
};
StageComponent.defaultProps = {
+45
View File
@@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import React from 'react';
import bindAll from 'lodash.bindall';
import QuestionComponent from '../components/question/question.jsx';
class Question extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleChange',
'handleKeyPress',
'handleSubmit'
]);
this.state = {
answer: ''
};
}
handleChange (e) {
this.setState({answer: e.target.value});
}
handleKeyPress (event) {
if (event.key === 'Enter') this.handleSubmit();
}
handleSubmit () {
this.props.onQuestionAnswered(this.state.answer);
}
render () {
return (
<QuestionComponent
answer={this.state.answer}
question={this.props.question}
onChange={this.handleChange}
onClick={this.handleSubmit}
onKeyPress={this.handleKeyPress}
/>
);
}
}
Question.propTypes = {
onQuestionAnswered: PropTypes.func.isRequired,
question: PropTypes.string
};
export default Question;
+17 -2
View File
@@ -24,12 +24,14 @@ class Stage extends React.Component {
'cancelMouseDownTimeout',
'detachMouseEvents',
'handleDoubleClick',
'handleQuestionAnswered',
'onMouseUp',
'onMouseMove',
'onMouseDown',
'onStartDrag',
'onStopDrag',
'updateRect',
'questionListener',
'setCanvas'
]);
this.state = {
@@ -38,7 +40,8 @@ class Stage extends React.Component {
isDragging: false,
dragOffset: null,
dragId: null,
colorInfo: null
colorInfo: null,
question: null
};
}
componentDidMount () {
@@ -47,12 +50,14 @@ class Stage extends React.Component {
this.updateRect();
this.renderer = new Renderer(this.canvas);
this.props.vm.attachRenderer(this.renderer);
this.props.vm.runtime.addListener('QUESTION', this.questionListener);
}
shouldComponentUpdate (nextProps, nextState) {
return this.props.width !== nextProps.width ||
this.props.height !== nextProps.height ||
this.props.isColorPicking !== nextProps.isColorPicking ||
this.state.colorInfo !== nextState.colorInfo;
this.state.colorInfo !== nextState.colorInfo ||
this.state.question !== nextState.question;
}
componentDidUpdate (prevProps) {
if (this.props.isColorPicking && !prevProps.isColorPicking) {
@@ -66,6 +71,14 @@ class Stage extends React.Component {
this.detachRectEvents();
this.stopColorPickingLoop();
}
questionListener (question) {
this.setState({question: question});
}
handleQuestionAnswered (answer) {
this.setState({question: null}, () => {
this.props.vm.runtime.emit('ANSWER', answer);
});
}
startColorPickingLoop () {
this.intervalId = setInterval(() => {
this.setState({colorInfo: this.getColorInfo(this.pickX, this.pickY)});
@@ -251,7 +264,9 @@ class Stage extends React.Component {
<StageComponent
canvasRef={this.setCanvas}
colorInfo={this.state.colorInfo}
question={this.state.question}
onDoubleClick={this.handleDoubleClick}
onQuestionAnswered={this.handleQuestionAnswered}
{...props}
/>
);
+4 -4
View File
@@ -336,12 +336,12 @@ const control = `
</shadow>
</value>
</block>
<block type="control_forever"/>
<block id="forever" type="control_forever"/>
${blockSeparator}
<block type="control_if"/>
<block type="control_if_else"/>
<block type="control_wait_until"/>
<block type="control_repeat_until"/>
<block id="wait_until" type="control_wait_until"/>
<block id="repeat_until" type="control_repeat_until"/>
${blockSeparator}
<block type="control_stop"/>
${blockSeparator}
@@ -382,7 +382,7 @@ const sensing = `
</value>
</block>
${blockSeparator}
<block type="sensing_askandwait">
<block id="askandwait" type="sensing_askandwait">
<value name="QUESTION">
<shadow type="text">
<field name="TEXT">What's your name?</field>