MCPcopy Create free account
hub / github.com/Noumena-Network/code / VirtualMessageList

Function VirtualMessageList

src/components/VirtualMessageList.tsx:271–499  ·  view source on GitHub ↗
({
  messages,
  scrollRef,
  columns,
  itemKey,
  renderItem,
  onItemClick,
  isItemClickable,
  isItemExpanded,
  extractSearchText = defaultExtractSearchText,
  trackStickyPrompt,
  selectedIndex,
  cursorNavRef,
  setCursor,
  jumpRef,
  onSearchMatchesChange,
  scanElement,
  setPositions
}: Props)

Source from the content-addressed store, hash-verified

269 return t10;
270}
271export function VirtualMessageList({
272 messages,
273 scrollRef,
274 columns,
275 itemKey,
276 renderItem,
277 onItemClick,
278 isItemClickable,
279 isItemExpanded,
280 extractSearchText = defaultExtractSearchText,
281 trackStickyPrompt,
282 selectedIndex,
283 cursorNavRef,
284 setCursor,
285 jumpRef,
286 onSearchMatchesChange,
287 scanElement,
288 setPositions
289}: Props): React.ReactNode {
290 recordRenderTrace('VirtualMessageList');
291 const stickyPromptPredecessorRef = useRef<StickyPromptPredecessorState>();
292 // Incremental key array. Streaming appends one message at a time; rebuilding
293 // the full string array on every commit allocates O(n) per message (~1MB
294 // churn at 27k messages). Append-only delta push when the prefix matches;
295 // fall back to full rebuild on compaction, /clear, or itemKey change.
296 const keysRef = useRef<string[]>([]);
297 const prevMessagesRef = useRef<typeof messages>(messages);
298 const prevItemKeyRef = useRef(itemKey);
299 if (prevItemKeyRef.current !== itemKey || messages.length < keysRef.current.length || messages[0] !== prevMessagesRef.current[0]) {
300 keysRef.current = messages.map(m => itemKey(m));
301 } else {
302 for (let i = keysRef.current.length; i < messages.length; i++) {
303 keysRef.current.push(itemKey(messages[i]!));
304 }
305 }
306 prevMessagesRef.current = messages;
307 prevItemKeyRef.current = itemKey;
308 const keys = keysRef.current;
309 const stickyPromptPredecessors = useMemo(() => {
310 const next = computeStickyPromptPredecessors(messages, stickyPromptPredecessorRef.current);
311 stickyPromptPredecessorRef.current = next;
312 return next.previousStickyPromptIndex;
313 }, [messages]);
314 const estimatedHeightCacheRef = useRef(new Map<number, WeakMap<RenderableMessage, number>>());
315 const estimateItemHeight = useCallback((index: number) => {
316 const msg = messages[index];
317 if (!msg) return undefined;
318 let cacheByColumns = estimatedHeightCacheRef.current.get(columns);
319 if (!cacheByColumns) {
320 cacheByColumns = new WeakMap<RenderableMessage, number>();
321 estimatedHeightCacheRef.current.set(columns, cacheByColumns);
322 }
323 const cached = cacheByColumns.get(msg);
324 if (cached !== undefined) return cached;
325
326 // Transcript entry is the long-history hotspot. A cheap per-message row
327 // estimate is enough to avoid mounting a fixed 24-30 giant code-fence
328 // messages before Yoga has measured the tail.

Callers

nothing calls this directly

Calls 11

recordRenderTraceFunction · 0.85
estimateTextRowsFunction · 0.85
useVirtualScrollFunction · 0.85
recordLivePromptTraceFunction · 0.85
isNavigableMessageFunction · 0.85
setMethod · 0.80
scanFunction · 0.70
extractSearchTextFunction · 0.50
getMethod · 0.45

Tested by

no test coverage detected