diff --git a/src/components/library-item/library-item.css b/src/components/library-item/library-item.css index 3102d3d2d2a29d5f58db70f638b3d15fc5404491..12253a55202602010b71b2a98014d1ecbbe787df 100644 --- a/src/components/library-item/library-item.css +++ b/src/components/library-item/library-item.css @@ -26,8 +26,16 @@ border-color: #1dacf4; } +.library-item-image-container-wrapper { + height: 100px; + width: 100%; + position: relative; +} + .library-item-image-container { + position: absolute; height: 100px; + width: 100%; } .library-item-image { diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx index 8e113c9be08af583a36272da486fe8afe31e0367..cdb1415a12db8370c0e8e5a66f7c6d732ba5073e 100644 --- a/src/components/library-item/library-item.jsx +++ b/src/components/library-item/library-item.jsx @@ -14,6 +14,9 @@ class LibraryItem extends React.Component { 'handleMouseLeave' ]); } + shouldComponentUpdate (nextProps) { + return this.props.iconURL !== nextProps.iconURL; + } handleClick (e) { this.props.onSelect(this.props.id); e.preventDefault(); @@ -32,11 +35,14 @@ class LibraryItem extends React.Component { onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} > - <Box className={styles.libraryItemImageContainer}> - <img - className={styles.libraryItemImage} - src={this.props.iconURL} - /> + {/* Layers of wrapping is to prevent layout thrashing on animation */} + <Box className={styles.libraryItemImageContainerWrapper}> + <Box className={styles.libraryItemImageContainer}> + <img + className={styles.libraryItemImage} + src={this.props.iconURL} + /> + </Box> </Box> <span className={styles.libraryItemName}>{this.props.name}</span> </Box> diff --git a/src/containers/costume-library.jsx b/src/containers/costume-library.jsx index d0a004ba674e37c4710c581ef1c72bd7658d798d..f245c098fcc179fc76fb17ba2c9590f449a379cc 100644 --- a/src/containers/costume-library.jsx +++ b/src/containers/costume-library.jsx @@ -7,7 +7,7 @@ const costumeLibraryContent = require('../lib/libraries/costumes.json'); const LibraryComponent = require('../components/library/library.jsx'); -class CostumeLibrary extends React.Component { +class CostumeLibrary extends React.PureComponent { constructor (props) { super(props); bindAll(this, [ diff --git a/src/containers/sound-library.jsx b/src/containers/sound-library.jsx index 53aa6bde02f9d54e0d394691549bd04416c7bce5..d82512225f5ccdadb4ce2ec548275d9f7acbfb3d 100644 --- a/src/containers/sound-library.jsx +++ b/src/containers/sound-library.jsx @@ -9,7 +9,7 @@ const soundIcon = require('../components/asset-panel/icon--sound.svg'); const soundLibraryContent = require('../lib/libraries/sounds.json'); -class SoundLibrary extends React.Component { +class SoundLibrary extends React.PureComponent { constructor (props) { super(props); bindAll(this, [ diff --git a/src/containers/sprite-library.jsx b/src/containers/sprite-library.jsx index 0a1bcaa3ebcad309733aa10c5f98faf25c68f56a..6395b421a7abb0664b334a8839105067548c9f0e 100644 --- a/src/containers/sprite-library.jsx +++ b/src/containers/sprite-library.jsx @@ -7,22 +7,68 @@ const spriteLibraryContent = require('../lib/libraries/sprites.json'); const LibraryComponent = require('../components/library/library.jsx'); -class SpriteLibrary extends React.Component { +class SpriteLibrary extends React.PureComponent { constructor (props) { super(props); bindAll(this, [ - 'handleItemSelect' + 'handleItemSelect', + 'handleMouseEnter', + 'handleMouseLeave', + 'rotateCostume', + 'startRotatingCostumes', + 'stopRotatingCostumes' ]); + this.state = { + activeSprite: null, + costumeIndex: 0, + sprites: spriteLibraryContent + }; + } + componentWillReceiveProps (newProps) { + if (!newProps.visible) clearInterval(this.intervalId); } handleItemSelect (item) { this.props.vm.addSprite2(JSON.stringify(item.json)); } + handleMouseEnter (item) { + this.stopRotatingCostumes(); + this.setState({activeSprite: item}, this.startRotatingCostumes); + } + handleMouseLeave () { + this.stopRotatingCostumes(); + } + startRotatingCostumes () { + if (!this.state.activeSprite) return; + this.rotateCostume(); + this.intervalId = setInterval(this.rotateCostume, 300); + } + stopRotatingCostumes () { + this.intervalId = clearInterval(this.intervalId); + } + rotateCostume () { + const costumes = this.state.activeSprite.json.costumes; + const nextCostumeIndex = (this.state.costumeIndex + 1) % costumes.length; + this.setState({ + costumeIndex: nextCostumeIndex, + sprites: this.state.sprites.map(sprite => { + if (sprite.name === this.state.activeSprite.name) { + return { + ...sprite, + md5: sprite.json.costumes[nextCostumeIndex].baseLayerMD5 + }; + } + return sprite; + }) + }); + } render () { return ( <LibraryComponent - data={spriteLibraryContent} + data={this.state.sprites} title="Sprite Library" visible={this.props.visible} + onItemMouseEnter={this.handleMouseEnter} + onItemMouseLeave={this.handleMouseLeave} onItemSelected={this.handleItemSelect} onRequestClose={this.props.onRequestClose} />