diff --git a/src/containers/stroke-width-indicator.jsx b/src/containers/stroke-width-indicator.jsx index 30d9c0a9..ed27ff96 100644 --- a/src/containers/stroke-width-indicator.jsx +++ b/src/containers/stroke-width-indicator.jsx @@ -3,12 +3,13 @@ import PropTypes from 'prop-types'; import React from 'react'; import bindAll from 'lodash.bindall'; import parseColor from 'parse-color'; -import {changeStrokeColor} from '../reducers/stroke-style'; +import {changeStrokeColor, changeStrokeColor2, changeStrokeGradientType} from '../reducers/stroke-style'; import {changeStrokeWidth} from '../reducers/stroke-width'; import StrokeWidthIndicatorComponent from '../components/stroke-width-indicator.jsx'; import {getSelectedLeafItems} from '../helper/selection'; import {applyColorToSelection, applyStrokeWidthToSelection, getColorsFromSelection, MIXED} from '../helper/style-path'; +import GradientTypes from '../lib/gradient-types'; import Modes from '../lib/modes'; import Formats from '../lib/format'; import {isBitmap} from '../lib/format'; @@ -23,8 +24,15 @@ class StrokeWidthIndicator extends React.Component { handleChangeStrokeWidth (newWidth) { let changed = applyStrokeWidthToSelection(newWidth, this.props.textEditTarget); if ((!this.props.strokeWidth || this.props.strokeWidth === 0) && newWidth > 0) { - let currentColor = getColorsFromSelection(getSelectedLeafItems(), isBitmap(this.props.format)).strokeColor; - if (currentColor === null) { + const currentColorState = getColorsFromSelection(getSelectedLeafItems(), isBitmap(this.props.format)); + + // Color counts as null if either both colors are null or the primary color is null and it's solid + // TODO: consolidate this check in one place + const wasNull = currentColorState.strokeColor === null && + (currentColorState.strokeColor2 === null || + currentColorState.strokeGradientType === GradientTypes.SOLID); + + if (wasNull) { changed = applyColorToSelection( '#000', 0, // colorIndex, @@ -32,11 +40,15 @@ class StrokeWidthIndicator extends React.Component { true, // applyToStroke this.props.textEditTarget) || changed; - currentColor = '#000'; - } else if (currentColor !== MIXED) { - currentColor = parseColor(currentColor).hex; + // If there's no previous stroke color, default to solid black + this.props.onChangeStrokeGradientType(GradientTypes.SOLID); + this.props.onChangeStrokeColor('#000'); + } else if (currentColorState.strokeColor !== MIXED) { + // Set color state from the selected item's stroke color + this.props.onChangeStrokeGradientType(currentColorState.strokeGradientType); + this.props.onChangeStrokeColor(parseColor(currentColorState.strokeColor).hex); + this.props.onChangeStrokeColor2(parseColor(currentColorState.strokeColor2).hex); } - this.props.onChangeStrokeColor(currentColor); } this.props.onChangeStrokeWidth(newWidth); if (changed) this.props.onUpdateImage(); @@ -64,6 +76,12 @@ const mapDispatchToProps = dispatch => ({ onChangeStrokeColor: strokeColor => { dispatch(changeStrokeColor(strokeColor)); }, + onChangeStrokeColor2: strokeColor => { + dispatch(changeStrokeColor2(strokeColor)); + }, + onChangeStrokeGradientType: strokeColor => { + dispatch(changeStrokeGradientType(strokeColor)); + }, onChangeStrokeWidth: strokeWidth => { dispatch(changeStrokeWidth(strokeWidth)); } @@ -73,6 +91,8 @@ StrokeWidthIndicator.propTypes = { disabled: PropTypes.bool.isRequired, format: PropTypes.oneOf(Object.keys(Formats)), onChangeStrokeColor: PropTypes.func.isRequired, + onChangeStrokeColor2: PropTypes.func.isRequired, + onChangeStrokeGradientType: PropTypes.func.isRequired, onChangeStrokeWidth: PropTypes.func.isRequired, onUpdateImage: PropTypes.func.isRequired, strokeWidth: PropTypes.number, diff --git a/src/reducers/stroke-style.js b/src/reducers/stroke-style.js index 72a15168..1d611356 100644 --- a/src/reducers/stroke-style.js +++ b/src/reducers/stroke-style.js @@ -6,6 +6,8 @@ const CHANGE_STROKE_GRADIENT_TYPE = 'scratch-paint/stroke-style/CHANGE_STROKE_GR const CLEAR_STROKE_GRADIENT = 'scratch-paint/stroke-style/CLEAR_STROKE_GRADIENT'; const DEFAULT_COLOR = '#000000'; +import {CHANGE_STROKE_WIDTH} from './stroke-width'; + const reducer = makeColorStyleReducer({ changePrimaryColorAction: CHANGE_STROKE_COLOR, changeSecondaryColorAction: CHANGE_STROKE_COLOR_2, @@ -17,6 +19,22 @@ const reducer = makeColorStyleReducer({ selectionGradientTypeKey: 'strokeGradientType' }); +// This is mostly the same as the generated reducer, but with one piece of extra logic to set the color to null when the +// stroke width is set to 0. +// https://redux.js.org/recipes/structuring-reducers/reusing-reducer-logic +const strokeReducer = function (state, action) { + if (action.type === CHANGE_STROKE_WIDTH && Math.max(action.strokeWidth, 0) === 0) { + // TODO: this preserves the gradient type when you change the stroke width to 0. + // Alternatively, we could set gradientType to SOLID instead of setting secondary to null, but since + // the stroke width is automatically set to 0 as soon as a "null" color is detected (including a gradient for + // which both colors are null), that would change the gradient type back to solid if you selected null for both + // gradient colors. + return {...state, primary: null, secondary: null}; + } + + return reducer(state, action); +}; + // Action creators ================================== const changeStrokeColor = function (strokeColor) { return { @@ -46,7 +64,7 @@ const clearStrokeGradient = function () { }; export { - reducer as default, + strokeReducer as default, changeStrokeColor, changeStrokeColor2, changeStrokeGradientType,