diff --git a/ts/components/conversation/Message.dom.tsx b/ts/components/conversation/Message.dom.tsx index 688f841ee3..d75ede8c1e 100644 --- a/ts/components/conversation/Message.dom.tsx +++ b/ts/components/conversation/Message.dom.tsx @@ -1021,7 +1021,7 @@ export class Message extends React.PureComponent { this.setState(({ metadataWidth }) => ({ // We don't want text to jump around if the metadata shrinks, but we want to make // sure we have enough room. - metadataWidth: Math.max(metadataWidth, newMetadataWidth), + metadataWidth: Math.ceil(Math.max(metadataWidth, newMetadataWidth)), })); }; diff --git a/ts/components/conversation/Timeline.dom.tsx b/ts/components/conversation/Timeline.dom.tsx index 35c76e77fd..45156715e0 100644 --- a/ts/components/conversation/Timeline.dom.tsx +++ b/ts/components/conversation/Timeline.dom.tsx @@ -281,7 +281,7 @@ export class Timeline extends React.Component< this.#messagesRef.current ?.querySelector(`[data-item-index="${itemIndex}"]`) - ?.scrollIntoViewIfNeeded(); + ?.scrollIntoView({ block: 'center' }); } #scrollToBottom = (setFocus?: boolean): void => { @@ -532,6 +532,7 @@ export class Timeline extends React.Component< const atBottomDetectorEl = this.#atBottomDetectorRef.current; let centerMessageId: undefined | string; + let centerMessageRelativeTop = 0; for (const [element, intersectionRatio] of this.#intersectionRatios) { if (intersectionRatio === 0) { continue; @@ -548,8 +549,13 @@ export class Timeline extends React.Component< const relativeTop = element.getBoundingClientRect().top - containerElRectTop; - if (!centerMessageId || relativeTop < containerElMidline) { + if ( + !centerMessageId || + (relativeTop > centerMessageRelativeTop && + relativeTop < containerElMidline) + ) { centerMessageId = messageId; + centerMessageRelativeTop = relativeTop; } } @@ -728,7 +734,12 @@ export class Timeline extends React.Component< ); } } else if ('scrollToIndex' in snapshot) { - this.#scrollToItemIndex(snapshot.scrollToIndex); + // Wait to scroll until after another render has completed, to allow for message + // sizes to measured & stabilize + this.setState( + state => state, + () => this.#scrollToItemIndex(snapshot.scrollToIndex) + ); } else if ('scrollTop' in snapshot) { containerEl.scrollTop = snapshot.scrollTop; } else {