chore: remove scroll jank investigation logging
This commit is contained in:
@@ -25,17 +25,6 @@ const AUTO_SCROLL_BOTTOM_THRESHOLD_PX = 64;
|
||||
const AUTO_SCROLL_RESUME_THRESHOLD_PX = 1;
|
||||
import { useWebElementScrollbar } from "./use-web-scrollbar";
|
||||
|
||||
function logWebStickyBottom(_event: string, _details: Record<string, unknown>): void {
|
||||
// Intentionally disabled: this path is too noisy during voice debugging.
|
||||
}
|
||||
|
||||
function getDebugNow(): number | null {
|
||||
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
||||
return Number(performance.now().toFixed(3));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isScrollContainerNearBottom(
|
||||
scrollContainer: Pick<HTMLElement, "scrollTop" | "clientHeight" | "scrollHeight">,
|
||||
thresholdPx = AUTO_SCROLL_BOTTOM_THRESHOLD_PX,
|
||||
@@ -92,36 +81,6 @@ function isScrollContainerOverscrolledPastBottom(
|
||||
return getScrollContainerDistanceFromBottom(scrollContainer) < 0;
|
||||
}
|
||||
|
||||
const VIEWPORT_LOG_PREFIX = "[WebStreamViewport]";
|
||||
|
||||
function vlog(agentId: string, event: string, details: Record<string, unknown> = {}): void {
|
||||
console.log(VIEWPORT_LOG_PREFIX, agentId, event, details);
|
||||
}
|
||||
|
||||
function useRenderTracker(
|
||||
label: string,
|
||||
agentId: string,
|
||||
watched: Record<string, unknown>,
|
||||
): number {
|
||||
const renderCountRef = useRef(0);
|
||||
const prevRef = useRef<Record<string, unknown> | null>(null);
|
||||
renderCountRef.current += 1;
|
||||
const changed: string[] = [];
|
||||
if (prevRef.current !== null) {
|
||||
for (const key of Object.keys(watched)) {
|
||||
if (!Object.is(prevRef.current[key], watched[key])) {
|
||||
changed.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
prevRef.current = { ...watched };
|
||||
console.log(VIEWPORT_LOG_PREFIX, agentId, `${label} render #${renderCountRef.current}`, {
|
||||
isFirst: renderCountRef.current === 1,
|
||||
changed,
|
||||
});
|
||||
return renderCountRef.current;
|
||||
}
|
||||
|
||||
function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: boolean }) {
|
||||
const {
|
||||
segments,
|
||||
@@ -135,26 +94,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
scrollEnabled,
|
||||
isMobileBreakpoint,
|
||||
} = props;
|
||||
useRenderTracker("WebStreamViewport", props.agentId, {
|
||||
agentId: props.agentId,
|
||||
segments,
|
||||
"segments.historyMounted": segments.historyMounted,
|
||||
"segments.historyVirtualized": segments.historyVirtualized,
|
||||
"segments.liveHead": segments.liveHead,
|
||||
boundary,
|
||||
renderers,
|
||||
"renderers.renderHistoryMountedRow": renderers.renderHistoryMountedRow,
|
||||
"renderers.renderHistoryVirtualizedRow": renderers.renderHistoryVirtualizedRow,
|
||||
"renderers.renderLiveHeadRow": renderers.renderLiveHeadRow,
|
||||
"renderers.renderLiveAuxiliary": renderers.renderLiveAuxiliary,
|
||||
listEmptyComponent,
|
||||
viewportRef,
|
||||
routeBottomAnchorRequest,
|
||||
isAuthoritativeHistoryReady,
|
||||
onNearBottomChange,
|
||||
scrollEnabled,
|
||||
isMobileBreakpoint,
|
||||
});
|
||||
const scrollContainerRef = useRef<HTMLElement | null>(null);
|
||||
const contentRef = useRef<HTMLElement | null>(null);
|
||||
const handleScrollContainerRef = useCallback((node: HTMLElement | null) => {
|
||||
@@ -170,13 +109,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
};
|
||||
const followOutputRef = useRef(followOutput);
|
||||
const lastKnownScrollTopRef = useRef(0);
|
||||
const lastLoggedMetricsRef = useRef<{
|
||||
scrollTop: number;
|
||||
clientWidth: number;
|
||||
clientHeight: number;
|
||||
scrollWidth: number;
|
||||
scrollHeight: number;
|
||||
} | null>(null);
|
||||
const pendingUserScrollUpIntentRef = useRef(false);
|
||||
const isPointerScrollActiveRef = useRef(false);
|
||||
const lastTouchClientYRef = useRef<number | null>(null);
|
||||
@@ -214,28 +146,16 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
overscan: 8,
|
||||
});
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:virtualizer-adjust setup fired", {});
|
||||
rowVirtualizer.shouldAdjustScrollPositionOnItemSizeChange = (_item, _delta, instance) => {
|
||||
const viewportHeight = instance.scrollRect?.height ?? 0;
|
||||
const scrollOffset = instance.scrollOffset ?? 0;
|
||||
const remainingDistance = instance.getTotalSize() - (scrollOffset + viewportHeight);
|
||||
logWebStickyBottom("virtualizer_item_size_change", {
|
||||
agentId: props.agentId,
|
||||
delta: _delta,
|
||||
itemIndex: _item.index,
|
||||
itemStart: _item.start,
|
||||
itemSize: _item.size,
|
||||
viewportHeight,
|
||||
scrollOffset,
|
||||
totalSize: instance.getTotalSize(),
|
||||
remainingDistance,
|
||||
});
|
||||
return remainingDistance > AUTO_SCROLL_BOTTOM_THRESHOLD_PX;
|
||||
};
|
||||
return () => {
|
||||
rowVirtualizer.shouldAdjustScrollPositionOnItemSizeChange = undefined;
|
||||
};
|
||||
}, [rowVirtualizer, props.agentId]);
|
||||
}, [rowVirtualizer]);
|
||||
const virtualRows = rowVirtualizer.getVirtualItems();
|
||||
const virtualTotalSize = rowVirtualizer.getTotalSize();
|
||||
|
||||
@@ -293,21 +213,11 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
if (isScrollContainerOverscrolledPastBottom(scrollContainer)) {
|
||||
return;
|
||||
}
|
||||
logWebStickyBottom("viewport_scroll_to_bottom", {
|
||||
agentId: props.agentId,
|
||||
behavior,
|
||||
followOutput: followOutputRef.current,
|
||||
scrollTop: scrollContainer.scrollTop,
|
||||
clientWidth: scrollContainer.clientWidth,
|
||||
clientHeight: scrollContainer.clientHeight,
|
||||
scrollWidth: scrollContainer.scrollWidth,
|
||||
scrollHeight: scrollContainer.scrollHeight,
|
||||
});
|
||||
scrollElementToBottom(scrollContainer, behavior);
|
||||
lastKnownScrollTopRef.current = scrollContainer.scrollTop;
|
||||
syncNearBottom(scrollContainer, onNearBottomChange);
|
||||
},
|
||||
[onNearBottomChange, props.agentId],
|
||||
[onNearBottomChange],
|
||||
);
|
||||
|
||||
const scheduleStickToBottom = useCallback(() => {
|
||||
@@ -318,15 +228,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
if (pendingAutoScrollFrameRef.current !== null) {
|
||||
return;
|
||||
}
|
||||
logWebStickyBottom("viewport_schedule_stick_to_bottom", {
|
||||
agentId: props.agentId,
|
||||
followOutput: followOutputRef.current,
|
||||
scrollTop: scrollContainer?.scrollTop ?? null,
|
||||
clientWidth: scrollContainer?.clientWidth ?? null,
|
||||
clientHeight: scrollContainer?.clientHeight ?? null,
|
||||
scrollWidth: scrollContainer?.scrollWidth ?? null,
|
||||
scrollHeight: scrollContainer?.scrollHeight ?? null,
|
||||
});
|
||||
pendingAutoScrollFrameRef.current = window.requestAnimationFrame(() => {
|
||||
pendingAutoScrollFrameRef.current = null;
|
||||
if (!followOutputRef.current) {
|
||||
@@ -334,7 +235,7 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
}
|
||||
scrollMessagesToBottom("auto");
|
||||
});
|
||||
}, [props.agentId, scrollMessagesToBottom]);
|
||||
}, [scrollMessagesToBottom]);
|
||||
|
||||
const forceStickToBottom = useCallback(() => {
|
||||
cancelPendingStickToBottom();
|
||||
@@ -349,31 +250,7 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
return;
|
||||
}
|
||||
syncNearBottom(scrollContainer, onNearBottomChange);
|
||||
const currentMetrics = {
|
||||
scrollTop: scrollContainer.scrollTop,
|
||||
clientWidth: scrollContainer.clientWidth,
|
||||
clientHeight: scrollContainer.clientHeight,
|
||||
scrollWidth: scrollContainer.scrollWidth,
|
||||
scrollHeight: scrollContainer.scrollHeight,
|
||||
};
|
||||
const previousMetrics = lastLoggedMetricsRef.current;
|
||||
const shouldLog =
|
||||
!previousMetrics ||
|
||||
previousMetrics.scrollTop !== currentMetrics.scrollTop ||
|
||||
previousMetrics.clientWidth !== currentMetrics.clientWidth ||
|
||||
previousMetrics.clientHeight !== currentMetrics.clientHeight ||
|
||||
previousMetrics.scrollWidth !== currentMetrics.scrollWidth ||
|
||||
previousMetrics.scrollHeight !== currentMetrics.scrollHeight;
|
||||
if (shouldLog) {
|
||||
lastLoggedMetricsRef.current = currentMetrics;
|
||||
logWebStickyBottom("viewport_metrics_updated", {
|
||||
agentId: props.agentId,
|
||||
followOutput: followOutputRef.current,
|
||||
distanceFromBottom: getScrollContainerDistanceFromBottom(scrollContainer),
|
||||
...currentMetrics,
|
||||
});
|
||||
}
|
||||
}, [onNearBottomChange, props.agentId]);
|
||||
}, [onNearBottomChange]);
|
||||
|
||||
const handleDomScroll = useCallback(() => {
|
||||
const scrollContainer = scrollContainerRef.current;
|
||||
@@ -402,26 +279,10 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
}
|
||||
|
||||
lastKnownScrollTopRef.current = currentScrollTop;
|
||||
logWebStickyBottom("viewport_dom_scroll", {
|
||||
agentId: props.agentId,
|
||||
now: getDebugNow(),
|
||||
scrollTop: currentScrollTop,
|
||||
clientHeight: scrollContainer.clientHeight,
|
||||
scrollHeight: scrollContainer.scrollHeight,
|
||||
activeElementTag:
|
||||
typeof document !== "undefined"
|
||||
? (document.activeElement?.tagName?.toLowerCase() ?? null)
|
||||
: null,
|
||||
activeElementRole:
|
||||
typeof document !== "undefined"
|
||||
? (document.activeElement?.getAttribute?.("aria-label") ?? null)
|
||||
: null,
|
||||
});
|
||||
updateScrollMetrics();
|
||||
}, [cancelPendingStickToBottom, updateScrollMetrics, props.agentId]);
|
||||
}, [cancelPendingStickToBottom, updateScrollMetrics]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
vlog(props.agentId, "effect:activation-reset fired", { activationKey, isActivationReady });
|
||||
if (!isActivationReady) {
|
||||
return;
|
||||
}
|
||||
@@ -443,12 +304,9 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
return () => {
|
||||
window.clearTimeout(timeout);
|
||||
};
|
||||
}, [activationKey, forceStickToBottom, isActivationReady, scheduleStickToBottom, props.agentId]);
|
||||
}, [activationKey, forceStickToBottom, isActivationReady, scheduleStickToBottom]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:stick-on-segments-change fired", {
|
||||
followOutput: followOutputRef.current,
|
||||
});
|
||||
if (!followOutputRef.current) {
|
||||
return;
|
||||
}
|
||||
@@ -458,28 +316,16 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
segments.historyMounted,
|
||||
segments.historyVirtualized,
|
||||
segments.liveHead,
|
||||
props.agentId,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:stick-on-virtual-total fired", {
|
||||
followOutput: followOutputRef.current,
|
||||
shouldUseVirtualizer,
|
||||
virtualTotalSize,
|
||||
});
|
||||
if (!followOutputRef.current || !shouldUseVirtualizer) {
|
||||
return;
|
||||
}
|
||||
scheduleStickToBottom();
|
||||
}, [scheduleStickToBottom, shouldUseVirtualizer, virtualTotalSize, props.agentId]);
|
||||
}, [scheduleStickToBottom, shouldUseVirtualizer, virtualTotalSize]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:metrics-on-segments-change fired", {
|
||||
mounted: segments.historyMounted.length,
|
||||
virtualized: segments.historyVirtualized.length,
|
||||
liveHead: segments.liveHead.length,
|
||||
virtualTotalSize,
|
||||
});
|
||||
updateScrollMetrics();
|
||||
}, [
|
||||
segments.historyMounted.length,
|
||||
@@ -487,11 +333,9 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
segments.liveHead.length,
|
||||
updateScrollMetrics,
|
||||
virtualTotalSize,
|
||||
props.agentId,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:resize-observer setup fired", {});
|
||||
const scrollContainer = scrollContainerRef.current;
|
||||
const contentNode = contentRef.current;
|
||||
if (!scrollContainer || typeof ResizeObserver === "undefined") {
|
||||
@@ -500,15 +344,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
|
||||
updateScrollMetrics();
|
||||
const observer = new ResizeObserver(() => {
|
||||
logWebStickyBottom("viewport_resize_observed", {
|
||||
agentId: props.agentId,
|
||||
followOutput: followOutputRef.current,
|
||||
scrollTop: scrollContainer.scrollTop,
|
||||
clientWidth: scrollContainer.clientWidth,
|
||||
clientHeight: scrollContainer.clientHeight,
|
||||
scrollWidth: scrollContainer.scrollWidth,
|
||||
scrollHeight: scrollContainer.scrollHeight,
|
||||
});
|
||||
updateScrollMetrics();
|
||||
if (!followOutputRef.current) {
|
||||
return;
|
||||
@@ -522,68 +357,14 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [props.agentId, scheduleStickToBottom, updateScrollMetrics]);
|
||||
}, [scheduleStickToBottom, updateScrollMetrics]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:scroll-listeners setup fired", {});
|
||||
const scrollContainer = scrollContainerRef.current;
|
||||
if (!scrollContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalScrollTo = scrollContainer.scrollTo.bind(scrollContainer);
|
||||
const scrollTopDescriptor =
|
||||
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(scrollContainer), "scrollTop") ??
|
||||
Object.getOwnPropertyDescriptor(Element.prototype, "scrollTop");
|
||||
scrollContainer.scrollTo = ((...args: Parameters<HTMLElement["scrollTo"]>) => {
|
||||
const firstArg = args[0] as ScrollToOptions | number | undefined;
|
||||
const target =
|
||||
typeof firstArg === "object" && firstArg !== null
|
||||
? {
|
||||
top: firstArg.top ?? null,
|
||||
left: firstArg.left ?? null,
|
||||
behavior: firstArg.behavior ?? null,
|
||||
}
|
||||
: {
|
||||
top: typeof args[1] === "number" ? args[1] : null,
|
||||
left: typeof firstArg === "number" ? firstArg : null,
|
||||
behavior: null,
|
||||
};
|
||||
logWebStickyBottom("viewport_scroll_to_called", {
|
||||
agentId: props.agentId,
|
||||
now: getDebugNow(),
|
||||
currentScrollTop: scrollContainer.scrollTop,
|
||||
target,
|
||||
stack:
|
||||
typeof Error !== "undefined"
|
||||
? (new Error().stack?.split("\n").slice(1, 6).join("\n") ?? null)
|
||||
: null,
|
||||
});
|
||||
return originalScrollTo(...args);
|
||||
}) as typeof scrollContainer.scrollTo;
|
||||
if (scrollTopDescriptor?.get && scrollTopDescriptor?.set) {
|
||||
Object.defineProperty(scrollContainer, "scrollTop", {
|
||||
configurable: true,
|
||||
enumerable: scrollTopDescriptor.enumerable ?? false,
|
||||
get() {
|
||||
return scrollTopDescriptor.get?.call(scrollContainer);
|
||||
},
|
||||
set(value: number) {
|
||||
logWebStickyBottom("viewport_scroll_top_set", {
|
||||
agentId: props.agentId,
|
||||
now: getDebugNow(),
|
||||
currentScrollTop: scrollTopDescriptor.get?.call(scrollContainer) ?? null,
|
||||
nextScrollTop: value,
|
||||
stack:
|
||||
typeof Error !== "undefined"
|
||||
? (new Error().stack?.split("\n").slice(1, 6).join("\n") ?? null)
|
||||
: null,
|
||||
});
|
||||
return scrollTopDescriptor.set?.call(scrollContainer, value);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const handleWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY < 0) {
|
||||
pendingUserScrollUpIntentRef.current = true;
|
||||
@@ -618,27 +399,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
const handleTouchEnd = () => {
|
||||
lastTouchClientYRef.current = null;
|
||||
};
|
||||
const handleSelectionChange = () => {
|
||||
const activeElement =
|
||||
typeof document !== "undefined"
|
||||
? (document.activeElement as HTMLTextAreaElement | null)
|
||||
: null;
|
||||
logWebStickyBottom("document_selection_changed", {
|
||||
agentId: props.agentId,
|
||||
now: getDebugNow(),
|
||||
activeElementTag: activeElement?.tagName?.toLowerCase() ?? null,
|
||||
activeElementRole: activeElement?.getAttribute?.("aria-label") ?? null,
|
||||
selectionStart:
|
||||
activeElement && typeof activeElement.selectionStart === "number"
|
||||
? activeElement.selectionStart
|
||||
: null,
|
||||
selectionEnd:
|
||||
activeElement && typeof activeElement.selectionEnd === "number"
|
||||
? activeElement.selectionEnd
|
||||
: null,
|
||||
scrollTop: scrollContainer.scrollTop,
|
||||
});
|
||||
};
|
||||
|
||||
scrollContainer.addEventListener("scroll", handleDomScroll, { passive: true });
|
||||
scrollContainer.addEventListener("wheel", handleWheel, { passive: true });
|
||||
@@ -649,9 +409,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
scrollContainer.addEventListener("touchmove", handleTouchMove, { passive: true });
|
||||
scrollContainer.addEventListener("touchend", handleTouchEnd, { passive: true });
|
||||
scrollContainer.addEventListener("touchcancel", handleTouchEnd, { passive: true });
|
||||
if (typeof document !== "undefined") {
|
||||
document.addEventListener("selectionchange", handleSelectionChange, { passive: true });
|
||||
}
|
||||
|
||||
return () => {
|
||||
scrollContainer.removeEventListener("scroll", handleDomScroll);
|
||||
@@ -663,18 +420,10 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
scrollContainer.removeEventListener("touchmove", handleTouchMove);
|
||||
scrollContainer.removeEventListener("touchend", handleTouchEnd);
|
||||
scrollContainer.removeEventListener("touchcancel", handleTouchEnd);
|
||||
scrollContainer.scrollTo = originalScrollTo;
|
||||
if (scrollTopDescriptor) {
|
||||
Reflect.deleteProperty(scrollContainer, "scrollTop");
|
||||
}
|
||||
if (typeof document !== "undefined") {
|
||||
document.removeEventListener("selectionchange", handleSelectionChange);
|
||||
}
|
||||
};
|
||||
}, [cancelPendingStickToBottom, handleDomScroll, props.agentId]);
|
||||
}, [cancelPendingStickToBottom, handleDomScroll]);
|
||||
|
||||
useEffect(() => {
|
||||
vlog(props.agentId, "effect:viewportRef-handle setup fired", {});
|
||||
const handle: StreamViewportHandle = {
|
||||
scrollToBottom: () => {
|
||||
setFollowOutput(true);
|
||||
@@ -685,16 +434,6 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
if (!followOutputRef.current) {
|
||||
return;
|
||||
}
|
||||
const scrollContainer = scrollContainerRef.current;
|
||||
logWebStickyBottom("viewport_prepare_for_change", {
|
||||
agentId: props.agentId,
|
||||
followOutput: followOutputRef.current,
|
||||
scrollTop: scrollContainer?.scrollTop ?? null,
|
||||
clientWidth: scrollContainer?.clientWidth ?? null,
|
||||
clientHeight: scrollContainer?.clientHeight ?? null,
|
||||
scrollWidth: scrollContainer?.scrollWidth ?? null,
|
||||
scrollHeight: scrollContainer?.scrollHeight ?? null,
|
||||
});
|
||||
scheduleStickToBottom();
|
||||
},
|
||||
};
|
||||
@@ -705,16 +444,9 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
}
|
||||
cancelPendingStickToBottom();
|
||||
};
|
||||
}, [
|
||||
cancelPendingStickToBottom,
|
||||
forceStickToBottom,
|
||||
props.agentId,
|
||||
scheduleStickToBottom,
|
||||
viewportRef,
|
||||
]);
|
||||
}, [cancelPendingStickToBottom, forceStickToBottom, scheduleStickToBottom, viewportRef]);
|
||||
|
||||
const contentContainerStyle = useMemo((): CSSProperties => {
|
||||
vlog(props.agentId, "memo:contentContainerStyle rebuilt", { isMobileBreakpoint });
|
||||
return {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
@@ -725,9 +457,8 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
paddingRight: isMobileBreakpoint ? 8 : 16,
|
||||
boxSizing: "border-box",
|
||||
};
|
||||
}, [isMobileBreakpoint, props.agentId]);
|
||||
}, [isMobileBreakpoint]);
|
||||
const scrollContainerStyle = useMemo((): CSSProperties => {
|
||||
vlog(props.agentId, "memo:scrollContainerStyle rebuilt", { scrollEnabled });
|
||||
return {
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
@@ -735,15 +466,14 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
overflowY: scrollEnabled ? "auto" : "hidden",
|
||||
overscrollBehaviorY: "contain",
|
||||
};
|
||||
}, [scrollEnabled, props.agentId]);
|
||||
}, [scrollEnabled]);
|
||||
const virtualRowsContainerStyle = useMemo((): CSSProperties => {
|
||||
vlog(props.agentId, "memo:virtualRowsContainerStyle rebuilt", { virtualTotalSize });
|
||||
return {
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: virtualTotalSize,
|
||||
};
|
||||
}, [virtualTotalSize, props.agentId]);
|
||||
}, [virtualTotalSize]);
|
||||
const renderVirtualRowStyle = useCallback(
|
||||
(start: number): CSSProperties => ({
|
||||
position: "absolute",
|
||||
@@ -757,40 +487,26 @@ function WebStreamViewport(props: StreamRenderInput & { isMobileBreakpoint: bool
|
||||
[],
|
||||
);
|
||||
const mountedHistoryRows = useMemo(() => {
|
||||
vlog(props.agentId, "memo:mountedHistoryRows rebuilt", {
|
||||
count: segments.historyMounted.length,
|
||||
});
|
||||
return segments.historyMounted.map((item, index) => (
|
||||
<Fragment key={item.id}>
|
||||
{renderHistoryMountedRow(item, index, segments.historyMounted)}
|
||||
</Fragment>
|
||||
));
|
||||
}, [renderHistoryMountedRow, segments.historyMounted, props.agentId]);
|
||||
}, [renderHistoryMountedRow, segments.historyMounted]);
|
||||
const liveHeadRows = useMemo(() => {
|
||||
vlog(props.agentId, "memo:liveHeadRows rebuilt", { count: segments.liveHead.length });
|
||||
return segments.liveHead.map((item, index) => (
|
||||
<Fragment key={item.id}>{renderLiveHeadRow(item, index, segments.liveHead)}</Fragment>
|
||||
));
|
||||
}, [renderLiveHeadRow, segments.liveHead, props.agentId]);
|
||||
}, [renderLiveHeadRow, segments.liveHead]);
|
||||
const liveAuxiliary = useMemo(() => {
|
||||
vlog(props.agentId, "memo:liveAuxiliary rebuilt", {});
|
||||
return renderLiveAuxiliary();
|
||||
}, [renderLiveAuxiliary, props.agentId]);
|
||||
}, [renderLiveAuxiliary]);
|
||||
const shouldRenderEmpty =
|
||||
!boundary.hasMountedHistory &&
|
||||
!boundary.hasVirtualizedHistory &&
|
||||
!boundary.hasLiveHead &&
|
||||
!liveAuxiliary;
|
||||
|
||||
vlog(props.agentId, "render summary", {
|
||||
virtualRowsRendered: virtualRows.length,
|
||||
mountedHistoryRowsRendered: segments.historyMounted.length,
|
||||
liveHeadRowsRendered: segments.liveHead.length,
|
||||
shouldUseVirtualizer,
|
||||
virtualTotalSize,
|
||||
shouldRenderEmpty,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user