Skip to content

Commit e5a6b6d

Browse files
authored
Fix code block selection and copy button functionality during answer generation (#1065)
1 parent aa1abd0 commit e5a6b6d

File tree

1 file changed

+55
-32
lines changed

1 file changed

+55
-32
lines changed

packages/web/src/components/Markdown.tsx

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useMemo, useState } from 'react';
1+
import { useEffect, useMemo, useState, memo } from 'react';
22
import { BaseProps } from '../@types/common';
33
import { default as ReactMarkdown } from 'react-markdown';
44
import remarkGfm from 'remark-gfm';
@@ -109,6 +109,7 @@ const LinkRenderer = (props: any) => {
109109
</>
110110
);
111111
};
112+
112113
// eslint-disable-next-line @typescript-eslint/no-explicit-any
113114
const ImageRenderer = (props: any) => {
114115
const { isS3Url } = useRagFile();
@@ -124,7 +125,58 @@ const ImageRenderer = (props: any) => {
124125
return <img id={props.id} src={src} />;
125126
};
126127

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 = /language-(\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) => {
128180
return (
129181
<ReactMarkdown
130182
className={`${className ?? ''} prose max-w-full`}
@@ -137,36 +189,7 @@ const Markdown = React.memo(({ className, prefix, children }: Props) => {
137189
sup: ({ children }) => (
138190
<sup className="m-0.5 rounded-full bg-gray-200 px-1">{children}</sup>
139191
),
140-
code({ className, children }) {
141-
const language = /language-(\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,
170193
}}
171194
/>
172195
);

0 commit comments

Comments
 (0)