Updated scrollable_list to use documentElement for (primary/only) scrolling functionality
added infinite scrolling, updated intersection observer, updates all components that send onScroll, onScrollTop props, removed div ref/setRef to this.node, removed all references to this.node
This commit is contained in:
parent
a6e80559ad
commit
a8bc9be5e7
@ -42,9 +42,9 @@ export default class ScrollableList extends PureComponent {
|
|||||||
scrollToTopOnMouseIdle = false;
|
scrollToTopOnMouseIdle = false;
|
||||||
|
|
||||||
setScrollTop = newScrollTop => {
|
setScrollTop = newScrollTop => {
|
||||||
if (this.node.scrollTop !== newScrollTop) {
|
if (this.documentElement.scrollTop !== newScrollTop) {
|
||||||
this.lastScrollWasSynthetic = true;
|
this.lastScrollWasSynthetic = true;
|
||||||
this.node.scrollTop = newScrollTop;
|
this.documentElement.scrollTop = newScrollTop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ export default class ScrollableList extends PureComponent {
|
|||||||
this.clearMouseIdleTimer();
|
this.clearMouseIdleTimer();
|
||||||
this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
|
this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
|
||||||
|
|
||||||
if (!this.mouseMovedRecently && this.node.scrollTop === 0) {
|
if (!this.mouseMovedRecently && this.documentElement.scrollTop === 0) {
|
||||||
// Only set if we just started moving and are scrolled to the top.
|
// Only set if we just started moving and are scrolled to the top.
|
||||||
this.scrollToTopOnMouseIdle = true;
|
this.scrollToTopOnMouseIdle = true;
|
||||||
}
|
}
|
||||||
@ -81,19 +81,25 @@ export default class ScrollableList extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
this.window = window;
|
||||||
|
this.documentElement = document.documentElement;
|
||||||
|
|
||||||
|
this.attachScrollListener();
|
||||||
this.attachIntersectionObserver();
|
this.attachIntersectionObserver();
|
||||||
|
// Handle initial scroll posiiton
|
||||||
|
this.handleScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
getScrollPosition = () => {
|
getScrollPosition = () => {
|
||||||
if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) {
|
if (this.documentElement && (this.documentElement.scrollTop > 0 || this.mouseMovedRecently)) {
|
||||||
return { height: this.node.scrollHeight, top: this.node.scrollTop };
|
return { height: this.documentElement.scrollHeight, top: this.documentElement.scrollTop };
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScrollBottom = (snapshot) => {
|
updateScrollBottom = (snapshot) => {
|
||||||
const newScrollTop = this.node.scrollHeight - snapshot;
|
const newScrollTop = this.documentElement.scrollHeight - snapshot;
|
||||||
|
|
||||||
this.setScrollTop(newScrollTop);
|
this.setScrollTop(newScrollTop);
|
||||||
}
|
}
|
||||||
@ -102,7 +108,61 @@ export default class ScrollableList extends PureComponent {
|
|||||||
// Reset the scroll position when a new child comes in in order not to
|
// Reset the scroll position when a new child comes in in order not to
|
||||||
// jerk the scrollbar around if you're already scrolled down the page.
|
// jerk the scrollbar around if you're already scrolled down the page.
|
||||||
if (snapshot !== null) {
|
if (snapshot !== null) {
|
||||||
this.setScrollTop(this.node.scrollHeight - snapshot);
|
this.setScrollTop(this.documentElement.scrollHeight - snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachScrollListener () {
|
||||||
|
this.window.addEventListener('scroll', this.handleScroll);
|
||||||
|
this.window.addEventListener('wheel', this.handleWheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
detachScrollListener () {
|
||||||
|
this.window.removeEventListener('scroll', this.handleScroll);
|
||||||
|
this.window.removeEventListener('wheel', this.handleWheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleScroll = throttle(() => {
|
||||||
|
if (this.window) {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = this.documentElement;
|
||||||
|
const offset = scrollHeight - scrollTop - clientHeight;
|
||||||
|
|
||||||
|
if (600 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) {
|
||||||
|
this.props.onLoadMore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollTop < 100 && this.props.onScrollToTop) {
|
||||||
|
this.props.onScrollToTop();
|
||||||
|
} else if (this.props.onScroll) {
|
||||||
|
this.props.onScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.lastScrollWasSynthetic) {
|
||||||
|
// If the last scroll wasn't caused by setScrollTop(), assume it was
|
||||||
|
// intentional and cancel any pending scroll reset on mouse idle
|
||||||
|
this.scrollToTopOnMouseIdle = false;
|
||||||
|
}
|
||||||
|
this.lastScrollWasSynthetic = false;
|
||||||
|
}
|
||||||
|
}, 150, {
|
||||||
|
trailing: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
handleWheel = throttle(() => {
|
||||||
|
this.scrollToTopOnMouseIdle = false;
|
||||||
|
}, 150, {
|
||||||
|
trailing: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
getSnapshotBeforeUpdate (prevProps) {
|
||||||
|
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.documentElement.scrollTop > 0 || this.mouseMovedRecently)) {
|
||||||
|
return this.documentElement.scrollHeight - this.documentElement.scrollTop;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +198,6 @@ export default class ScrollableList extends PureComponent {
|
|||||||
return firstChild && firstChild.key;
|
return firstChild && firstChild.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
setRef = (c) => {
|
|
||||||
this.node = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = e => {
|
handleLoadMore = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onLoadMore();
|
this.props.onLoadMore();
|
||||||
@ -158,7 +214,7 @@ export default class ScrollableList extends PureComponent {
|
|||||||
|
|
||||||
if (showLoading) {
|
if (showLoading) {
|
||||||
scrollableArea = (
|
scrollableArea = (
|
||||||
<div className='slist slist--flex' ref={this.setRef}>
|
<div className='slist slist--flex'>
|
||||||
<div role='feed' className='item-list'>
|
<div role='feed' className='item-list'>
|
||||||
{prepend}
|
{prepend}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user