LANCommander/LANCommander.UI/Components/InfiniteLoader/InfiniteScroll.ts
Pat Hartl 66abc6e59e Implement infinite loading with chat thread
- Chat messages are now loaded based on scroll position
- Read status is now updated and set by last message read
- Reworked script importing by using ScriptProvider
2026-01-11 14:38:24 -06:00

77 lines
No EOL
2.3 KiB
TypeScript

import { InfiniteScrollAnchor } from "./InfiniteScrollAnchor";
export class InfiniteScroll {
public scrollHost: Element;
public sentinel: Element;
public dotnet: any;
public static Create(dotnet: any, scrollHost: Element, sentinel: Element): InfiniteScroll {
return new InfiniteScroll(dotnet, scrollHost, sentinel);
}
constructor(dotnet: any, scrollHost: Element, sentinel: Element) {
this.dotnet = dotnet;
this.scrollHost = scrollHost;
this.sentinel = sentinel;
}
ObserveSentinel() {
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
this.dotnet.invokeMethodAsync("OnSentinelVisible");
}
}
}, {
root: this.scrollHost,
threshold: 0.01
});
observer.observe(this.sentinel);
}
CaptureAnchor(): InfiniteScrollAnchor {
const first = this.scrollHost.querySelector("[data-id]");
if (!first)
return null;
const rect = first.getBoundingClientRect();
const hostRect = this.scrollHost.getBoundingClientRect();
const anchor = new InfiniteScrollAnchor();
anchor.Id = first.getAttribute("data-id");
anchor.OffsetTop = rect.top - hostRect.top;
return anchor;
}
RestoreAfterPrepend(anchor: InfiniteScrollAnchor) {
if (!anchor)
return;
const el = this.scrollHost.querySelector(`[data-id="${anchor.Id}"]`);
if (!el)
return;
const rect = el.getBoundingClientRect();
const hostRect = this.scrollHost.getBoundingClientRect();
const newOffset = rect.top - hostRect.top;
this.scrollHost.scrollTop += (newOffset - anchor.OffsetTop);
}
IsSentinelVisible(): boolean {
const rect = this.sentinel.getBoundingClientRect();
const hostRect = this.scrollHost.getBoundingClientRect();
// Check if sentinel is within the visible area of the scroll host
return rect.top >= hostRect.top && rect.top <= hostRect.bottom;
}
ScrollToBottom() {
this.scrollHost.scrollTop = this.scrollHost.scrollHeight;
}
}