mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 13:32:28 -05:00
Switch state to track hover item ID instead of item itself
This commit is contained in:
parent
3bb606e16a
commit
7e1375d855
7 changed files with 58 additions and 45 deletions
|
@ -37,7 +37,6 @@
|
|||
"babel-plugin-transform-object-rest-spread": "^6.22.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-react": "^6.22.0",
|
||||
"canvas-prebuilt": "^1.6.5-prerelease.1",
|
||||
"classnames": "2.2.5",
|
||||
"css-loader": "0.28.3",
|
||||
"enzyme": "^2.8.2",
|
||||
|
|
|
@ -9,7 +9,6 @@ import {setHoveredItem, clearHoveredItem} from '../reducers/hover';
|
|||
|
||||
import SelectTool from '../helper/selection-tools/select-tool';
|
||||
import SelectModeComponent from '../components/select-mode.jsx';
|
||||
import paper from 'paper';
|
||||
|
||||
class SelectMode extends React.Component {
|
||||
constructor (props) {
|
||||
|
@ -25,8 +24,8 @@ class SelectMode extends React.Component {
|
|||
}
|
||||
}
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.tool && nextProps.hoveredItem !== this.props.hoveredItem) {
|
||||
this.tool.setPrevHoveredItem(nextProps.hoveredItem);
|
||||
if (this.tool && nextProps.hoveredItemId !== this.props.hoveredItemId) {
|
||||
this.tool.setPrevHoveredItemId(nextProps.hoveredItemId);
|
||||
}
|
||||
|
||||
if (nextProps.isSelectModeActive && !this.props.isSelectModeActive) {
|
||||
|
@ -57,7 +56,7 @@ class SelectMode extends React.Component {
|
|||
SelectMode.propTypes = {
|
||||
clearHoveredItem: PropTypes.func.isRequired,
|
||||
handleMouseDown: PropTypes.func.isRequired,
|
||||
hoveredItem: PropTypes.instanceOf(paper.Item),
|
||||
hoveredItemId: PropTypes.number,
|
||||
isSelectModeActive: PropTypes.bool.isRequired,
|
||||
onUpdateSvg: PropTypes.func.isRequired,
|
||||
setHoveredItem: PropTypes.func.isRequired
|
||||
|
@ -65,11 +64,11 @@ SelectMode.propTypes = {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
isSelectModeActive: state.scratchPaint.mode === Modes.SELECT,
|
||||
hoveredItem: state.scratchPaint.hoveredItem
|
||||
hoveredItemId: state.scratchPaint.hoveredItemId
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
setHoveredItem: hoveredItem => {
|
||||
dispatch(setHoveredItem(hoveredItem));
|
||||
setHoveredItem: hoveredItemId => {
|
||||
dispatch(setHoveredItem(hoveredItemId));
|
||||
},
|
||||
clearHoveredItem: () => {
|
||||
dispatch(clearHoveredItem());
|
||||
|
|
|
@ -1,29 +1,43 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import bindAll from 'lodash.bindall';
|
||||
import paper from 'paper';
|
||||
|
||||
const SelectionHOC = function (WrappedComponent) {
|
||||
class SelectionComponent extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'removeItemById'
|
||||
]);
|
||||
}
|
||||
componentDidMount () {
|
||||
if (this.props.hoveredItem) {
|
||||
if (this.props.hoveredItemId) {
|
||||
paper.view.update();
|
||||
}
|
||||
}
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.props.hoveredItem && this.props.hoveredItem !== prevProps.hoveredItem) {
|
||||
// A hover item has been added. Update the view
|
||||
if (prevProps.hoveredItem) {
|
||||
prevProps.hoveredItem.remove();
|
||||
// Hovered item has changed
|
||||
if ((this.props.hoveredItemId && this.props.hoveredItemId !== prevProps.hoveredItemId) ||
|
||||
(!this.props.hoveredItemId && prevProps.hoveredItemId)) {
|
||||
// Remove the old hover item if any
|
||||
this.removeItemById(prevProps.hoveredItemId);
|
||||
}
|
||||
}
|
||||
removeItemById (itemId) {
|
||||
if (itemId) {
|
||||
const match = paper.project.getItem({
|
||||
match: item => (item.id === itemId)
|
||||
});
|
||||
if (match) {
|
||||
match.remove();
|
||||
}
|
||||
} else if (!this.props.hoveredItem && prevProps.hoveredItem) {
|
||||
// Remove the hover item
|
||||
prevProps.hoveredItem.remove();
|
||||
}
|
||||
}
|
||||
render () {
|
||||
const {
|
||||
hoveredItem, // eslint-disable-line no-unused-vars
|
||||
hoveredItemId, // eslint-disable-line no-unused-vars
|
||||
...props
|
||||
} = this.props;
|
||||
return (
|
||||
|
@ -32,11 +46,11 @@ const SelectionHOC = function (WrappedComponent) {
|
|||
}
|
||||
}
|
||||
SelectionComponent.propTypes = {
|
||||
hoveredItem: PropTypes.instanceOf(paper.Item)
|
||||
hoveredItemId: PropTypes.number
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hoveredItem: state.scratchPaint.hoveredItem
|
||||
hoveredItemId: state.scratchPaint.hoveredItemId
|
||||
});
|
||||
return connect(
|
||||
mapStateToProps
|
||||
|
|
|
@ -47,11 +47,11 @@ class SelectTool extends paper.Tool {
|
|||
* To be called when the hovered item changes. When the select tool hovers over a
|
||||
* new item, it compares against this to see if a hover item change event needs to
|
||||
* be fired.
|
||||
* @param {paper.Item} prevHoveredItem The highlight that indicates the mouse is over
|
||||
* a given item currently
|
||||
* @param {paper.Item} prevHoveredItemId ID of the highlight item that indicates the mouse is
|
||||
* over a given item currently
|
||||
*/
|
||||
setPrevHoveredItem (prevHoveredItem) {
|
||||
this.prevHoveredItem = prevHoveredItem;
|
||||
setPrevHoveredItemId (prevHoveredItemId) {
|
||||
this.prevHoveredItemId = prevHoveredItemId;
|
||||
}
|
||||
/**
|
||||
* Returns the hit options to use when conducting hit tests.
|
||||
|
@ -92,11 +92,11 @@ class SelectTool extends paper.Tool {
|
|||
}
|
||||
handleMouseMove (event) {
|
||||
const hoveredItem = getHoveredItem(event, this.getHitOptions());
|
||||
if ((!hoveredItem && this.prevHoveredItem) || // There is no longer a hovered item
|
||||
(hoveredItem && !this.prevHoveredItem) || // There is now a hovered item
|
||||
(hoveredItem && this.prevHoveredItem &&
|
||||
hoveredItem.id !== this.prevHoveredItem.id)) { // hovered item changed
|
||||
this.setHoveredItem(hoveredItem);
|
||||
if ((!hoveredItem && this.prevHoveredItemId) || // There is no longer a hovered item
|
||||
(hoveredItem && !this.prevHoveredItemId) || // There is now a hovered item
|
||||
(hoveredItem && this.prevHoveredItemId &&
|
||||
hoveredItem.id !== this.prevHoveredItemId)) { // hovered item changed
|
||||
this.setHoveredItem(hoveredItem ? hoveredItem.id : null);
|
||||
}
|
||||
}
|
||||
handleMouseDrag (event) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import paper from 'paper';
|
||||
import log from '../log/log';
|
||||
|
||||
const CHANGE_HOVERED = 'scratch-paint/hover/CHANGE_HOVERED';
|
||||
|
@ -8,29 +7,36 @@ const reducer = function (state, action) {
|
|||
if (typeof state === 'undefined') state = initialState;
|
||||
switch (action.type) {
|
||||
case CHANGE_HOVERED:
|
||||
if (typeof action.hoveredItem === 'undefined' ||
|
||||
(action.hoveredItem !== null && !(action.hoveredItem instanceof paper.Item))) {
|
||||
if (typeof action.hoveredItemId === 'undefined') {
|
||||
log.warn(`Hovered item should not be set to undefined. Use null.`);
|
||||
return state;
|
||||
} else if (typeof action.hoveredItemId === 'undefined' || isNaN(action.hoveredItemId)) {
|
||||
log.warn(`Hovered item should be an item ID number. Got: ${action.hoveredItemId}`);
|
||||
return state;
|
||||
}
|
||||
return action.hoveredItem;
|
||||
return action.hoveredItemId;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Action creators ==================================
|
||||
const setHoveredItem = function (hoveredItem) {
|
||||
/**
|
||||
* Set the hovered item state to the given item ID
|
||||
* @param {number} hoveredItemId The paper.Item ID of the hover indicator item.
|
||||
* @return {object} Redux action to change the hovered item.
|
||||
*/
|
||||
const setHoveredItem = function (hoveredItemId) {
|
||||
return {
|
||||
type: CHANGE_HOVERED,
|
||||
hoveredItem: hoveredItem
|
||||
hoveredItemId: hoveredItemId
|
||||
};
|
||||
};
|
||||
|
||||
const clearHoveredItem = function () {
|
||||
return {
|
||||
type: CHANGE_HOVERED,
|
||||
hoveredItem: null
|
||||
hoveredItemId: null
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@ export default combineReducers({
|
|||
brushMode: brushModeReducer,
|
||||
eraserMode: eraserModeReducer,
|
||||
color: colorReducer,
|
||||
hoveredItem: hoverReducer
|
||||
hoveredItemId: hoverReducer
|
||||
});
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
/* eslint-env jest */
|
||||
import paper from 'paper';
|
||||
import reducer from '../../src/reducers/hover';
|
||||
import {clearHoveredItem, setHoveredItem} from '../../src/reducers/hover';
|
||||
|
||||
beforeEach(() => {
|
||||
paper.setup();
|
||||
});
|
||||
|
||||
test('initialState', () => {
|
||||
let defaultState;
|
||||
expect(reducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeNull();
|
||||
|
@ -14,22 +9,22 @@ test('initialState', () => {
|
|||
|
||||
test('setHoveredItem', () => {
|
||||
let defaultState;
|
||||
const item1 = new paper.Path();
|
||||
const item2 = new paper.Path();
|
||||
const item1 = 1;
|
||||
const item2 = 2;
|
||||
expect(reducer(defaultState /* state */, setHoveredItem(item1) /* action */)).toBe(item1);
|
||||
expect(reducer(item1 /* state */, setHoveredItem(item2) /* action */)).toBe(item2);
|
||||
});
|
||||
|
||||
test('clearHoveredItem', () => {
|
||||
let defaultState;
|
||||
const item = new paper.Path();
|
||||
const item = 1;
|
||||
expect(reducer(defaultState /* state */, clearHoveredItem() /* action */)).toBeNull();
|
||||
expect(reducer(item /* state */, clearHoveredItem() /* action */)).toBeNull();
|
||||
});
|
||||
|
||||
test('invalidSetHoveredItem', () => {
|
||||
let defaultState;
|
||||
const item = new paper.Path();
|
||||
const item = 1;
|
||||
const nonItem = {random: 'object'};
|
||||
let undef;
|
||||
expect(reducer(defaultState /* state */, setHoveredItem(nonItem) /* action */)).toBeNull();
|
||||
|
|
Loading…
Reference in a new issue