Skip to content

Commit d4e0195

Browse files
committed
Investigate code editor
1 parent 912cd12 commit d4e0195

1 file changed

Lines changed: 79 additions & 124 deletions

File tree

packages/module/src/Message/CodeBlockMessage/CodeBlockMessage.tsx

Lines changed: 79 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,22 @@
11
// ============================================================================
22
// Chatbot Main - Message - Content - Code Block
33
// ============================================================================
4-
import { useState, useRef, useId, useCallback, useEffect } from 'react';
5-
import SyntaxHighlighter from 'react-syntax-highlighter';
6-
import { obsidian } from 'react-syntax-highlighter/dist/esm/styles/hljs';
7-
// Import PatternFly components
8-
import {
9-
CodeBlock,
10-
CodeBlockAction,
11-
CodeBlockCode,
12-
Button,
13-
Tooltip,
14-
ExpandableSection,
15-
ExpandableSectionToggle,
16-
ExpandableSectionProps,
17-
ExpandableSectionToggleProps,
18-
ExpandableSectionVariant
19-
} from '@patternfly/react-core';
20-
21-
import { CheckIcon } from '@patternfly/react-icons/dist/esm/icons/check-icon';
22-
import { CopyIcon } from '@patternfly/react-icons/dist/esm/icons/copy-icon';
23-
import { ExpandableSectionForSyntaxHighlighter } from './ExpandableSectionForSyntaxHighlighter';
4+
import { useState } from 'react';
5+
import { ExpandableSectionProps, ExpandableSection } from '@patternfly/react-core';
6+
7+
import { CodeEditor, CodeEditorProps, Language } from '@patternfly/react-code-editor';
248

259
export interface CodeBlockMessageProps {
2610
/** Content rendered in code block */
2711
children?: React.ReactNode;
28-
/** Aria label applied to code block */
29-
'aria-label'?: string;
3012
/** Class name applied to code block */
3113
className?: string;
3214
/** Whether code block is expandable */
3315
isExpandable?: boolean;
3416
/** Additional props passed to expandable section if isExpandable is applied */
3517
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
36-
/** Additional props passed to expandable toggle if isExpandable is applied */
37-
expandableSectionToggleProps?: ExpandableSectionToggleProps;
18+
/** Additional props passed to code editor */
19+
codeEditorProps?: Omit<CodeEditorProps, 'ref'>;
3820
/** Link text applied to expandable toggle when expanded */
3921
expandedText?: string;
4022
/** Link text applied to expandable toggle when collapsed */
@@ -47,24 +29,63 @@ const DEFAULT_COLLAPSED_TEXT = 'Show more';
4729
const CodeBlockMessage = ({
4830
children,
4931
className,
50-
'aria-label': ariaLabel,
5132
isExpandable = false,
5233
expandableSectionProps,
53-
expandableSectionToggleProps,
5434
expandedText = DEFAULT_EXPANDED_TEXT,
5535
collapsedText = DEFAULT_COLLAPSED_TEXT,
36+
codeEditorProps,
5637
...props
5738
}: CodeBlockMessageProps) => {
58-
const [copied, setCopied] = useState(false);
5939
const [isExpanded, setIsExpanded] = useState(false);
6040

61-
const buttonRef = useRef();
62-
const tooltipID = useId();
63-
const toggleId = useId();
64-
const contentId = useId();
65-
const codeBlockRef = useRef<HTMLDivElement>(null);
41+
const languageString = /language-(\w+)/.exec(className || '')?.[1];
42+
43+
const getLanguage = (lang: string | undefined): Language | undefined => {
44+
if (!lang) {
45+
return undefined;
46+
}
47+
48+
const languageMap: Record<string, Language> = {
49+
javascript: Language.javascript,
50+
js: Language.javascript,
51+
typescript: Language.typescript,
52+
ts: Language.typescript,
53+
jsx: Language.javascript,
54+
tsx: Language.typescript,
55+
html: Language.html,
56+
css: Language.css,
57+
scss: Language.scss,
58+
json: Language.json,
59+
xml: Language.xml,
60+
yaml: Language.yaml,
61+
yml: Language.yaml,
62+
python: Language.python,
63+
py: Language.python,
64+
java: Language.java,
65+
c: Language.c,
66+
cpp: Language.cpp,
67+
csharp: Language.csharp,
68+
cs: Language.csharp,
69+
go: Language.go,
70+
rust: Language.rust,
71+
php: Language.php,
72+
ruby: Language.ruby,
73+
rb: Language.ruby,
74+
bash: Language.shell,
75+
sh: Language.shell,
76+
shell: Language.shell,
77+
dockerfile: Language.dockerfile,
78+
sql: Language.sql,
79+
markdown: Language.markdown,
80+
md: Language.markdown,
81+
plaintext: Language.plaintext,
82+
text: Language.plaintext
83+
};
84+
85+
return languageMap[lang.toLowerCase()];
86+
};
6687

67-
const language = /language-(\w+)/.exec(className || '')?.[1];
88+
const language = getLanguage(languageString);
6889

6990
// Get custom toggle text from data attributes if available - for use with rehype plugins
7091
const customExpandedText = props['data-expanded-text'];
@@ -84,27 +105,10 @@ const CodeBlockMessage = ({
84105
);
85106
}
86107

87-
const onToggle = (isExpanded) => {
108+
const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
88109
setIsExpanded(isExpanded);
89110
};
90111

91-
// Handle clicking copy button
92-
const handleCopy = useCallback((event, text) => {
93-
navigator.clipboard.writeText(text.toString());
94-
setCopied(true);
95-
}, []);
96-
97-
// Reset copied state
98-
useEffect(() => {
99-
if (copied) {
100-
const timer = setTimeout(() => {
101-
setCopied(false);
102-
}, 3000);
103-
104-
return () => clearTimeout(timer);
105-
}
106-
});
107-
108112
if (!String(children).includes('\n')) {
109113
return (
110114
<code {...props} className="pf-chatbot__message-inline-code">
@@ -113,82 +117,33 @@ const CodeBlockMessage = ({
113117
);
114118
}
115119

116-
// Setup code block header
117-
const actions = (
118-
<>
119-
<CodeBlockAction>
120-
{language && <div className="pf-chatbot__message-code-block-language">{language}</div>}
121-
<Button
122-
ref={buttonRef}
123-
aria-label={ariaLabel ?? 'Copy code'}
124-
variant="plain"
125-
className="pf-chatbot__button--copy"
126-
onClick={(event) => handleCopy(event, children)}
127-
>
128-
{copied ? <CheckIcon /> : <CopyIcon />}
129-
</Button>
130-
<Tooltip id={tooltipID} content="Copy" position="top" triggerRef={buttonRef} />
131-
</CodeBlockAction>
132-
</>
120+
const codeEditor = (
121+
<CodeEditor
122+
key={`code-editor-${isExpanded}`} // Force remount on state change
123+
code={children?.toString()}
124+
isReadOnly
125+
isCopyEnabled
126+
isLanguageLabelVisible
127+
language={language}
128+
height="sizeToFit"
129+
{...codeEditorProps}
130+
></CodeEditor>
133131
);
134132

135133
return (
136-
<div className="pf-chatbot__message-code-block" ref={codeBlockRef}>
137-
<CodeBlock actions={actions}>
138-
<CodeBlockCode>
139-
<>
140-
{language ? (
141-
// SyntaxHighlighter doesn't work with ExpandableSection because it targets the direct child
142-
// Forked for now and adjusted to match what we need
143-
<ExpandableSectionForSyntaxHighlighter
144-
variant={ExpandableSectionVariant.truncate}
145-
isExpanded={isExpanded}
146-
isDetached
147-
toggleId={toggleId}
148-
contentId={contentId}
149-
language={language}
150-
{...expandableSectionProps}
151-
>
152-
<SyntaxHighlighter
153-
{...props}
154-
language={language}
155-
style={obsidian}
156-
PreTag="div"
157-
CodeTag="div"
158-
wrapLongLines
159-
>
160-
{String(children).replace(/\n$/, '')}
161-
</SyntaxHighlighter>
162-
</ExpandableSectionForSyntaxHighlighter>
163-
) : (
164-
<ExpandableSection
165-
variant={ExpandableSectionVariant.truncate}
166-
isExpanded={isExpanded}
167-
isDetached
168-
toggleId={toggleId}
169-
contentId={contentId}
170-
{...expandableSectionProps}
171-
>
172-
{children}
173-
</ExpandableSection>
174-
)}
175-
</>
176-
</CodeBlockCode>
177-
{isExpandable && (
178-
<ExpandableSectionToggle
179-
isExpanded={isExpanded}
180-
onToggle={onToggle}
181-
direction="up"
182-
toggleId={toggleId}
183-
contentId={contentId}
184-
hasTruncatedContent
185-
className="pf-chatbot__message-code-toggle"
186-
{...expandableSectionToggleProps}
187-
>
188-
{isExpanded ? finalExpandedText : finalCollapsedText}
189-
</ExpandableSectionToggle>
190-
)}
191-
</CodeBlock>
134+
<div>
135+
{isExpandable ? (
136+
<ExpandableSection
137+
toggleText={isExpanded ? finalExpandedText : finalCollapsedText}
138+
onToggle={onToggle}
139+
isExpanded={isExpanded}
140+
{...expandableSectionProps}
141+
>
142+
{codeEditor}
143+
</ExpandableSection>
144+
) : (
145+
codeEditor
146+
)}
192147
</div>
193148
);
194149
};

0 commit comments

Comments
 (0)