Skip to content

Commit

Permalink
Prevent tab 'appear' icon animations running again when tab is moved
Browse files Browse the repository at this point in the history
Fix brave#11470
Note that if we want to animate the unmounting of the component (when audio is stopped), then we should use https://github.com/reactjs/react-transition-group
  • Loading branch information
petemill committed Oct 13, 2017
1 parent 7de1673 commit ab14121
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 39 deletions.
10 changes: 10 additions & 0 deletions app/renderer/components/styles/animations.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const opacityIncreaseKeyframes = {
}
}

const opacityIncreaseElementKeyframes = {
opacity: [0, 1]
}

// TODO: this could be a function with param included
// to which property should be changed
const widthIncreaseKeyframes = (start, end) => ({
Expand All @@ -31,6 +35,10 @@ const widthIncreaseKeyframes = (start, end) => ({
}
})

const widthIncreaseElementKeyframes = (start, end) => ({
width: [start, end]
})

const loaderAnimation = {
'0': {
transform: 'translate(0,0)'
Expand All @@ -46,6 +54,8 @@ const loaderAnimation = {
module.exports = {
spinKeyframes,
opacityIncreaseKeyframes,
opacityIncreaseElementKeyframes,
widthIncreaseKeyframes,
widthIncreaseElementKeyframes,
loaderAnimation
}
46 changes: 38 additions & 8 deletions app/renderer/components/tabs/content/audioTabIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
Expand All @@ -18,14 +19,15 @@ const tabState = require('../../../../common/state/tabState')
const windowActions = require('../../../../../js/actions/windowActions')

// Styles
const {widthIncreaseKeyframes} = require('../../styles/animations')
const {widthIncreaseElementKeyframes} = require('../../styles/animations')
const globalStyles = require('../../styles/global')
const {theme} = require('../../styles/theme')

class AudioTabIcon extends React.Component {
constructor (props) {
super(props)
this.toggleMute = this.toggleMute.bind(this)
this.setRef = this.setRef.bind(this)
}

get audioIcon () {
Expand Down Expand Up @@ -56,6 +58,39 @@ class AudioTabIcon extends React.Component {
return props
}

componentDidMount (props) {
this.transitionIfRequired()
}

componentDidUpdate (prevProps) {
this.transitionIfRequired(prevProps)
}

transitionIfRequired (prevProps) {
// transition only if we have an element and we're not pinned
if (!this.element || this.props.isPinned) {
return
}
// transition only if audio state changes
const hasChanged = !prevProps || this.props.showAudioIcon !== prevProps.showAudioIcon
// TODO: if we want to animate the unmounting of the component (when audio is stopped),
// then we should use https://github.com/reactjs/react-transition-group
if (!hasChanged || !this.props.showAudioIcon) {
return
}
// TODO: measure element width if this ever becomes dynamic since it's not great to specify complex size logic in two places
// ...or animate a child element using transform: translateX in order to achieve the slide-in
const frames = widthIncreaseElementKeyframes(0, globalStyles.spacing.iconSize)
this.element.animate(frames, {
duration: 100,
easing: 'linear'
})
}

setRef (ref) {
this.element = ReactDOM.findDOMNode(ref)
}

render () {
if (this.props.isPinned || !this.props.showAudioIcon) {
return null
Expand All @@ -66,19 +101,14 @@ class AudioTabIcon extends React.Component {
className={css(styles.audioTab__icon)}
symbol={this.audioIcon}
onClick={this.toggleMute}
ref={this.setRef}
/>
}
}

const styles = StyleSheet.create({
audioTab__icon: {
width: 0,
animationName: widthIncreaseKeyframes(0, globalStyles.spacing.iconSize),
animationDelay: '50ms',
animationTimingFunction: 'linear',
animationDuration: '100ms',
animationFillMode: 'forwards',

width: globalStyles.spacing.iconSize,
overflow: 'hidden',
margin: '0 -2px 0 2px',
zIndex: globalStyles.zindex.zindexTabsAudioTopBorder,
Expand Down
42 changes: 35 additions & 7 deletions app/renderer/components/tabs/content/closeTabIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
Expand All @@ -22,14 +23,15 @@ const appActions = require('../../../../../js/actions/appActions')
// Styles
const {theme} = require('../../styles/theme')
const {spacing, zindex} = require('../../styles/global')
const {opacityIncreaseKeyframes} = require('../../styles/animations')
const {opacityIncreaseElementKeyframes} = require('../../styles/animations')
const closeTabSvg = require('../../../../extensions/brave/img/tabs/close_btn.svg')

class CloseTabIcon extends React.Component {
constructor (props) {
super(props)
this.onClick = this.onClick.bind(this)
this.onDragStart = this.onDragStart.bind(this)
this.setRef = this.setRef.bind(this)
}

onClick (event) {
Expand Down Expand Up @@ -63,6 +65,37 @@ class CloseTabIcon extends React.Component {
return props
}

componentDidMount (props) {
this.transitionIfRequired()
}

componentDidUpdate (prevProps) {
this.transitionIfRequired(prevProps)
}

transitionIfRequired (prevProps) {
// transition only if we have an element and we're not pinned
if (!this.element || this.props.isPinned) {
return
}
// transition only if relevant state changes
const hasChanged = !prevProps || this.props.showCloseIcon !== prevProps.showCloseIcon
// TODO: if we want to animate the unmounting of the component (when tab is unhovered),
// then we should use https://github.com/reactjs/react-transition-group
if (!hasChanged || !this.props.showCloseIcon) {
return
}
const frames = opacityIncreaseElementKeyframes
this.element.animate(frames, {
duration: 200,
easing: 'linear'
})
}

setRef (ref) {
this.element = ReactDOM.findDOMNode(ref)
}

render () {
if (this.props.isPinned || !this.props.showCloseIcon) {
return null
Expand All @@ -79,6 +112,7 @@ class CloseTabIcon extends React.Component {
onClick={this.onClick}
onDragStart={this.onDragStart}
draggable='true'
ref={this.setRef}
/>
}
}
Expand All @@ -87,13 +121,7 @@ module.exports = ReduxComponent.connect(CloseTabIcon)

const styles = StyleSheet.create({
closeTab__icon: {
opacity: 0,
willChange: 'opacity',
animationName: opacityIncreaseKeyframes,
animationTimingFunction: 'linear',
animationDuration: '200ms',
animationDelay: '25ms',
animationFillMode: 'forwards',

boxSizing: 'border-box',
zIndex: zindex.zindexTabsThumbnail,
Expand Down
39 changes: 31 additions & 8 deletions app/renderer/components/tabs/content/favIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
Expand All @@ -19,9 +20,14 @@ const tabState = require('../../../../common/state/tabState')
const defaultIconSvg = require('../../../../extensions/brave/img/tabs/default.svg')
const loadingIconSvg = require('../../../../extensions/brave/img/tabs/loading.svg')
const {filter, color, spacing} = require('../../styles/global')
const {spinKeyframes, opacityIncreaseKeyframes} = require('../../styles/animations')
const {spinKeyframes, opacityIncreaseElementKeyframes} = require('../../styles/animations')

class Favicon extends React.Component {
constructor (props) {
super(props)
this.setRef = this.setRef.bind(this)
}

mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const tabId = ownProps.tabId
Expand All @@ -47,6 +53,29 @@ class Favicon extends React.Component {
: this.props.favicon || 'defaultIcon'
}

componentDidMount (props) {
this.transitionInIfRequired()
}

componentDidUpdate (prevProps) {
this.transitionInIfRequired(prevProps)
}

transitionInIfRequired (prevProps) {
// transition only if favicon changes
const shouldTransitionIn = this.element && !this.props.tabLoading && (!prevProps || this.props.favicon !== prevProps.favicon)
if (shouldTransitionIn) {
this.element.animate(opacityIncreaseElementKeyframes, {
duration: 200,
easing: 'linear'
})
}
}

setRef (ref) {
this.element = ReactDOM.findDOMNode(ref)
}

render () {
if (!this.props.isPinned && !this.props.showIcon) {
return null
Expand Down Expand Up @@ -81,6 +110,7 @@ class Favicon extends React.Component {
!this.props.isPinned && this.props.showIconWithLessMargin && styles.icon_lessMargin,
!this.props.isPinned && this.props.showIconAtReducedSize && styles.icon_reducedSize
)}
ref={this.setRef}
symbol={
this.props.tabLoading
? (
Expand All @@ -100,14 +130,7 @@ module.exports = ReduxComponent.connect(Favicon)

const styles = StyleSheet.create({
icon: {
opacity: 0,
willChange: 'opacity',
animationName: opacityIncreaseKeyframes,
animationDelay: '50ms',
animationTimingFunction: 'linear',
animationDuration: '200ms',
animationFillMode: 'forwards',

position: 'relative',
boxSizing: 'border-box',
width: spacing.iconSize,
Expand Down
39 changes: 31 additions & 8 deletions app/renderer/components/tabs/content/newSessionIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
Expand All @@ -17,10 +18,15 @@ const frameStateUtil = require('../../../../../js/state/frameStateUtil')

// Styles
const globalStyles = require('../../styles/global')
const {opacityIncreaseKeyframes} = require('../../styles/animations')
const {opacityIncreaseElementKeyframes} = require('../../styles/animations')
const newSessionSvg = require('../../../../extensions/brave/img/tabs/new_session.svg')

class NewSessionIcon extends React.Component {
constructor (props) {
super(props)
this.setRef = this.setRef.bind(this)
}

mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const tabId = ownProps.tabId
Expand All @@ -37,6 +43,29 @@ class NewSessionIcon extends React.Component {
return props
}

componentDidMount (props) {
this.transitionInIfRequired()
}

componentDidUpdate (prevProps) {
this.transitionInIfRequired(prevProps)
}

transitionInIfRequired (prevProps) {
// transition only if showPartitionIcon is newly true
const shouldTransitionIn = this.element && !this.props.isPinned && this.props.showPartitionIcon && this.props.partitionNumber !== 0 && (!prevProps || !prevProps.showParitionIcon || this.props.partitionNumber === 0)
if (shouldTransitionIn) {
this.element.animate(opacityIncreaseElementKeyframes, {
duration: 200,
easing: 'linear'
})
}
}

setRef (ref) {
this.element = ReactDOM.findDOMNode(ref)
}

render () {
if (
this.props.isPinned ||
Expand All @@ -60,6 +89,7 @@ class NewSessionIcon extends React.Component {
symbolContent={this.props.partitionNumber}
l10nArgs={{partitionNumber: this.props.partitionNumber}}
l10nId='sessionInfoTab'
ref={this.setRef}
/>
}
}
Expand All @@ -68,14 +98,7 @@ module.exports = ReduxComponent.connect(NewSessionIcon)

const styles = StyleSheet.create({
newSession__icon: {
opacity: 0,
willChange: 'opacity',
animationName: opacityIncreaseKeyframes,
animationDelay: '100ms',
animationTimingFunction: 'linear',
animationDuration: '200ms',
animationFillMode: 'forwards',

zIndex: globalStyles.zindex.zindexTabsThumbnail,
boxSizing: 'border-box',
display: 'flex',
Expand Down
Loading

0 comments on commit ab14121

Please sign in to comment.