diff --git a/app/lib/components/Chat/MessageList.jsx b/app/lib/components/Chat/MessageList.jsx index 3f59d1a..e80e17b 100644 --- a/app/lib/components/Chat/MessageList.jsx +++ b/app/lib/components/Chat/MessageList.jsx @@ -1,14 +1,9 @@ import React, { Component } from 'react'; +import { compose } from 'redux'; import PropTypes from 'prop-types'; import marked from 'marked'; import { connect } from 'react-redux'; - -const scrollToBottom = () => -{ - const messagesDiv = document.getElementById('messages'); - - messagesDiv.scrollTop = messagesDiv.scrollHeight; -}; +import scrollToBottom from './scrollToBottom'; const linkRenderer = new marked.Renderer(); @@ -22,16 +17,6 @@ linkRenderer.link = (href, title, text) => class MessageList extends Component { - componentDidMount() - { - scrollToBottom(); - } - - componentDidUpdate() - { - scrollToBottom(); - } - getTimeString(time) { return `${(time.getHours() < 10 ? '0' : '')}${time.getHours()}:${(time.getMinutes() < 10 ? '0' : '')}${time.getMinutes()}`; @@ -96,8 +81,9 @@ const mapStateToProps = (state) => }; }; -const MessageListContainer = connect( - mapStateToProps +const MessageListContainer = compose( + connect(mapStateToProps), + scrollToBottom() )(MessageList); export default MessageListContainer; diff --git a/app/lib/components/Chat/scrollToBottom.jsx b/app/lib/components/Chat/scrollToBottom.jsx new file mode 100644 index 0000000..2a107a4 --- /dev/null +++ b/app/lib/components/Chat/scrollToBottom.jsx @@ -0,0 +1,63 @@ +import React, { Component } from 'react'; +import { findDOMNode } from 'react-dom'; + +/** + * A higher order component which scrolls the user to the bottom of the + * wrapped component, provided that the user already was at the bottom + * of the wrapped component. Useful for chats and similar use cases. + * @param {number} treshold The required distance from the bottom required. + */ +const scrollToBottom = (treshold = 0) => (WrappedComponent) => +{ + return class AutoScroller extends Component + { + constructor(props) + { + super(props); + + this.ref = React.createRef(); + } + + getSnapshotBeforeUpdate() + { + // Check if the user has scrolled close enough to the bottom for + // us to scroll to the bottom or not. + return this.elem.scrollHeight - this.elem.scrollTop <= + this.elem.clientHeight - treshold; + } + + scrollToBottom = () => + { + // Scroll the user to the bottom of the wrapped element. + this.elem.scrollTop = this.elem.scrollHeight; + }; + + componentDidMount() + { + // eslint-disable-next-line react/no-find-dom-node + this.elem = findDOMNode(this.ref.current); + + this.scrollToBottom(); + } + + componentDidUpdate(prevProps, prevState, atBottom) + { + if (atBottom) + { + this.scrollToBottom(); + } + } + + render() + { + return ( + + ); + } + }; +}; + +export default scrollToBottom; \ No newline at end of file diff --git a/app/lib/components/FullScreenView.jsx b/app/lib/components/FullScreenView.jsx index cee2dd0..ebf62f4 100644 --- a/app/lib/components/FullScreenView.jsx +++ b/app/lib/components/FullScreenView.jsx @@ -11,7 +11,8 @@ const FullScreenView = (props) => const { advancedMode, consumer, - toggleConsumerFullscreen + toggleConsumerFullscreen, + toolbarsVisible } = props; if (!consumer) @@ -39,7 +40,9 @@ const FullScreenView = (props) =>
{ e.stopPropagation(); @@ -63,13 +66,15 @@ FullScreenView.propTypes = { advancedMode : PropTypes.bool, consumer : appPropTypes.Consumer, - toggleConsumerFullscreen : PropTypes.func.isRequired + toggleConsumerFullscreen : PropTypes.func.isRequired, + toolbarsVisible : PropTypes.bool }; const mapStateToProps = (state) => { return { - consumer : state.consumers[state.room.fullScreenConsumer] + consumer : state.consumers[state.room.fullScreenConsumer], + toolbarsVisible : state.room.toolbarsVisible }; }; diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index dcc62d5..142394e 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -179,13 +179,13 @@ .room-controls { visibility: hidden; - animation: fade-out 0.5s; + animation: fade-out 0.3s; opacity: 0; &.visible { visibility: visible; opacity: 1; - animation: fade-in 0.5s; + animation: fade-in 0.3s; } } diff --git a/app/stylus/index.styl b/app/stylus/index.styl index 3ae98ce..2ad0be0 100644 --- a/app/stylus/index.styl +++ b/app/stylus/index.styl @@ -5,6 +5,7 @@ global-reset(); @import './mixins'; @import './fonts'; @import './reset'; +@import './keyframes'; html { height: 100%; diff --git a/app/stylus/keyframes.styl b/app/stylus/keyframes.styl new file mode 100644 index 0000000..76a728e --- /dev/null +++ b/app/stylus/keyframes.styl @@ -0,0 +1,21 @@ +@keyframes fade-in { + from { + opacity: 0; + visibility: hidden; + } + + to { + visibility: visible; + } +} + +@keyframes fade-out { + from { + visibility: visible; + } + + to { + opacity: 0; + visibility: hidden; + } +} \ No newline at end of file