1
- import React , { useEffect , useMemo , useState } from 'react' ;
1
+ import { useEffect , useMemo , useState , memo } from 'react' ;
2
2
import { BaseProps } from '../@types/common' ;
3
3
import { default as ReactMarkdown } from 'react-markdown' ;
4
4
import remarkGfm from 'remark-gfm' ;
@@ -109,6 +109,7 @@ const LinkRenderer = (props: any) => {
109
109
</ >
110
110
) ;
111
111
} ;
112
+
112
113
// eslint-disable-next-line @typescript-eslint/no-explicit-any
113
114
const ImageRenderer = ( props : any ) => {
114
115
const { isS3Url } = useRagFile ( ) ;
@@ -124,7 +125,58 @@ const ImageRenderer = (props: any) => {
124
125
return < img id = { props . id } src = { src } /> ;
125
126
} ;
126
127
127
- const Markdown = React . memo ( ( { className, prefix, children } : Props ) => {
128
+ const CodeRenderer = memo (
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
+ ( props : any ) => {
131
+ const language = / l a n g u a g e - ( \w + ) / . exec ( props . className || '' ) ?. [ 1 ] ;
132
+ const codeText = String ( props . children ) . replace ( / \n $ / , '' ) ;
133
+ const isCodeBlock = codeText . includes ( '\n' ) ;
134
+ return (
135
+ < >
136
+ { language ? (
137
+ // Code block with language
138
+ < >
139
+ < div className = "flex" >
140
+ < span className = "flex-auto" > { language } </ span >
141
+ < ButtonCopy
142
+ className = "mr-2 justify-end text-gray-400"
143
+ text = { codeText }
144
+ />
145
+ </ div >
146
+ < SyntaxHighlighter
147
+ style = { vscDarkPlus }
148
+ language = { language || 'plaintext' } >
149
+ { codeText }
150
+ </ SyntaxHighlighter >
151
+ </ >
152
+ ) : isCodeBlock ? (
153
+ // Code block without language
154
+ < code className = "block rounded-md py-1" >
155
+ { codeText . split ( '\n' ) . map ( ( line , index ) => (
156
+ < span key = { `line-${ index } ` } className = "block px-1 py-0" >
157
+ { line }
158
+ </ span >
159
+ ) ) }
160
+ </ code >
161
+ ) : (
162
+ // Inline code
163
+ < span className = "bg-aws-squid-ink/10 border-aws-squid-ink/30 inline rounded-md border px-1 py-0.5" >
164
+ { codeText }
165
+ </ span >
166
+ ) }
167
+ </ >
168
+ ) ;
169
+ } ,
170
+ ( prevProps , nextProps ) => {
171
+ // Only re-render if the code content or language changes
172
+ return (
173
+ String ( prevProps . children ) === String ( nextProps . children ) &&
174
+ prevProps . className === nextProps . className
175
+ ) ;
176
+ }
177
+ ) ;
178
+
179
+ const Markdown = memo ( ( { className, prefix, children } : Props ) => {
128
180
return (
129
181
< ReactMarkdown
130
182
className = { `${ className ?? '' } prose max-w-full` }
@@ -137,36 +189,7 @@ const Markdown = React.memo(({ className, prefix, children }: Props) => {
137
189
sup : ( { children } ) => (
138
190
< sup className = "m-0.5 rounded-full bg-gray-200 px-1" > { children } </ sup >
139
191
) ,
140
- code ( { className, children } ) {
141
- const language = / l a n g u a g e - ( \w + ) / . exec ( className || '' ) ?. [ 1 ] ;
142
- const isCodeBlock = ! ! language ;
143
- const codeText = String ( children ) . replace ( / \n $ / , '' ) ;
144
-
145
- return (
146
- < >
147
- { isCodeBlock ? (
148
- < >
149
- < div className = "flex" >
150
- < span className = "flex-auto" > { language } </ span >
151
- < ButtonCopy
152
- className = "mr-2 justify-end text-gray-400"
153
- text = { codeText } // Specify the source code part to be copied to the clipboard as the target, and pass it to SyntaxHighlighter
154
- />
155
- </ div >
156
- < SyntaxHighlighter
157
- children = { codeText }
158
- style = { vscDarkPlus }
159
- language = { isCodeBlock ? language : 'plaintext' }
160
- />
161
- </ >
162
- ) : (
163
- < span className = "bg-aws-squid-ink/10 border-aws-squid-ink/30 inline rounded-md border px-1 py-0.5" >
164
- { codeText }
165
- </ span >
166
- ) }
167
- </ >
168
- ) ;
169
- } ,
192
+ code : CodeRenderer ,
170
193
} }
171
194
/>
172
195
) ;
0 commit comments