/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { useRef, useCallback } from 'react'; import type React from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import type { ConsoleMessageItem } from '../types.js'; import { ScrollableList, type ScrollableListRef, } from './shared/ScrollableList.js'; interface DetailedMessagesDisplayProps { messages: ConsoleMessageItem[]; maxHeight: number | undefined; width: number; hasFocus: boolean; } const iconBoxWidth = 3; export const DetailedMessagesDisplay: React.FC< DetailedMessagesDisplayProps > = ({ messages, maxHeight, width, hasFocus }) => { const scrollableListRef = useRef>(null); const borderAndPadding = 3; const estimatedItemHeight = useCallback( (index: number) => { const msg = messages[index]; if (!msg) { return 1; } const textWidth = width - borderAndPadding - iconBoxWidth; if (textWidth <= 0) { return 1; } const lines = Math.ceil((msg.content?.length || 1) / textWidth); return Math.max(1, lines); }, [width, messages], ); if (messages.length === 0) { return null; } return ( Debug Console (F12 to close) { let textColor = theme.text.primary; let icon = 'ℹ'; // Information source (ℹ) switch (msg.type) { case 'warn': textColor = theme.status.warning; icon = '⚠'; // Warning sign (⚠) break; case 'error': textColor = theme.status.error; icon = '✖'; // Heavy multiplication x (✖) break; case 'debug': textColor = theme.text.secondary; // Or theme.text.secondary icon = '🔍'; // Left-pointing magnifying glass (🔍) break; case 'log': default: // Default textColor and icon are already set break; } return ( {icon} {msg.content} {msg.count && msg.count > 1 && ( (x{msg.count}) )} ); }} keyExtractor={(item, index) => `${item.content}-${index}`} estimatedItemHeight={estimatedItemHeight} hasFocus={hasFocus} initialScrollIndex={Number.MAX_SAFE_INTEGER} /> ); };