[Glitch] Temporarily hold timeline if mouse moved recently
Port 6e72dda7ef
to glitch-soc
lolsob-rspec
parent
cf48c0e6e1
commit
f4191a8a00
|
@ -10,6 +10,8 @@ import classNames from 'classnames';
|
|||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
|
||||
import LoadingIndicator from './loading_indicator';
|
||||
|
||||
const MOUSE_IDLE_DELAY = 300;
|
||||
|
||||
export default class ScrollableList extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -38,6 +40,8 @@ export default class ScrollableList extends PureComponent {
|
|||
|
||||
state = {
|
||||
fullscreen: null,
|
||||
mouseMovedRecently: false,
|
||||
scrollToTopOnMouseIdle: false,
|
||||
};
|
||||
|
||||
intersectionObserverWrapper = new IntersectionObserverWrapper();
|
||||
|
@ -61,6 +65,47 @@ export default class ScrollableList extends PureComponent {
|
|||
trailing: true,
|
||||
});
|
||||
|
||||
mouseIdleTimer = null;
|
||||
|
||||
clearMouseIdleTimer = () => {
|
||||
if (this.mouseIdleTimer === null) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(this.mouseIdleTimer);
|
||||
this.mouseIdleTimer = null;
|
||||
};
|
||||
|
||||
handleMouseMove = throttle(() => {
|
||||
// As long as the mouse keeps moving, clear and restart the idle timer.
|
||||
this.clearMouseIdleTimer();
|
||||
this.mouseIdleTimer =
|
||||
setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
|
||||
|
||||
this.setState(({
|
||||
mouseMovedRecently,
|
||||
scrollToTopOnMouseIdle,
|
||||
}) => ({
|
||||
mouseMovedRecently: true,
|
||||
// Only set scrollToTopOnMouseIdle if we just started moving and were
|
||||
// scrolled to the top. Otherwise, just retain the previous state.
|
||||
scrollToTopOnMouseIdle:
|
||||
mouseMovedRecently
|
||||
? scrollToTopOnMouseIdle
|
||||
: (this.node.scrollTop === 0),
|
||||
}));
|
||||
}, MOUSE_IDLE_DELAY / 2);
|
||||
|
||||
handleMouseIdle = () => {
|
||||
if (this.state.scrollToTopOnMouseIdle) {
|
||||
this.node.scrollTop = 0;
|
||||
this.props.onScrollToTop();
|
||||
}
|
||||
this.setState({
|
||||
mouseMovedRecently: false,
|
||||
scrollToTopOnMouseIdle: false,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.attachScrollListener();
|
||||
this.attachIntersectionObserver();
|
||||
|
@ -90,7 +135,7 @@ export default class ScrollableList extends PureComponent {
|
|||
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
||||
React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
|
||||
this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
|
||||
if (someItemInserted && this.node.scrollTop > 0) {
|
||||
if ((someItemInserted && this.node.scrollTop > 0) || this.state.mouseMovedRecently) {
|
||||
return this.node.scrollHeight - this.node.scrollTop;
|
||||
} else {
|
||||
return null;
|
||||
|
@ -104,6 +149,7 @@ export default class ScrollableList extends PureComponent {
|
|||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.clearMouseIdleTimer();
|
||||
this.detachScrollListener();
|
||||
this.detachIntersectionObserver();
|
||||
detachFullscreenListener(this.onFullScreenChange);
|
||||
|
@ -181,7 +227,7 @@ export default class ScrollableList extends PureComponent {
|
|||
);
|
||||
} else if (isLoading || childrenCount > 0 || hasMore || !emptyMessage) {
|
||||
scrollableArea = (
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef} onMouseMove={this.handleMouseMove}>
|
||||
<div role='feed' className='item-list'>
|
||||
{prepend}
|
||||
|
||||
|
|
Loading…
Reference in New Issue