@@ -5,25 +5,68 @@ import { useState, useRef, useId, useCallback, useEffect } from 'react';
55import SyntaxHighlighter from 'react-syntax-highlighter' ;
66import { obsidian } from 'react-syntax-highlighter/dist/esm/styles/hljs' ;
77// Import PatternFly components
8- import { CodeBlock , CodeBlockAction , CodeBlockCode , Button , Tooltip } from '@patternfly/react-core' ;
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' ;
920
1021import { CheckIcon } from '@patternfly/react-icons/dist/esm/icons/check-icon' ;
1122import { CopyIcon } from '@patternfly/react-icons/dist/esm/icons/copy-icon' ;
12- import { ExtraProps } from 'react-markdown' ;
23+ import { ExpandableSectionForSyntaxHighlighter } from './ExpandableSectionForSyntaxHighlighter' ;
24+
25+ export interface CodeBlockMessageProps {
26+ /** Content rendered in code block */
27+ children ?: React . ReactNode ;
28+ /** Aria label applied to code block */
29+ 'aria-label' ?: string ;
30+ /** Class name applied to code block */
31+ className ?: string ;
32+ /** Whether code block is expandable */
33+ isExpandable ?: boolean ;
34+ /** Additional props passed to expandable section if isExpandable is applied */
35+ expandableSectionProps ?: Omit < ExpandableSectionProps , 'ref' > ;
36+ /** Additional props passed to expandable toggle if isExpandable is applied */
37+ expandableSectionToggleProps ?: ExpandableSectionToggleProps ;
38+ /** Link text applied to expandable toggle when expanded */
39+ expandedText ?: string ;
40+ /** Link text applied to expandable toggle when collapsed */
41+ collapsedText ?: string ;
42+ }
1343
1444const CodeBlockMessage = ( {
1545 children,
1646 className,
1747 'aria-label' : ariaLabel ,
48+ isExpandable = false ,
49+ expandableSectionProps,
50+ expandableSectionToggleProps,
51+ expandedText = 'Show less' ,
52+ collapsedText = 'Show more' ,
1853 ...props
19- } : Omit < JSX . IntrinsicElements [ 'code' ] , 'ref' > & ExtraProps ) => {
54+ } : CodeBlockMessageProps ) => {
2055 const [ copied , setCopied ] = useState ( false ) ;
56+ const [ isExpanded , setIsExpanded ] = useState ( false ) ;
2157
22- const buttonRef = useRef ( undefined ) ;
58+ const buttonRef = useRef ( ) ;
2359 const tooltipID = useId ( ) ;
60+ const toggleId = useId ( ) ;
61+ const contentId = useId ( ) ;
62+ const codeBlockRef = useRef < HTMLDivElement > ( null ) ;
2463
2564 const language = / l a n g u a g e - ( \w + ) / . exec ( className || '' ) ?. [ 1 ] ;
2665
66+ const onToggle = ( isExpanded ) => {
67+ setIsExpanded ( isExpanded ) ;
68+ } ;
69+
2770 // Handle clicking copy button
2871 const handleCopy = useCallback ( ( event , text ) => {
2972 navigator . clipboard . writeText ( text . toString ( ) ) ;
@@ -69,17 +112,61 @@ const CodeBlockMessage = ({
69112 ) ;
70113
71114 return (
72- < div className = "pf-chatbot__message-code-block" >
115+ < div className = "pf-chatbot__message-code-block" ref = { codeBlockRef } >
73116 < CodeBlock actions = { actions } >
74117 < CodeBlockCode >
75- { language ? (
76- < SyntaxHighlighter { ...props } language = { language } style = { obsidian } PreTag = "div" CodeTag = "div" wrapLongLines >
77- { String ( children ) . replace ( / \n $ / , '' ) }
78- </ SyntaxHighlighter >
79- ) : (
80- < > { children } </ >
81- ) }
118+ < >
119+ { language ? (
120+ // SyntaxHighlighter doesn't work with ExpandableSection because it targets the direct child
121+ // Forked for now and adjusted to match what we need
122+ < ExpandableSectionForSyntaxHighlighter
123+ variant = { ExpandableSectionVariant . truncate }
124+ isExpanded = { isExpanded }
125+ isDetached
126+ toggleId = { toggleId }
127+ contentId = { contentId }
128+ language = { language }
129+ { ...expandableSectionProps }
130+ >
131+ < SyntaxHighlighter
132+ { ...props }
133+ language = { language }
134+ style = { obsidian }
135+ PreTag = "div"
136+ CodeTag = "div"
137+ wrapLongLines
138+ >
139+ { String ( children ) . replace ( / \n $ / , '' ) }
140+ </ SyntaxHighlighter >
141+ </ ExpandableSectionForSyntaxHighlighter >
142+ ) : (
143+ < ExpandableSection
144+ variant = { ExpandableSectionVariant . truncate }
145+ isExpanded = { isExpanded }
146+ isDetached
147+ toggleId = { toggleId }
148+ contentId = { contentId }
149+ { ...expandableSectionProps }
150+ >
151+ { children }
152+ </ ExpandableSection >
153+ ) }
154+ </ >
82155 </ CodeBlockCode >
156+ { isExpandable && (
157+ < ExpandableSectionToggle
158+ isExpanded = { isExpanded }
159+ onToggle = { onToggle }
160+ direction = "up"
161+ toggleId = { toggleId }
162+ contentId = { contentId }
163+ hasTruncatedContent
164+ className = "pf-chatbot__message-code-toggle"
165+ { ...expandableSectionToggleProps }
166+ >
167+ { isExpanded ? expandedText : collapsedText }
168+ </ ExpandableSectionToggle >
169+ ) }
83170 </ CodeBlock >
84171 </ div >
85172 ) ;
0 commit comments