1- import React , { useCallback } from 'react' ;
1+ import React , { useCallback , useEffect , useRef } from 'react' ;
22import styled from 'styled-components' ;
33import { useSelector } from 'react-redux' ;
44import { useTheme } from '../hooks/useTheme' ;
@@ -11,48 +11,28 @@ import Prism from 'prismjs';
1111
1212export const expandMessageReferences = ( content : string , messages : Message [ ] ) : string => {
1313 if ( ! content ) return '' ;
14- // Create a temporary div to parse HTML content
1514 const tempDiv = document . createElement ( 'div' ) ;
1615 tempDiv . innerHTML = content ;
17- // Helper to highlight code blocks in content
18- const highlightCodeBlocks = ( element : HTMLElement ) => {
19- const codeBlocks = element . querySelectorAll ( 'pre code' ) ;
20- codeBlocks . forEach ( block => {
21- if ( block instanceof HTMLElement ) {
22- Prism . highlightElement ( block ) ;
23- }
24- } ) ;
25- } ;
26- // Process all elements with IDs that match message references
2716 const processNode = ( node : HTMLElement ) => {
2817 const messageID = node . getAttribute ( "message-id" ) ;
2918 if ( messageID ) {
30- // if(node.getAttribute("filled") === "true") {
31- // logger.debug('Skipping filled node', {id: node.id});
32- // return;
33- // }
3419 if ( messageID ?. startsWith ( 'z' ) ) {
3520 const referencedMessage = messages . find ( m => m . id === messageID ) ;
3621 if ( referencedMessage ) {
3722 logger . debug ( 'Expanding referenced message' , { id : messageID , contentLength : referencedMessage . content . length } ) ;
3823 node . innerHTML = expandMessageReferences ( referencedMessage . content , messages ) ;
39- node . setAttribute ( "filled" , "true" ) ;
40- highlightCodeBlocks ( node ) ;
4124 } else {
4225 logger . debug ( 'Referenced message not found' , { id : node . id } ) ;
4326 }
4427 }
4528 }
46- // Recursively process child elements
4729 Array . from ( node . children ) . forEach ( child => {
4830 if ( child instanceof HTMLElement ) {
4931 processNode ( child ) ;
5032 }
5133 } ) ;
5234 } ;
53- // logger.debug('Expanding message references', {content});
5435 processNode ( tempDiv ) ;
55- highlightCodeBlocks ( tempDiv ) ;
5636 return tempDiv . innerHTML ;
5737} ;
5838
@@ -85,8 +65,7 @@ const MessageContent = styled.div`
8565 color: var(--theme-text);
8666 font-family: var(--theme-code-font);
8767 }
88-
89-
68+
9069 .href-link, .play-button, .regen-button, .cancel-button, .text-submit-button {
9170 cursor: pointer;
9271 user-select: none;
@@ -119,8 +98,6 @@ const MessageContent = styled.div`
11998 }
12099 }
121100
122- /* Style code blocks according to theme */
123-
124101 pre[class*="language-"] {
125102 background: ${ ( { theme} ) => theme . colors . surface } ;
126103 margin: 1em 0;
@@ -137,8 +114,6 @@ const MessageContent = styled.div`
137114 font-family: ${ ( { theme} ) => theme . typography . console . fontFamily } ;
138115 }
139116
140- /* Style inline code differently from code blocks */
141-
142117 :not(pre) > code {
143118 background: ${ ( { theme} ) => theme . colors . surface } ;
144119 color: ${ ( { theme} ) => theme . colors . text . primary } ;
@@ -150,14 +125,12 @@ const MessageContent = styled.div`
150125` ;
151126
152127const extractMessageAction = ( target : HTMLElement ) : { messageId : string | undefined , action : string | undefined } => {
153- // Check for data attributes
154128 const messageId = target . getAttribute ( 'data-message-id' ) ??
155129 target . getAttribute ( 'data-id' ) ??
156130 undefined ;
157131 let action = target . getAttribute ( 'data-message-action' ) ??
158132 target . getAttribute ( 'data-action' ) ??
159133 undefined ;
160- // Check element classes
161134 if ( ! action ) {
162135 if ( target . classList . contains ( 'href-link' ) ) action = 'link' ;
163136 else if ( target . classList . contains ( 'play-button' ) ) action = 'run' ;
@@ -249,29 +222,27 @@ const MessageList: React.FC<MessageListProps> = ({messages: propMessages}) => {
249222 const storeMessages = useSelector ( ( state : RootState ) => state . messages . messages ) ;
250223 const messages = Array . isArray ( propMessages ) ? propMessages :
251224 Array . isArray ( storeMessages ) ? storeMessages : [ ] ;
252-
253- // Memoize message processing
254- const memoizedProcessMessageContent = React . useMemo ( ( ) => {
255- return ( content : string ) => {
256- if ( ! content ) return '' ;
257- return expandMessageReferences ( content , messages ) ;
258- } ;
259- } , [ messages ] ) ;
260-
261- // Optimize message filtering
262- const filteredMessages = React . useMemo ( ( ) => {
263- return messages
264- . filter ( ( message ) => message . id && ! message . id . startsWith ( "z" ) )
265- . filter ( ( message ) => message . content ?. length > 0 ) ;
266- } , [ messages ] ) ;
267- const theme = useTheme ( ) ;
225+ const messageListRef = useRef < HTMLDivElement > ( null ) ;
226+
227+ // Effect to handle syntax highlighting after render
228+ useEffect ( ( ) => {
229+ if ( messageListRef . current ) {
230+ const codeBlocks = messageListRef . current . querySelectorAll ( 'pre code' ) ;
231+ logger . debug ( 'Highlighting code blocks:' , { count : codeBlocks . length } ) ;
232+ codeBlocks . forEach ( block => {
233+ Prism . highlightElement ( block ) ;
234+ } ) ;
235+ }
236+ } , [ messages ] ) ; // Re-run when messages change
237+ useTheme ( ) ;
268238 logger . component ( 'MessageList' , 'Rendering component' , { hasPropMessages : ! ! propMessages } ) ;
239+
269240 // Store tab states on mount
270241 React . useEffect ( ( ) => {
271242 logger . debug ( 'MessageList - Initial tab state setup' ) ;
272243 const containers = document . querySelectorAll ( '.tabs-container' ) ;
273244 containers . forEach ( container => {
274- if ( container instanceof HTMLElement ) { // Ensure container is HTMLElement
245+ if ( container instanceof HTMLElement ) { // Ensure container is HTMLElement
275246 const activeTab = container . querySelector ( '.tab-button.active' ) ;
276247 if ( activeTab instanceof HTMLElement ) {
277248 const forTab = activeTab . getAttribute ( 'data-for-tab' ) ;
@@ -288,7 +259,7 @@ const MessageList: React.FC<MessageListProps> = ({messages: propMessages}) => {
288259 }
289260 } ) ;
290261 } , [ ] ) ;
291- // Store current tab states before update
262+
292263 const preserveTabStates = useCallback ( ( ) => {
293264 const containers = document . querySelectorAll ( '.tabs-container' ) ;
294265 containers . forEach ( container => {
@@ -302,8 +273,6 @@ const MessageList: React.FC<MessageListProps> = ({messages: propMessages}) => {
302273 } ) ;
303274 } , [ ] ) ;
304275
305-
306- // Log when component is mounted/unmounted
307276 React . useEffect ( ( ) => {
308277 logger . component ( 'MessageList' , 'Component mounted' , { timestamp : new Date ( ) . toISOString ( ) } ) ;
309278 return ( ) => {
@@ -326,12 +295,12 @@ const MessageList: React.FC<MessageListProps> = ({messages: propMessages}) => {
326295 // Preserve current tab states
327296 preserveTabStates ( ) ;
328297
329-
330298 // Process tabs after messages update
331299 requestAnimationFrame ( ( ) => {
332300 try {
333301 logger . debug ( 'MessageList - Updating tabs after message change' ) ;
334302 updateTabs ( ) ;
303+ Prism . highlightAll ( ) ;
335304 } catch ( error ) {
336305 logger . error ( 'Error processing tabs:' , error ) ;
337306 // Reset tab state on error
@@ -340,32 +309,31 @@ const MessageList: React.FC<MessageListProps> = ({messages: propMessages}) => {
340309 } ) ;
341310 } , [ messages ] ) ;
342311
343- return (
344- < MessageListContainer >
345- { filteredMessages . map ( ( message ) => {
346- logger . debug ( 'MessageList - Rendering message' , {
347- id : message . id ,
348- type : message . type ,
349- timestamp : message . timestamp ,
350- contentLength : message . content ?. length || 0
351- } ) ;
352- return (
353- < MessageItem
354- key = { message . id } // Changed key to use only message.id
355- type = { message . type }
356- >
357- < MessageContent
358- className = "message-body"
359- onClick = { handleClick }
360- dangerouslySetInnerHTML = { {
361- __html : memoizedProcessMessageContent ( message . content )
362- } }
363- />
364- </ MessageItem >
365- ) ;
366- } ) }
367- </ MessageListContainer >
368- ) ;
312+ return < MessageListContainer ref = { messageListRef } >
313+ { React . useMemo ( ( ) => messages
314+ . filter ( ( message ) => message . id && ! message . id . startsWith ( "z" ) )
315+ . filter ( ( message ) => message . content ?. length > 0 ) ,
316+ [ messages ] ) . map ( ( message ) => {
317+ logger . debug ( 'MessageList - Rendering message' , {
318+ id : message . id ,
319+ type : message . type ,
320+ timestamp : message . timestamp ,
321+ contentLength : message . content ?. length || 0
322+ } ) ;
323+ return < MessageItem
324+ key = { message . id } // Changed key to use only message.id
325+ type = { message . type }
326+ >
327+ { < MessageContent
328+ className = "message-body"
329+ onClick = { handleClick }
330+ dangerouslySetInnerHTML = { {
331+ __html : expandMessageReferences ( message . content , messages )
332+ } }
333+ /> }
334+ </ MessageItem > ;
335+ } ) }
336+ </ MessageListContainer > ;
369337} ;
370338
371339
0 commit comments