feat(desktop): pure scroll-decision logic for new message list
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
// Pure, DOM-free scroll-decision logic for MessageList. Unit-tested so the
|
||||
// tricky math is verified without a browser (jsdom has no layout).
|
||||
|
||||
export interface ScrollMetrics {
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
clientHeight: number;
|
||||
}
|
||||
|
||||
/** Distance from the bottom edge is within `threshold` px. */
|
||||
export function isNearBottom(m: ScrollMetrics, threshold: number): boolean {
|
||||
return m.scrollHeight - (m.scrollTop + m.clientHeight) <= threshold;
|
||||
}
|
||||
|
||||
/** Scroll offset is within `threshold` px of the top. */
|
||||
export function isNearTop(m: ScrollMetrics, threshold: number): boolean {
|
||||
return m.scrollTop <= threshold;
|
||||
}
|
||||
|
||||
export interface SavedPosition {
|
||||
topmostIndex: number;
|
||||
stickToBottom: boolean;
|
||||
}
|
||||
|
||||
export interface Anchor {
|
||||
index: number;
|
||||
align: 'start' | 'end';
|
||||
}
|
||||
|
||||
/**
|
||||
* Where a freshly-opened chat should start.
|
||||
* - default / "left at bottom" → last row, aligned to the viewport bottom.
|
||||
* - "left scrolled up" → the saved top-most row, aligned to the viewport top
|
||||
* (clamped in case the cached row count shrank).
|
||||
*/
|
||||
export function resolveInitialAnchor(saved: SavedPosition | null, rowCount: number): Anchor {
|
||||
if (rowCount <= 0) return { index: 0, align: 'end' };
|
||||
if (saved && !saved.stickToBottom) {
|
||||
const index = Math.max(0, Math.min(saved.topmostIndex, rowCount - 1));
|
||||
return { index, align: 'start' };
|
||||
}
|
||||
return { index: rowCount - 1, align: 'end' };
|
||||
}
|
||||
Reference in New Issue
Block a user