refactor(desktop): export VirtuosoRow type for MessageList
This commit is contained in:
@@ -84,7 +84,7 @@ import { clearDraft, getDraftSync, setDraft } from '../lib/composerDraftStore';
|
|||||||
// pending bubbles and the "load older" tile inside the same Virtuoso
|
// pending bubbles and the "load older" tile inside the same Virtuoso
|
||||||
// instance means scroll-to-bottom / followOutput stay coherent across both
|
// instance means scroll-to-bottom / followOutput stay coherent across both
|
||||||
// (we don't need a sibling scroll container for pending items).
|
// (we don't need a sibling scroll container for pending items).
|
||||||
type VirtuosoRow =
|
export type VirtuosoRow =
|
||||||
| { kind: 'loader'; key: string }
|
| { kind: 'loader'; key: string }
|
||||||
| { kind: 'message'; key: string; message: DecryptedMessage; idx: number }
|
| { kind: 'message'; key: string; message: DecryptedMessage; idx: number }
|
||||||
| { kind: 'pending'; key: string; item: OutboxItem };
|
| { kind: 'pending'; key: string; item: OutboxItem };
|
||||||
@@ -110,6 +110,21 @@ const EMPTY_REACTIONS: AggregatedReaction[] = [];
|
|||||||
// reading position even if some rows above re-render at different heights.
|
// reading position even if some rows above re-render at different heights.
|
||||||
const scrollPositions = new Map<string, { topmostIndex: number; stickToBottom: boolean }>();
|
const scrollPositions = new Map<string, { topmostIndex: number; stickToBottom: boolean }>();
|
||||||
|
|
||||||
|
// ── TEMP scroll-jank instrumentation ──────────────────────────────────────
|
||||||
|
// Flip SCROLL_DEBUG to false or delete this block once the chat-switch flicker
|
||||||
|
// is root-caused. Logs go to the devtools console AND window.__scrolllog (copy
|
||||||
|
// the whole run with: copy(window.__scrolllog.join('\n')) ).
|
||||||
|
const SCROLL_DEBUG = true;
|
||||||
|
const dbgNow = (): number => Math.round(performance.now());
|
||||||
|
const dbgLog = (line: string): void => {
|
||||||
|
if (!SCROLL_DEBUG) return;
|
||||||
|
const w = window as unknown as { __scrolllog?: string[] };
|
||||||
|
(w.__scrolllog ??= []).push(line);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(line);
|
||||||
|
};
|
||||||
|
// ──────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/** Pending composer attachment: the raw File plus the per-attachment
|
/** Pending composer attachment: the raw File plus the per-attachment
|
||||||
* view-once flag the user can toggle from the thumb hover button (P7.T4).
|
* view-once flag the user can toggle from the thumb hover button (P7.T4).
|
||||||
* Lives only in composer state — the flag is forwarded into
|
* Lives only in composer state — the flag is forwarded into
|
||||||
@@ -496,6 +511,18 @@ export function ConversationPage() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [virtuosoRows.length > 0]);
|
}, [virtuosoRows.length > 0]);
|
||||||
|
|
||||||
|
// SCROLL_DEBUG: log every render with the height-affecting inputs so the
|
||||||
|
// post-mount cascade (reactions/pins/receipts/divider/refresh) is visible.
|
||||||
|
useEffect(() => {
|
||||||
|
dbgLog(
|
||||||
|
`[scroll] render t=${dbgNow()} id=${(id ?? '').slice(0, 6)} loading=${loading}` +
|
||||||
|
` msgs=${messages.length} rows=${virtuosoRows.length}` +
|
||||||
|
` reactions=${reactionsByMessage.size} pins=${pins.length}` +
|
||||||
|
` firstUnread=${firstUnreadId ? 'set' : '-'}` +
|
||||||
|
` displayCount=${displayCount} initIdx=${JSON.stringify(initialTopMostIndex)}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const jumpToMessage = useCallback(
|
const jumpToMessage = useCallback(
|
||||||
(targetId: string) => {
|
(targetId: string) => {
|
||||||
const msgIdx = messages.findIndex((m) => m.id === targetId);
|
const msgIdx = messages.findIndex((m) => m.id === targetId);
|
||||||
@@ -702,6 +729,7 @@ export function ConversationPage() {
|
|||||||
// away counter when the user actually reaches the bottom.
|
// away counter when the user actually reaches the bottom.
|
||||||
const handleAtBottomStateChange = useCallback(
|
const handleAtBottomStateChange = useCallback(
|
||||||
(atBottom: boolean) => {
|
(atBottom: boolean) => {
|
||||||
|
dbgLog(`[scroll] atBottom=${atBottom} t=${dbgNow()}`);
|
||||||
setStickToBottom(atBottom);
|
setStickToBottom(atBottom);
|
||||||
if (atBottom) setNewMessagesWhileAway(0);
|
if (atBottom) setNewMessagesWhileAway(0);
|
||||||
if (id) {
|
if (id) {
|
||||||
@@ -720,6 +748,7 @@ export function ConversationPage() {
|
|||||||
// we only care about the start of the range here.
|
// we only care about the start of the range here.
|
||||||
const handleRangeChanged = useCallback(
|
const handleRangeChanged = useCallback(
|
||||||
(range: { startIndex: number; endIndex: number }) => {
|
(range: { startIndex: number; endIndex: number }) => {
|
||||||
|
dbgLog(`[scroll] range t=${dbgNow()} start=${range.startIndex} end=${range.endIndex}`);
|
||||||
topmostIndexRef.current = range.startIndex;
|
topmostIndexRef.current = range.startIndex;
|
||||||
if (id) {
|
if (id) {
|
||||||
const prev = scrollPositions.get(id);
|
const prev = scrollPositions.get(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user