mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 13:32:28 -05:00
add stroke color to state
This commit is contained in:
parent
1088de519f
commit
74ff77a38d
6 changed files with 162 additions and 21 deletions
|
@ -6,6 +6,7 @@ import EraserMode from '../containers/eraser-mode.jsx';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import LineMode from '../containers/line-mode.jsx';
|
import LineMode from '../containers/line-mode.jsx';
|
||||||
import FillColorIndicatorComponent from '../containers/fill-color-indicator.jsx';
|
import FillColorIndicatorComponent from '../containers/fill-color-indicator.jsx';
|
||||||
|
import StrokeColorIndicatorComponent from '../containers/stroke-color-indicator.jsx';
|
||||||
|
|
||||||
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
||||||
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
||||||
|
@ -20,16 +21,6 @@ const messages = defineMessages({
|
||||||
id: 'paint.paintEditor.costume',
|
id: 'paint.paintEditor.costume',
|
||||||
description: 'Label for the name of a sound',
|
description: 'Label for the name of a sound',
|
||||||
defaultMessage: 'Costume'
|
defaultMessage: 'Costume'
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
id: 'paint.paintEditor.fill',
|
|
||||||
description: 'Label for the color picker for the fill color',
|
|
||||||
defaultMessage: 'Fill'
|
|
||||||
},
|
|
||||||
outline: {
|
|
||||||
id: 'paint.paintEditor.outline',
|
|
||||||
description: 'Label for the color picker for the outline color',
|
|
||||||
defaultMessage: 'Outline'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -107,18 +98,10 @@ class PaintEditorComponent extends React.Component {
|
||||||
|
|
||||||
{/* Second Row */}
|
{/* Second Row */}
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
{/* To be fill */}
|
{/* fill */}
|
||||||
<FillColorIndicatorComponent />
|
<FillColorIndicatorComponent />
|
||||||
{/* To be stroke */}
|
{/* stroke */}
|
||||||
<div className={styles.inputGroup}>
|
<StrokeColorIndicatorComponent />
|
||||||
<Label text={this.props.intl.formatMessage(messages.outline)}>
|
|
||||||
<BufferedInput
|
|
||||||
tabIndex="1"
|
|
||||||
type="text"
|
|
||||||
value="meow"
|
|
||||||
/>
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputGroup}>
|
<div className={styles.inputGroup}>
|
||||||
Mode tools
|
Mode tools
|
||||||
|
|
38
src/components/stroke-color-indicator.jsx
Normal file
38
src/components/stroke-color-indicator.jsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
||||||
|
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
||||||
|
import Label from './forms/label.jsx';
|
||||||
|
import Input from './forms/input.jsx';
|
||||||
|
|
||||||
|
import styles from './paint-editor.css';
|
||||||
|
|
||||||
|
const BufferedInput = BufferedInputHOC(Input);
|
||||||
|
const messages = defineMessages({
|
||||||
|
stroke: {
|
||||||
|
id: 'paint.paintEditor.stroke',
|
||||||
|
description: 'Label for the color picker for the outline color',
|
||||||
|
defaultMessage: 'Outline'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const StrokeColorIndicatorComponent = props => (
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<Label text={props.intl.formatMessage(messages.stroke)}>
|
||||||
|
<BufferedInput
|
||||||
|
tabIndex="1"
|
||||||
|
type="text"
|
||||||
|
value={props.strokeColor}
|
||||||
|
onSubmit={props.onChangeStrokeColor}
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
StrokeColorIndicatorComponent.propTypes = {
|
||||||
|
intl: intlShape,
|
||||||
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
|
strokeColor: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default injectIntl(StrokeColorIndicatorComponent);
|
31
src/containers/stroke-color-indicator.jsx
Normal file
31
src/containers/stroke-color-indicator.jsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {changeStrokeColor} from '../reducers/stroke-color';
|
||||||
|
import StrokeColorIndicatorComponent from '../components/stroke-color-indicator.jsx';
|
||||||
|
|
||||||
|
const StrokeColorIndicator = props => (
|
||||||
|
<StrokeColorIndicatorComponent
|
||||||
|
strokeColor={props.strokeColor}
|
||||||
|
onChangeStrokeColor={props.handleChangeStrokeColor}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
StrokeColorIndicator.propTypes = {
|
||||||
|
handleChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
|
strokeColor: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
strokeColor: state.scratchPaint.color.strokeColor
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
handleChangeStrokeColor: strokeColor => {
|
||||||
|
dispatch(changeStrokeColor(strokeColor));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(StrokeColorIndicator);
|
8
src/reducers/color.js
Normal file
8
src/reducers/color.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import {combineReducers} from 'redux';
|
||||||
|
import fillColorReducer from './fill-color';
|
||||||
|
import strokeColorReducer from './stroke-color';
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
fillColor: fillColorReducer,
|
||||||
|
strokeColor: strokeColorReducer
|
||||||
|
});
|
33
src/reducers/stroke-color.js
Normal file
33
src/reducers/stroke-color.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import log from '../log/log';
|
||||||
|
|
||||||
|
const CHANGE_STROKE_COLOR = 'scratch-paint/stroke-color/CHANGE_STROKE_COLOR';
|
||||||
|
const initialState = '#000';
|
||||||
|
// Matches hex colors
|
||||||
|
const regExp = /^#([0-9a-f]{3}){1,2}$/i;
|
||||||
|
|
||||||
|
const reducer = function (state, action) {
|
||||||
|
if (typeof state === 'undefined') state = initialState;
|
||||||
|
switch (action.type) {
|
||||||
|
case CHANGE_STROKE_COLOR:
|
||||||
|
if (!regExp.test(action.strokeColor)) {
|
||||||
|
log.warn(`Invalid hex color code: ${action.fillColor}`);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return action.strokeColor;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Action creators ==================================
|
||||||
|
const changeStrokeColor = function (strokeColor) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_STROKE_COLOR,
|
||||||
|
strokeColor: strokeColor
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
reducer as default,
|
||||||
|
changeStrokeColor
|
||||||
|
};
|
48
test/unit/stroke-color-reducer.test.js
Normal file
48
test/unit/stroke-color-reducer.test.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* eslint-env jest */
|
||||||
|
import strokeColorReducer from '../../src/reducers/stroke-color';
|
||||||
|
import {changeStrokeColor} from '../../src/reducers/stroke-color';
|
||||||
|
|
||||||
|
test('initialState', () => {
|
||||||
|
let defaultState;
|
||||||
|
|
||||||
|
expect(strokeColorReducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('changeStrokeColor', () => {
|
||||||
|
let defaultState;
|
||||||
|
|
||||||
|
// 3 value hex code
|
||||||
|
let newStrokeColor = '#fff';
|
||||||
|
expect(strokeColorReducer(defaultState /* state */, changeStrokeColor(newStrokeColor) /* action */))
|
||||||
|
.toEqual(newStrokeColor);
|
||||||
|
expect(strokeColorReducer('#010' /* state */, changeStrokeColor(newStrokeColor) /* action */))
|
||||||
|
.toEqual(newStrokeColor);
|
||||||
|
|
||||||
|
// 6 value hex code
|
||||||
|
newStrokeColor = '#facade';
|
||||||
|
expect(strokeColorReducer(defaultState /* state */, changeStrokeColor(newStrokeColor) /* action */))
|
||||||
|
.toEqual(newStrokeColor);
|
||||||
|
expect(strokeColorReducer('#010' /* state */, changeStrokeColor(newStrokeColor) /* action */))
|
||||||
|
.toEqual(newStrokeColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invalidChangeStrokeColor', () => {
|
||||||
|
const origState = '#fff';
|
||||||
|
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor() /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#1') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#12') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#1234') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#12345') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('#1234567') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeColorReducer(origState /* state */, changeStrokeColor('invalid argument') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
});
|
Loading…
Reference in a new issue