From 63ea5b42010e2d239f4ed88fc813d4206bfcbc64 Mon Sep 17 00:00:00 2001 From: Paul Kaplan <pkaplan@media.mit.edu> Date: Wed, 31 Oct 2018 10:21:39 -0400 Subject: [PATCH] Make the backpack a drop area for workspace code --- src/components/backpack/backpack.jsx | 30 ++++++++--- src/containers/backpack.jsx | 75 +++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/components/backpack/backpack.jsx b/src/components/backpack/backpack.jsx index 9e9a4f75c..f5f450039 100644 --- a/src/components/backpack/backpack.jsx +++ b/src/components/backpack/backpack.jsx @@ -17,7 +17,19 @@ const dragTypeMap = { // Keys correspond with the backpack-server item types sprite: DragConstants.BACKPACK_SPRITE }; -const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, onToggle, onDelete}) => ( +const Backpack = ({ + blockDragOver, + containerRef, + contents, + dragOver, + error, + expanded, + loading, + onToggle, + onDelete, + onMouseEnter, + onMouseLeave +}) => ( <div className={styles.backpackContainer}> <div className={styles.backpackHeader} @@ -44,8 +56,12 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o </div> {expanded ? ( <div - className={styles.backpackList} + className={classNames(styles.backpackList, { + [styles.dragOver]: dragOver || blockDragOver + })} ref={containerRef} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} > {error ? ( <div className={styles.statusMessage}> @@ -66,11 +82,7 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o </div> ) : ( contents.length > 0 ? ( - <div - className={classNames(styles.backpackListInner, { - [styles.dragOver]: dragOver - })} - > + <div className={styles.backpackListInner}> {contents.map(item => ( <SpriteSelectorItem className={styles.backpackItem} @@ -104,6 +116,7 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o ); Backpack.propTypes = { + blockDragOver: PropTypes.bool, containerRef: PropTypes.func, contents: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string, @@ -116,10 +129,13 @@ Backpack.propTypes = { expanded: PropTypes.bool, loading: PropTypes.bool, onDelete: PropTypes.func, + onMouseEnter: PropTypes.func, + onMouseLeave: PropTypes.func, onToggle: PropTypes.func }; Backpack.defaultProps = { + blockDragOver: false, contents: [], dragOver: false, expanded: false, diff --git a/src/containers/backpack.jsx b/src/containers/backpack.jsx index 3f9b2dd59..755b3e3a5 100644 --- a/src/containers/backpack.jsx +++ b/src/containers/backpack.jsx @@ -8,7 +8,8 @@ import { deleteBackpackObject, soundPayload, costumePayload, - spritePayload + spritePayload, + codePayload } from '../lib/backpack-api'; import DragConstants from '../lib/drag-constants'; import DropAreaHOC from '../lib/drop-area-hoc.jsx'; @@ -28,10 +29,18 @@ class Backpack extends React.Component { 'handleToggle', 'handleDelete', 'getBackpackAssetURL', - 'refreshContents' + 'refreshContents', + 'handleMouseEnter', + 'handleMouseLeave', + 'handleBlockDragEnd', + 'handleBlockDragUpdate' ]); this.state = { - dragOver: false, + // While the DroppableHOC manages drop interactions for asset tiles, + // we still need to micromanage drops coming from the block workspace. + // TODO this may be refactorable with the share-the-love logic in SpriteSelectorItem + blockDragOutsideWorkspace: false, + blockDragOverBackpack: false, error: false, offset: 0, itemsPerPage: 20, @@ -50,12 +59,23 @@ class Backpack extends React.Component { storage._hasAddedBackpackSource = true; } } + componentDidMount () { + this.props.vm.addListener('BLOCK_DRAG_END', this.handleBlockDragEnd); + this.props.vm.addListener('BLOCK_DRAG_UPDATE', this.handleBlockDragUpdate); + } + componentWillUnmount () { + this.props.vm.removeListener('BLOCK_DRAG_END', this.handleBlockDragEnd); + this.props.vm.removeListener('BLOCK_DRAG_UPDATE', this.handleBlockDragUpdate); + } getBackpackAssetURL (asset) { return `${this.props.host}/${asset.assetId}.${asset.dataFormat}`; } handleToggle () { const newState = !this.state.expanded; - this.setState({expanded: newState, offset: 0}); + this.setState({expanded: newState, offset: 0}, () => { + // Emit resize on window to get blocks to resize + window.dispatchEvent(new Event('resize')); + }); if (newState) { this.refreshContents(); } @@ -72,6 +92,9 @@ class Backpack extends React.Component { case DragConstants.SPRITE: payloader = spritePayload; break; + case DragConstants.CODE: + payloader = codePayload; + break; } if (!payloader) return; @@ -110,15 +133,47 @@ class Backpack extends React.Component { }); } } + handleBlockDragUpdate (isOutsideWorkspace) { + this.setState({ + blockDragOutsideWorkspace: isOutsideWorkspace + }); + } + handleMouseEnter () { + if (this.state.blockDragOutsideWorkspace) { + this.setState({ + blockDragOverBackpack: true + }); + } + } + handleMouseLeave () { + this.setState({ + blockDragOverBackpack: false + }); + } + handleBlockDragEnd (blocks) { + if (this.state.blockDragOverBackpack) { + this.handleDrop({ + dragType: DragConstants.CODE, + payload: blocks + }); + } + this.setState({ + blockDragOverBackpack: false, + blockDragOutsideWorkspace: false + }); + } render () { return ( <DroppableBackpack + blockDragOver={this.state.blockDragOverBackpack} contents={this.state.contents} error={this.state.error} expanded={this.state.expanded} loading={this.state.loading} onDelete={this.handleDelete} onDrop={this.handleDrop} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} onToggle={this.props.host ? this.handleToggle : null} /> ); @@ -152,9 +207,17 @@ const getTokenAndUsername = state => { const mapStateToProps = state => Object.assign( { - vm: state.scratchGui.vm + dragInfo: state.scratchGui.assetDrag, + vm: state.scratchGui.vm, + blockDrag: state.scratchGui.blockDrag }, getTokenAndUsername(state) ); -export default connect(mapStateToProps)(Backpack); +const mapDispatchToProps = dispatch => ({ + dispatchSetHoveredSprite: spriteId => { + dispatch(setHoveredSprite(spriteId)); + } +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Backpack); -- GitLab