diff --git a/app/soapbox/components/scrollable_list.tsx b/app/soapbox/components/scrollable_list.tsx index 672520fa5..cc4b55867 100644 --- a/app/soapbox/components/scrollable_list.tsx +++ b/app/soapbox/components/scrollable_list.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Virtuoso, Components } from 'react-virtuoso'; +import { Virtuoso, Components, VirtuosoProps, VirtuosoHandle } from 'react-virtuoso'; import PullToRefresh from 'soapbox/components/pull-to-refresh'; import { useSettings } from 'soapbox/hooks'; @@ -25,7 +25,7 @@ const List: Components['List'] = React.forwardRef((props, ref) => { return
; }); -interface IScrollableList { +interface IScrollableList extends VirtuosoProps { scrollKey?: string, onLoadMore?: () => void, isLoading?: boolean, @@ -45,7 +45,7 @@ interface IScrollableList { } /** Legacy ScrollableList with Virtuoso for backwards-compatibility */ -const ScrollableList: React.FC = ({ +const ScrollableList = React.forwardRef(({ prepend = null, alwaysPrepend, children, @@ -61,7 +61,9 @@ const ScrollableList: React.FC = ({ hasMore, placeholderComponent: Placeholder, placeholderCount = 0, -}) => { + initialTopMostItemIndex = 0, + scrollerRef, +}, ref) => { const settings = useSettings(); const autoloadMore = settings.get('autoloadMore'); @@ -126,6 +128,7 @@ const ScrollableList: React.FC = ({ /** Render the actual Virtuoso list */ const renderFeed = (): JSX.Element => ( = ({ endReached={handleEndReached} isScrolling={isScrolling => isScrolling && onScroll && onScroll()} itemContent={renderItem} + initialTopMostItemIndex={showLoading ? 0 : initialTopMostItemIndex} context={{ listClassName: className, itemClassName, @@ -145,6 +149,7 @@ const ScrollableList: React.FC = ({ Item, Footer: loadMore, }} + scrollerRef={scrollerRef} /> ); @@ -162,6 +167,6 @@ const ScrollableList: React.FC = ({ {renderBody()} ); -}; +}); export default ScrollableList; diff --git a/app/soapbox/features/status/index.tsx b/app/soapbox/features/status/index.tsx index 25247ac6f..16c398df7 100644 --- a/app/soapbox/features/status/index.tsx +++ b/app/soapbox/features/status/index.tsx @@ -65,6 +65,7 @@ import ThreadStatus from './components/thread-status'; import type { AxiosError } from 'axios'; import type { History } from 'history'; +import type { VirtuosoHandle } from 'react-virtuoso'; import type { AnyAction } from 'redux'; import type { ThunkDispatch } from 'redux-thunk'; import type { RootState } from 'soapbox/store'; @@ -210,6 +211,7 @@ class Status extends ImmutablePureComponent { node: HTMLDivElement | null = null; status: HTMLDivElement | null = null; + scroller: VirtuosoHandle | null = null; _scrolledIntoView: boolean = false; fetchData = async() => { @@ -615,11 +617,10 @@ class Status extends ImmutablePureComponent { } componentDidUpdate(prevProps: IStatus, prevState: IStatusState) { - const { params, status, displayMedia } = this.props; - const { ancestorsIds } = prevProps; + const { params, status, displayMedia, ancestorsIds } = this.props; + const { isLoaded } = this.state; if (params.statusId !== prevProps.params.statusId) { - this._scrolledIntoView = false; this.fetchData(); } @@ -627,17 +628,11 @@ class Status extends ImmutablePureComponent { this.setState({ showMedia: defaultMediaVisibility(status, displayMedia), loadedStatusId: status.id }); } - if (this._scrolledIntoView) { - return; - } - - if (prevProps.status && ancestorsIds && ancestorsIds.size > 0 && this.node) { - const element = this.node.querySelector('.detailed-status'); - - window.requestAnimationFrame(() => { - element?.scrollIntoView(true); + if (params.statusId !== prevProps.params.statusId || status?.id !== prevProps.status?.id || ancestorsIds.size > prevProps.ancestorsIds.size || isLoaded !== prevState.isLoaded) { + this.scroller?.scrollToIndex({ + index: this.props.ancestorsIds.size, + offset: -80, }); - this._scrolledIntoView = true; } } @@ -671,6 +666,10 @@ class Status extends ImmutablePureComponent { })); } + setScrollerRef = (c: VirtuosoHandle) => { + this.scroller = c; + } + render() { const { me, status, ancestorsIds, descendantsIds, intl } = this.props; @@ -788,10 +787,12 @@ class Status extends ImmutablePureComponent {
} + initialTopMostItemIndex={ancestorsIds.size} > {children}