[Glitch] Fix scroll-to-status in threaded view being unreliable

Port 6ccd9c2f1f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Claire
2025-11-18 17:20:50 +01:00
parent 126823986a
commit 8c725777ed
2 changed files with 32 additions and 27 deletions

View File

@@ -4,7 +4,7 @@
@typescript-eslint/no-unsafe-assignment */
import type { CSSProperties } from 'react';
import { useState, useRef, useCallback } from 'react';
import { useState, useRef, useCallback, useEffect } from 'react';
import { FormattedMessage } from 'react-intl';
@@ -57,6 +57,8 @@ export const DetailedStatus: React.FC<{
pictureInPicture: any;
onToggleHidden?: (status: any) => void;
onToggleMediaVisibility?: () => void;
ancestors?: number;
multiColumn?: boolean;
expanded: boolean;
}> = ({
status,
@@ -72,6 +74,8 @@ export const DetailedStatus: React.FC<{
pictureInPicture,
onToggleMediaVisibility,
onToggleHidden,
ancestors = 0,
multiColumn = false,
expanded,
}) => {
const properStatus = status?.get('reblog') ?? status;
@@ -136,6 +140,30 @@ export const DetailedStatus: React.FC<{
if (onTranslate) onTranslate(status);
}, [onTranslate, status]);
// The component is managed and will change if the status changes
// Ancestors can increase when loading a thread, in which case we want to scroll,
// or decrease if a post is deleted, in which case we don't want to mess with it
const previousAncestors = useRef(-1);
useEffect(() => {
if (nodeRef.current && previousAncestors.current < ancestors) {
nodeRef.current.scrollIntoView(true);
// In the single-column interface, `scrollIntoView` will put the post behind the header, so compensate for that.
if (!multiColumn) {
const offset = document
.querySelector('.column-header__wrapper')
?.getBoundingClientRect().bottom;
if (offset) {
const scrollingElement = document.scrollingElement ?? document.body;
scrollingElement.scrollBy(0, -offset);
}
}
}
previousAncestors.current = ancestors;
}, [ancestors, multiColumn]);
if (!properStatus) {
return null;
}

View File

@@ -162,7 +162,6 @@ class Status extends ImmutablePureComponent {
componentDidMount () {
attachFullscreenListener(this.onFullScreenChange);
this.props.dispatch(fetchStatus(this.props.params.statusId, { forceFetch: true }));
this._scrollStatusIntoView();
}
static getDerivedStateFromProps(props, state) {
@@ -512,35 +511,11 @@ class Status extends ImmutablePureComponent {
this.statusNode = c;
};
_scrollStatusIntoView () {
const { status, multiColumn } = this.props;
if (status) {
requestIdleCallback(() => {
this.statusNode?.scrollIntoView(true);
// In the single-column interface, `scrollIntoView` will put the post behind the header,
// so compensate for that.
if (!multiColumn) {
const offset = document.querySelector('.column-header__wrapper')?.getBoundingClientRect()?.bottom;
if (offset) {
const scrollingElement = document.scrollingElement || document.body;
scrollingElement.scrollBy(0, -offset);
}
}
});
}
}
componentDidUpdate (prevProps) {
const { status, ancestorsIds, descendantsIds } = this.props;
const { status, descendantsIds } = this.props;
const isSameStatus = status && (prevProps.status?.get('id') === status.get('id'));
if (status && (ancestorsIds.length > prevProps.ancestorsIds.length || !isSameStatus)) {
this._scrollStatusIntoView();
}
// Only highlight replies after the initial load
if (prevProps.descendantsIds.length && isSameStatus) {
const newRepliesIds = difference(descendantsIds, prevProps.descendantsIds);
@@ -653,6 +628,8 @@ class Status extends ImmutablePureComponent {
showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility}
pictureInPicture={pictureInPicture}
ancestors={this.props.ancestorsIds.length}
multiColumn={multiColumn}
/>
<ActionBar