mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 13:32:28 -05:00
add fill color component
This commit is contained in:
parent
f96c26ddbe
commit
9e4c510372
6 changed files with 155 additions and 10 deletions
38
src/components/fill-color-indicator.jsx
Normal file
38
src/components/fill-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({
|
||||
fill: {
|
||||
id: 'paint.paintEditor.fill',
|
||||
description: 'Label for the color picker for the fill color',
|
||||
defaultMessage: 'Fill'
|
||||
}
|
||||
});
|
||||
const FillColorIndicatorComponent = props => (
|
||||
<div className={styles.inputGroup}>
|
||||
<Label text={props.intl.formatMessage(messages.fill)}>
|
||||
<BufferedInput
|
||||
tabIndex="1"
|
||||
type="text"
|
||||
value={props.fillColor}
|
||||
onSubmit={props.onChangeFillColor}
|
||||
/>
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
|
||||
FillColorIndicatorComponent.propTypes = {
|
||||
fillColor: PropTypes.string.isRequired,
|
||||
intl: intlShape,
|
||||
onChangeFillColor: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(FillColorIndicatorComponent);
|
|
@ -5,6 +5,7 @@ import BrushMode from '../containers/brush-mode.jsx';
|
|||
import EraserMode from '../containers/eraser-mode.jsx';
|
||||
import PropTypes from 'prop-types';
|
||||
import LineMode from '../containers/line-mode.jsx';
|
||||
import FillColorIndicatorComponent from '../containers/fill-color-indicator.jsx';
|
||||
|
||||
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
||||
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
||||
|
@ -107,15 +108,7 @@ class PaintEditorComponent extends React.Component {
|
|||
{/* Second Row */}
|
||||
<div className={styles.row}>
|
||||
{/* To be fill */}
|
||||
<div className={styles.inputGroup}>
|
||||
<Label text={this.props.intl.formatMessage(messages.fill)}>
|
||||
<BufferedInput
|
||||
tabIndex="1"
|
||||
type="text"
|
||||
value="meow"
|
||||
/>
|
||||
</Label>
|
||||
</div>
|
||||
<FillColorIndicatorComponent />
|
||||
{/* To be stroke */}
|
||||
<div className={styles.inputGroup}>
|
||||
<Label text={this.props.intl.formatMessage(messages.outline)}>
|
||||
|
|
31
src/containers/fill-color-indicator.jsx
Normal file
31
src/containers/fill-color-indicator.jsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {changeFillColor} from '../reducers/fill-color';
|
||||
import FillColorIndicatorComponent from '../components/fill-color-indicator.jsx';
|
||||
|
||||
const FillColorIndicator = props => (
|
||||
<FillColorIndicatorComponent
|
||||
fillColor={props.fillColor}
|
||||
onChangeFillColor={props.handleChangeFillColor}
|
||||
/>
|
||||
);
|
||||
|
||||
FillColorIndicator.propTypes = {
|
||||
fillColor: PropTypes.string.isRequired,
|
||||
handleChangeFillColor: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
fillColor: state.scratchPaint.fillColor
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
handleChangeFillColor: fillColor => {
|
||||
dispatch(changeFillColor(fillColor));
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(FillColorIndicator);
|
33
src/reducers/fill-color.js
Normal file
33
src/reducers/fill-color.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import log from '../log/log';
|
||||
|
||||
const CHANGE_FILL_COLOR = 'scratch-paint/fill-color/CHANGE_FILL_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_FILL_COLOR:
|
||||
if (!regExp.test(action.fillColor)) {
|
||||
log.warn(`Invalid hex color code: ${action.fillColor}`);
|
||||
return state;
|
||||
}
|
||||
return action.fillColor;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Action creators ==================================
|
||||
const changeFillColor = function (fillColor) {
|
||||
return {
|
||||
type: CHANGE_FILL_COLOR,
|
||||
fillColor: fillColor
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
reducer as default,
|
||||
changeFillColor
|
||||
};
|
|
@ -3,10 +3,12 @@ import modeReducer from './modes';
|
|||
import brushModeReducer from './brush-mode';
|
||||
import eraserModeReducer from './eraser-mode';
|
||||
import lineModeReducer from './line-mode';
|
||||
import fillColorReducer from './fill-color';
|
||||
|
||||
export default combineReducers({
|
||||
mode: modeReducer,
|
||||
brushMode: brushModeReducer,
|
||||
eraserMode: eraserModeReducer,
|
||||
lineMode: lineModeReducer
|
||||
lineMode: lineModeReducer,
|
||||
fillColor: fillColorReducer
|
||||
});
|
||||
|
|
48
test/unit/fill-color-reducer.test.js
Normal file
48
test/unit/fill-color-reducer.test.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* eslint-env jest */
|
||||
import fillColorReducer from '../../src/reducers/fill-color';
|
||||
import {changeFillColor} from '../../src/reducers/fill-color';
|
||||
|
||||
test('initialState', () => {
|
||||
let defaultState;
|
||||
|
||||
expect(fillColorReducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeDefined();
|
||||
});
|
||||
|
||||
test('changeFillColor', () => {
|
||||
let defaultState;
|
||||
|
||||
// 3 value hex code
|
||||
let newFillColor = '#fff';
|
||||
expect(fillColorReducer(defaultState /* state */, changeFillColor(newFillColor) /* action */))
|
||||
.toEqual(newFillColor);
|
||||
expect(fillColorReducer('#010' /* state */, changeFillColor(newFillColor) /* action */))
|
||||
.toEqual(newFillColor);
|
||||
|
||||
// 6 value hex code
|
||||
newFillColor = '#facade';
|
||||
expect(fillColorReducer(defaultState /* state */, changeFillColor(newFillColor) /* action */))
|
||||
.toEqual(newFillColor);
|
||||
expect(fillColorReducer('#010' /* state */, changeFillColor(newFillColor) /* action */))
|
||||
.toEqual(newFillColor);
|
||||
});
|
||||
|
||||
test('invalidChangeFillColor', () => {
|
||||
const origState = '#fff';
|
||||
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor() /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#1') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#12') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#1234') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#12345') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('#1234567') /* action */))
|
||||
.toBe(origState);
|
||||
expect(fillColorReducer(origState /* state */, changeFillColor('invalid argument') /* action */))
|
||||
.toBe(origState);
|
||||
});
|
Loading…
Reference in a new issue