diff --git a/src/components/color-picker/color-picker.css b/src/components/color-picker/color-picker.css index e0a8db4e..d7ae648c 100644 --- a/src/components/color-picker/color-picker.css +++ b/src/components/color-picker/color-picker.css @@ -32,10 +32,14 @@ margin: 8px; } -.label-readout { +[dir="ltr"] .label-readout { margin-left: 10px; } +[dir="rtl"] .label-readout { + margin-right: 10px; +} + .label-name { font-weight: bold; } @@ -96,6 +100,14 @@ margin: 8px; } -.gradient-picker-row > img + img { +[dir="ltr"] .gradient-picker-row > img + img { margin-left: calc(2 * $grid-unit); } + +[dir="rtl"] .gradient-picker-row > img + img { + margin-right: calc(2 * $grid-unit); +} + +[dir="rtl"] .gradient-swatches-row { + flex-direction: row-reverse; +} diff --git a/src/components/color-picker/color-picker.jsx b/src/components/color-picker/color-picker.jsx index 015e275f..7724db85 100644 --- a/src/components/color-picker/color-picker.jsx +++ b/src/components/color-picker/color-picker.jsx @@ -56,7 +56,10 @@ class ColorPickerComponent extends React.Component { } render () { return ( -
+
{this.props.shouldShowGradientTools ? (
@@ -103,7 +106,12 @@ class ColorPickerComponent extends React.Component {
{this.props.gradientType === GradientTypes.SOLID ? null : (
-
+
{ className={styles.modUnselect} enterExitTransitionDurationMs={20} popoverContent={ - +
@@ -17,7 +18,8 @@ const InputGroup = props => ( InputGroup.propTypes = { children: PropTypes.node.isRequired, className: PropTypes.string, - disabled: PropTypes.bool + disabled: PropTypes.bool, + rtl: PropTypes.bool }; export default InputGroup; diff --git a/src/components/paint-editor/paint-editor.jsx b/src/components/paint-editor/paint-editor.jsx index 75164647..c2f54be5 100644 --- a/src/components/paint-editor/paint-editor.jsx +++ b/src/components/paint-editor/paint-editor.jsx @@ -57,7 +57,10 @@ const messages = defineMessages({ }); const PaintEditorComponent = props => ( -
+
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
{/* First row */} @@ -338,6 +341,7 @@ PaintEditorComponent.propTypes = { onZoomReset: PropTypes.func.isRequired, rotationCenterX: PropTypes.number, rotationCenterY: PropTypes.number, + rtl: PropTypes.bool, setCanvas: PropTypes.func.isRequired, setTextArea: PropTypes.func.isRequired, textArea: PropTypes.instanceOf(Element) diff --git a/src/containers/color-picker.jsx b/src/containers/color-picker.jsx index 3a28dab9..e776832d 100644 --- a/src/containers/color-picker.jsx +++ b/src/containers/color-picker.jsx @@ -129,6 +129,7 @@ class ColorPicker extends React.Component { gradientType={this.props.gradientType} hue={this.state.hue} isEyeDropping={this.props.isEyeDropping} + rtl={this.props.rtl} saturation={this.state.saturation} shouldShowGradientTools={this.props.shouldShowGradientTools} onActivateEyeDropper={this.handleActivateEyeDropper} @@ -160,12 +161,14 @@ ColorPicker.propTypes = { onSelectColor: PropTypes.func.isRequired, onSelectColor2: PropTypes.func.isRequired, onSwap: PropTypes.func, + rtl: PropTypes.bool.isRequired, shouldShowGradientTools: PropTypes.bool.isRequired }; const mapStateToProps = state => ({ colorIndex: state.scratchPaint.fillMode.colorIndex, - isEyeDropping: state.scratchPaint.color.eyeDropper.active + isEyeDropping: state.scratchPaint.color.eyeDropper.active, + rtl: state.scratchPaint.layout.rtl }); const mapDispatchToProps = dispatch => ({ diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx index 991bce26..59396d64 100644 --- a/src/containers/paint-editor.jsx +++ b/src/containers/paint-editor.jsx @@ -13,6 +13,7 @@ import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; import {deactivateEyeDropper} from '../reducers/eye-dropper'; import {setTextEditTarget} from '../reducers/text-edit-target'; import {updateViewBounds} from '../reducers/view-bounds'; +import {setLayout} from '../reducers/layout'; import {getRaster, hideGuideLayers, showGuideLayers} from '../helper/layer'; import {commitSelectionToBitmap, convertToBitmap, convertToVector, getHitBounds} from '../helper/bitmap'; @@ -69,6 +70,7 @@ class PaintEditor extends React.Component { // When isSwitchingFormats is true, the format is about to switch, but isn't done switching. // This gives currently active tools a chance to finish what they were doing. this.isSwitchingFormats = false; + this.props.setLayout(this.props.rtl ? 'rtl' : 'ltr'); } componentDidMount () { document.addEventListener('keydown', (/* event */) => { @@ -94,6 +96,9 @@ class PaintEditor extends React.Component { } else if (isVector(newProps.format) && isBitmap(this.props.format)) { this.switchMode(Formats.VECTOR); } + if (newProps.rtl !== this.props.rtl) { + this.props.setLayout(newProps.rtl ? 'rtl' : 'ltr'); + } } componentDidUpdate (prevProps) { if (this.props.isEyeDropping && !prevProps.isEyeDropping) { @@ -386,6 +391,7 @@ class PaintEditor extends React.Component { name={this.props.name} rotationCenterX={this.props.rotationCenterX} rotationCenterY={this.props.rotationCenterY} + rtl={this.props.rtl} setCanvas={this.setCanvas} setTextArea={this.setTextArea} textArea={this.state.textArea} @@ -438,6 +444,8 @@ PaintEditor.propTypes = { removeTextEditTarget: PropTypes.func.isRequired, rotationCenterX: PropTypes.number, rotationCenterY: PropTypes.number, + rtl: PropTypes.bool, + setLayout: PropTypes.func.isRequired, setSelectedItems: PropTypes.func.isRequired, textEditing: PropTypes.bool.isRequired, undoSnapshot: PropTypes.func.isRequired, @@ -499,6 +507,9 @@ const mapDispatchToProps = dispatch => ({ removeTextEditTarget: () => { dispatch(setTextEditTarget()); }, + setLayout: layout => { + dispatch(setLayout(layout)); + }, setSelectedItems: format => { dispatch(setSelectedItems(getSelectedLeafItems(), isBitmap(format))); }, diff --git a/src/reducers/layout.js b/src/reducers/layout.js new file mode 100644 index 00000000..202328f3 --- /dev/null +++ b/src/reducers/layout.js @@ -0,0 +1,39 @@ +import log from '../log/log'; +const SET_LAYOUT = 'scratch-paint/layout/SET_LAYOUT'; +const initialState = {rtl: false}; + +const layouts = ['ltr', 'rtl']; + +const reducer = function (state, action) { + if (typeof state === 'undefined') state = initialState; + switch (action.type) { + case SET_LAYOUT: + if (layouts.indexOf(action.layout) === -1) { + log.warn(`Unrecognized layout provided: ${action.layout}`); + return state; + } + return {rtl: action.layout === 'rtl'}; + default: + return state; + } +}; + +// Action creators ================================== +/** + * Change the layout to the new layout + * @param {string} layout either 'ltr' or 'rtl' + * @return {object} Redux action to change the selected items. + */ +const setLayout = function (layout) { + return { + type: SET_LAYOUT, + layout: layout + }; +}; + + +export { + reducer as default, + setLayout, + SET_LAYOUT +}; diff --git a/src/reducers/scratch-paint-reducer.js b/src/reducers/scratch-paint-reducer.js index 35dbaf2f..8b6f0bec 100644 --- a/src/reducers/scratch-paint-reducer.js +++ b/src/reducers/scratch-paint-reducer.js @@ -11,6 +11,7 @@ import fillModeReducer from './fill-mode'; import fontReducer from './font'; import formatReducer from './format'; import hoverReducer from './hover'; +import layoutReducer from './layout'; import modalsReducer from './modals'; import selectedItemReducer from './selected-items'; import textEditTargetReducer from './text-edit-target'; @@ -30,6 +31,7 @@ export default combineReducers({ font: fontReducer, format: formatReducer, hoveredItemId: hoverReducer, + layout: layoutReducer, modals: modalsReducer, selectedItems: selectedItemReducer, textEditTarget: textEditTargetReducer,