From 043e31a4728b89289cc4093d22c7eca5a35e1276 Mon Sep 17 00:00:00 2001
From: Chris Garrity <chrisg@media.mit.edu>
Date: Wed, 31 Jul 2019 10:25:37 -0400
Subject: [PATCH] Refactor

* split play-button into container and component
* revised sound library tile:
  * play button in upper right
  * smaller sound icon (make the tile less loaded)
---
 .../library-item/lib-icon--sound-rtl.svg      | Bin 0 -> 2050 bytes
 .../library-item/lib-icon--sound.svg          | Bin 0 -> 2059 bytes
 src/components/library-item/library-item.jsx  |   2 +-
 src/components/library/library.jsx            |   2 +-
 src/components/play-button/play-button.css    |   4 +-
 src/components/play-button/play-button.jsx    | 159 +++++-------------
 src/containers/play-button.jsx                | 115 +++++++++++++
 src/containers/sound-library.jsx              |   4 +-
 8 files changed, 163 insertions(+), 123 deletions(-)
 create mode 100644 src/components/library-item/lib-icon--sound-rtl.svg
 create mode 100644 src/components/library-item/lib-icon--sound.svg
 create mode 100644 src/containers/play-button.jsx

diff --git a/src/components/library-item/lib-icon--sound-rtl.svg b/src/components/library-item/lib-icon--sound-rtl.svg
new file mode 100644
index 0000000000000000000000000000000000000000..db193366a3f7c592381ca6382f49de2ba2abc5a2
GIT binary patch
literal 2050
zcmZuyO>ZMN488BKP^Xs`7|WDMQDR_wff{X5z<cSYm%XL&)HdR^1KS&?{q_6gk9q=R
z3<DB}LsIWOQlpQrU)S!X+wE7|&A17k8rN+exAWCzF>e04|7}p3kCP9h{ma4~SM$RX
zK19#2jazoB#q#j~_GQ%_f7!l{8*=2}QvXdqaA+J-ZT914c{n`Z4Ts0$(I44wcZ*>p
zq9IaTT<%`itIgAUj={`^r?<`IgTpiWVK8vNcbjhaaM<qd+~=q6@VInIeRMySpgI2R
z2Cin@Bjx_|)<15)y20QQ;IKNZyUFM6x6OQb4zwQ5R)6mvcK^Ej)w*+kJZ?9`KksLw
z;o0?^ci!zEC(~W`aOmbh=CHh^_M_qH)!A#|R`YT5Zty`3KDY*N-2SlJK6T?}v)y#p
z-QWs&<NjH#*VmVIJ=lF)!@GOwHrx69g2oAv=LZynte=E@HVH9stK|9gh?}zcl=0)x
zH*@h^Qb{4U$$ZwB@ulPJb4-Fwn+ld1Q)Gk?FP6DRPV6&LN$|ZHC3{h_LT@5S^uj3>
ze2-W`Nm*JHS&9;<a&>8Bgk)H9X3Ejwqhv5sXeIbq*kX+!g0+=^L%<_aiekaRS`tg5
z+*XG`A&WR+ScAk8TS-1=!WuXroQVWAZ3XpkiE41ZSrh7woRs?!Qu1tSQPQc1YdQ$d
zQc#rEs|=7?f(-#~rvSPoXCtj8L{AYe7AqB@Xif&_;Dwkez2WVBHov$}OdcoF2ygLv
ze%v%7ch+E<`{tOvsTNdSt%1oRv4fS(g5=UF`;c;u0CO6nFRE72#Hob<Rd79H1v3>W
z0@hmua7z?p!0}K+gv<(Q%j%P4mY5vs4WuPlu2#xa^EnPar3f9BYDHP#T%nZc%_<tP
zty(O}1PC#E0kaW@gPJunrz*AR6~{5QDwV(-SRs{YP(nez(n@6s$}g^GOi&6%Ayjq?
z06K_6hQd+9Et`TG3yDhgy%q+{AXYPk?VSSnMz$(UM8I6lkc>%%Jw+p_&g2twVSU5g
zyL5tPXtaO~1$F4Okc&njG3}cX4`)MGhpuE`%o19VfN!uabt+P3MQ^vL2m_i4+|4v%
z&DnCQ&<k6Z+G6zpp<v*Kwho8d&S)kDggHqOsnD}PW1%>OsDWS>&~&rTGCCS9n;@*7
zd79ayo&XT~=8Qgs2n@Amb#*765gpLF8Mfd_iv>)jY2DQk6Yv_Yw{UfI5oCeG_Hy^E
zGgO)ZdC_p1a~J1nJyw9az(voy_K3!Sr}k$S5=<Niyhs$23T#3#0gY<K&3fo+#w4>M
zK(WUJDq>Lq{;tQG7B8Y4F%SAyOfrm<Iss=rbC3Bi&G~LwK0M>TIA0GxLfpURblzTW
b2;3+Cb-Qgd84c^raJlt{3tZ~;%AI@%Ucl45

literal 0
HcmV?d00001

diff --git a/src/components/library-item/lib-icon--sound.svg b/src/components/library-item/lib-icon--sound.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2ffc760131cccf23d7e0346985252c5e765ccefa
GIT binary patch
literal 2059
zcmZuyO>g5i5WVlOVAV?t$kdR-8IpnR1!}ZK0q><rFMG?zsx8Ek0^6IU{q=qHN38%+
z5WspIy&1lFLry=xJ#EcPyW4j|KdYRj%C!B%u<H8ttorNjw@Io#&p%D~FKhGKtqvQ+
z5Iw(DX47`-&Efyom#%&NWq6xaWXK?-{8wXQR~e-0_p@qqI6U7p&Fkx{ePuiB){Q5k
z1}V-VH*ednfBY!W<(!-2YBm34@JxT0Ow8|X-|p@Y!|ul1KDLL4jS;op{FIzV|FfBx
zl5vle`{Sy87@o{zawa%*hiyB*9lrOg=0vn@mfg4A{q7%g*KJ$#$HUM!%ez0P%_;Ph
zch&A6=8Ii>e`r@w=CC=Zw$tXgbc$M=ZZ)euB%c)W$%VW!`@?Q{Y-d$J^zG$sa*@0;
ze|OvMWwHF8?7nXi-M+N_uv(qfI4bgdk7AJZi)8CbQcST{vV44kSxB;yRdaX;OSCys
zU`i#}C5@8V01e~_s@GskF=o<2AvQWf5a499s3gRSbwMR$t|5OG2edT8g(T6X8ta@j
z`yj^}NbnJbTD%ROMM0441q{hXP98;$83NKqa>1WUxMT~#dQ=kwg0F=IUv}?9cH><H
zXMN)AQQ87K!qzBztpoIlOwk)X1+X5$l$78iqacexVhKgPjM~jY#R_>X`UdEvloNsA
ziVE9Elmy`Qd+ZW4UOa=rS#<#dL7i-)B8NjTK@t2x-BI5@?&eqXMYGLGIHH}w>gfS>
zMn&qB-@%G*`6z+31dGq;crrjkh%Q85P|vyO28w8jidA3<F8btLf)(G1MCKahLtY_(
z5$jn=T`8H^Mene`NH!+tAWJPECLc)52n@w1Q3~so04;LNj<ra9O~%<Ol0xwkd?}10
zGDwE$#=BtfdP*?sQHYcoHE<1>B1uG>qq8w+ayb-KLge64nzwpvn6DXTB<~$`h_Mtz
z#n{DxlF&S7Mkri|DN#6WL;%TLNd<HPn6M=%Tm*Iu&k>gz$TJFqlGo0C*iN)riY#as
zI2ar;smG?5BN!y`suUM5#&GGbvd7>;Z-o{rxkeW_C@kVlV5p^x2G>wF<(xt?ODLNK
zl@_Z&7DvJv9bvJFV@m00&KM{pbeh>>P6EMg#mHqU&{QT2rlOU{)8m3JJ?1Vt4IZwz
z1~0r?l$KzKG3;?dl;LvfFo)$0Ql;!LCri9x_8BYirdgC%hqDdNi3q*Y!8(u)Vabeg
zkI*G5b#M`mg?a=p%C>M`Ingl;3E*m6S-H3b5+%aX1HDpKcwCC30%x2TkZ~j~qk}|D
zFwbJt37@PAYKCB=uAw5qU|<;Eq1VoTt&VrgVtD%2_3dhMySabH#c{ePe#BJ$8s+qQ
czAA9B{M+t^YCdhs6>+})nl*0sa`(>v1Cv75<^TWy

literal 0
HcmV?d00001

diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
index 504be2b66..74a65aa9a 100644
--- a/src/components/library-item/library-item.jsx
+++ b/src/components/library-item/library-item.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 
 import Box from '../box/box.jsx';
-import PlayButton from '../play-button/play-button.jsx';
+import PlayButton from '../../containers/play-button.jsx';
 import styles from './library-item.css';
 import classNames from 'classnames';
 
diff --git a/src/components/library/library.jsx b/src/components/library/library.jsx
index 259e922ff..f85def50f 100644
--- a/src/components/library/library.jsx
+++ b/src/components/library/library.jsx
@@ -73,7 +73,7 @@ class LibraryComponent extends React.Component {
     handleTagClick (tag) {
         if (this.state.playingItem === null) {
             this.setState({
-                ilterQuery: '',
+                filterQuery: '',
                 selectedTag: tag.toLowerCase()
             });
         } else {
diff --git a/src/components/play-button/play-button.css b/src/components/play-button/play-button.css
index fbc901e66..17d2b6317 100644
--- a/src/components/play-button/play-button.css
+++ b/src/components/play-button/play-button.css
@@ -34,9 +34,9 @@
 }
 
 [dir="ltr"] .play-button {
-    left: .5rem;
+    right: .5rem;
 }
 
 [dir="rtl"] .play-button {
-    right: .5rem;
+    left: .5rem;
 }
diff --git a/src/components/play-button/play-button.jsx b/src/components/play-button/play-button.jsx
index 8071ce849..15f8226ac 100644
--- a/src/components/play-button/play-button.jsx
+++ b/src/components/play-button/play-button.jsx
@@ -1,7 +1,6 @@
 import PropTypes from 'prop-types';
 import React from 'react';
 import classNames from 'classnames';
-import bindAll from 'lodash.bindall';
 
 import {defineMessages, injectIntl, intlShape} from 'react-intl';
 
@@ -23,126 +22,52 @@ const messages = defineMessages({
     }
 });
 
-class PlayButton extends React.Component {
-    constructor (props) {
-        super(props);
-        bindAll(this, [
-            'handleClick',
-            'handleMouseDown',
-            'handleMouseEnter',
-            'handleMouseLeave',
-            'handleTouchStart',
-            'setButtonRef'
-        ]);
-        this.state = {
-            touchStarted: false
-        };
-    }
-    getDerivedStateFromProps (props, state) {
-        // if touchStarted is true and it's not playing, the sound must have ended.
-        // reset the touchStarted state to allow the sound to be replayed
-        if (state.touchStarted && !props.isPlaying) {
-            return {
-                touchStarted: false
-            };
-        }
-        return null; // nothing changed
-    }
-    componentDidMount () {
-        // Touch start
-        this.buttonRef.addEventListener('touchstart', this.handleTouchStart);
-    }
-    componentWillUnmount () {
-        this.buttonRef.removeEventListener('touchstart', this.handleTouchStart);
-    }
-    handleClick (e) {
-        //  stop the click from propagating out of the button
-        e.stopPropagation();
-    }
-    handleMouseDown (e) {
-        // prevent default (focus) on mouseDown
-        e.preventDefault();
-        if (this.props.isPlaying) {
-            // stop sound and reset touch state
-            this.props.onStop();
-            if (this.state.touchstarted) this.setState({touchStarted: false});
-        } else {
-            this.props.onPlay();
-            if (this.state.touchstarted) {
-                // started on touch, but now clicked mouse
-                this.setState({touchStarted: false});
-            }
-        }
-    }
-    handleTouchStart (e) {
-        if (this.props.isPlaying) {
-            // If playing, stop sound, and reset touch state
-            e.preventDefault();
-            this.setState({touchStarted: false});
-            this.props.onStop();
-        } else {
-            // otherwise start playing, and set touch state
-            e.preventDefault();
-            this.setState({touchStarted: true});
-            this.props.onPlay();
-        }
-    }
-    handleMouseEnter (e) {
-        // start the sound if it's not already playing
-        e.preventDefault();
-        if (!this.props.isPlaying) {
-            this.props.onPlay();
-        }
-    }
-    handleMouseLeave () {
-        // stop the sound unless it was started by touch
-        if (this.props.isPlaying && !this.state.touchstarted) {
-            this.props.onStop();
-        }
-    }
-    setButtonRef (ref) {
-        this.buttonRef = ref;
-    }
-    render () {
-        const {
-            className,
-            intl,
-            isPlaying,
-            onPlay, // eslint-disable-line no-unused-vars
-            onStop // eslint-disable-line no-unused-vars
-        } = this.props;
-        const label = isPlaying ?
-            intl.formatMessage(messages.stop) :
-            intl.formatMessage(messages.play);
+const PlayButtonComponent = ({
+    className,
+    intl,
+    isPlaying,
+    onClick,
+    onMouseDown,
+    onMouseEnter,
+    onMouseLeave,
+    setButtonRef,
+    ...props
+}) => {
+    const label = isPlaying ?
+        intl.formatMessage(messages.stop) :
+        intl.formatMessage(messages.play);
 
-        return (
-            <div
-                aria-label={label}
-                className={classNames(styles.playButton, className, {
-                    [styles.playing]: isPlaying
-                })}
-                ref={this.setButtonRef}
-                onClick={this.handleClick}
-                onMouseDown={this.handleMouseDown}
-                onMouseEnter={this.handleMouseEnter}
-                onMouseLeave={this.handleMouseLeave}
-            >
-                <img
-                    className={styles.playIcon}
-                    draggable={false}
-                    src={isPlaying ? stopIcon : playIcon}
-                />
-            </div>
-        );
-    }
-}
+    return (
+        <div
+            aria-label={label}
+            className={classNames(styles.playButton, className, {
+                [styles.playing]: isPlaying
+            })}
+            onClick={onClick}
+            onMouseDown={onMouseDown}
+            onMouseEnter={onMouseEnter}
+            onMouseLeave={onMouseLeave}
+            ref={setButtonRef}
+            {...props}
+        >
+            <img
+                className={styles.playIcon}
+                draggable={false}
+                src={isPlaying ? stopIcon : playIcon}
+            />
+        </div>
+    );
+};
 
-PlayButton.propTypes = {
+PlayButtonComponent.propTypes = {
     className: PropTypes.string,
     intl: intlShape,
     isPlaying: PropTypes.bool.isRequired,
-    onPlay: PropTypes.func.isRequired,
-    onStop: PropTypes.func.isRequired
+    onClick: PropTypes.func.isRequired,
+    onMouseDown: PropTypes.func.isRequired,
+    onMouseEnter: PropTypes.func.isRequired,
+    onMouseLeave: PropTypes.func.isRequired,
+    setButtonRef: PropTypes.func.isRequired
 };
 
-export default injectIntl(PlayButton);
+export default injectIntl(PlayButtonComponent);
diff --git a/src/containers/play-button.jsx b/src/containers/play-button.jsx
new file mode 100644
index 000000000..f0ed8b6a2
--- /dev/null
+++ b/src/containers/play-button.jsx
@@ -0,0 +1,115 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import bindAll from 'lodash.bindall';
+
+import PlayButtonComponent from '../components/play-button/play-button.jsx';
+
+class PlayButton extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleClick',
+            'handleMouseDown',
+            'handleMouseEnter',
+            'handleMouseLeave',
+            'handleTouchStart',
+            'setButtonRef'
+        ]);
+        this.state = {
+            touchStarted: false
+        };
+    }
+    getDerivedStateFromProps (props, state) {
+        // if touchStarted is true and it's not playing, the sound must have ended.
+        // reset the touchStarted state to allow the sound to be replayed
+        if (state.touchStarted && !props.isPlaying) {
+            return {
+                touchStarted: false
+            };
+        }
+        return null; // nothing changed
+    }
+    componentDidMount () {
+        // Touch start
+        this.buttonRef.addEventListener('touchstart', this.handleTouchStart);
+    }
+    componentWillUnmount () {
+        this.buttonRef.removeEventListener('touchstart', this.handleTouchStart);
+    }
+    handleClick (e) {
+        //  stop the click from propagating out of the button
+        e.stopPropagation();
+    }
+    handleMouseDown (e) {
+        // prevent default (focus) on mouseDown
+        e.preventDefault();
+        if (this.props.isPlaying) {
+            // stop sound and reset touch state
+            this.props.onStop();
+            if (this.state.touchstarted) this.setState({touchStarted: false});
+        } else {
+            this.props.onPlay();
+            if (this.state.touchstarted) {
+                // started on touch, but now clicked mouse
+                this.setState({touchStarted: false});
+            }
+        }
+    }
+    handleTouchStart (e) {
+        if (this.props.isPlaying) {
+            // If playing, stop sound, and reset touch state
+            e.preventDefault();
+            this.setState({touchStarted: false});
+            this.props.onStop();
+        } else {
+            // otherwise start playing, and set touch state
+            e.preventDefault();
+            this.setState({touchStarted: true});
+            this.props.onPlay();
+        }
+    }
+    handleMouseEnter (e) {
+        // start the sound if it's not already playing
+        e.preventDefault();
+        if (!this.props.isPlaying) {
+            this.props.onPlay();
+        }
+    }
+    handleMouseLeave () {
+        // stop the sound unless it was started by touch
+        if (this.props.isPlaying && !this.state.touchstarted) {
+            this.props.onStop();
+        }
+    }
+    setButtonRef (ref) {
+        this.buttonRef = ref;
+    }
+    render () {
+        const {
+            className,
+            isPlaying,
+            onPlay, // eslint-disable-line no-unused-vars
+            onStop // eslint-disable-line no-unused-vars
+        } = this.props;
+        return (
+            <PlayButtonComponent
+                className={className}
+                isPlaying={isPlaying}
+                onClick={this.handleClick}
+                onMouseDown={this.handleMouseDown}
+                onMouseEnter={this.handleMouseEnter}
+                onMouseLeave={this.handleMouseLeave}
+                setButtonRef={this.setButtonRef}
+            />
+        );
+    }
+}
+
+PlayButton.propTypes = {
+    className: PropTypes.string,
+    isPlaying: PropTypes.bool.isRequired,
+    onPlay: PropTypes.func.isRequired,
+    onStop: PropTypes.func.isRequired
+};
+
+export default PlayButton;
diff --git a/src/containers/sound-library.jsx b/src/containers/sound-library.jsx
index d3b9782d1..cdb5c7c6a 100644
--- a/src/containers/sound-library.jsx
+++ b/src/containers/sound-library.jsx
@@ -7,8 +7,8 @@ import AudioEngine from 'scratch-audio';
 
 import LibraryComponent from '../components/library/library.jsx';
 
-import soundIcon from '../components/asset-panel/icon--sound.svg';
-import soundIconRtl from '../components/asset-panel/icon--sound-rtl.svg';
+import soundIcon from '../components/library-item/lib-icon--sound.svg';
+import soundIconRtl from '../components/library-item/lib-icon--sound-rtl.svg';
 
 import soundLibraryContent from '../lib/libraries/sounds.json';
 import soundTags from '../lib/libraries/sound-tags';
-- 
GitLab