Skip to content

Commit afc459c

Browse files
committed
chore(docs): Make Message expandable code links unique
Added rehype plugin so we could adjust the expandable code toggle links in our User and Bot Messages. Eric recommended that these are unique. Because the code blocks are in the same Message, we need to do this by modifying the syntax tree. I added this functionality and also added a warning in case people try to do conflicting behaviors.
1 parent 6deace2 commit afc459c

8 files changed

Lines changed: 63 additions & 3 deletions

File tree

packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
SelectList,
1111
SelectOption
1212
} from '@patternfly/react-core';
13+
import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle';
1314

1415
export const BotMessageExample: FunctionComponent = () => {
1516
const [variant, setVariant] = useState<string>('Code');
@@ -268,6 +269,10 @@ _Italic text, formatted with single underscores_
268269
}
269270
error={variant === 'Error' ? error : undefined}
270271
codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
272+
// In this example, custom plugin will override any custom expandedText or collapsedText attributes provided
273+
// The purpose of this plugin is to provide unique link names for the code blocks
274+
// Because they are in the same message, this requires a custom plugin to parse the syntax tree
275+
additionalRehypePlugins={[rehypeCodeBlockToggle]}
271276
/>
272277
</>
273278
);

packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ sortValue: 3
3131
---
3232

3333
import Message from '@patternfly/chatbot/dist/dynamic/Message';
34+
import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle';
3435
import SourcesCard from '@patternfly/chatbot/dist/dynamic/SourcesCard';
3536
import { RobotIcon } from '@patternfly/react-icons/dist/esm/icons/robot-icon';
3637
import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon';

packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
SelectList,
1010
SelectOption
1111
} from '@patternfly/react-core';
12+
import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle';
1213

1314
export const UserMessageExample: FunctionComponent = () => {
1415
const [variant, setVariant] = useState<string>('Code');
@@ -250,6 +251,10 @@ _Italic text, formatted with single underscores_
250251
onEditUpdate={() => setIsEditable(false)}
251252
onEditCancel={() => setIsEditable(false)}
252253
codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
254+
// In this example, custom plugin will override any custom expandedText or collapsedText attributes provided
255+
// The purpose of this plugin is to provide unique link names for the code blocks
256+
// Because they are in the same message, this requires a custom plugin to parse the syntax tree
257+
additionalRehypePlugins={[rehypeCodeBlockToggle]}
253258
/>
254259
</>
255260
);

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,18 @@ export interface CodeBlockMessageProps {
4141
collapsedText?: string;
4242
}
4343

44+
const DEFAULT_EXPANDED_TEXT = 'Show less';
45+
const DEFAULT_COLLAPSED_TEXT = 'Show more';
46+
4447
const CodeBlockMessage = ({
4548
children,
4649
className,
4750
'aria-label': ariaLabel,
4851
isExpandable = false,
4952
expandableSectionProps,
5053
expandableSectionToggleProps,
51-
expandedText = 'Show less',
52-
collapsedText = 'Show more',
54+
expandedText = DEFAULT_EXPANDED_TEXT,
55+
collapsedText = DEFAULT_COLLAPSED_TEXT,
5356
...props
5457
}: CodeBlockMessageProps) => {
5558
const [copied, setCopied] = useState(false);
@@ -63,6 +66,24 @@ const CodeBlockMessage = ({
6366

6467
const language = /language-(\w+)/.exec(className || '')?.[1];
6568

69+
// Get custom toggle text from data attributes if available - for use with rehype plugins
70+
const customExpandedText = props['data-expanded-text'];
71+
const customCollapsedText = props['data-collapsed-text'];
72+
73+
const finalExpandedText = customExpandedText || expandedText;
74+
const finalCollapsedText = customCollapsedText || collapsedText;
75+
76+
if (
77+
(customExpandedText && expandedText !== DEFAULT_EXPANDED_TEXT) ||
78+
(customCollapsedText && collapsedText !== DEFAULT_COLLAPSED_TEXT)
79+
) {
80+
// eslint-disable-next-line no-console
81+
console.error(
82+
'Message:',
83+
'Custom rehype plugins that rely on data-expanded-text or data-collapsed-text will override expandedText and collapsedText props if both are passed in.'
84+
);
85+
}
86+
6687
const onToggle = (isExpanded) => {
6788
setIsExpanded(isExpanded);
6889
};
@@ -164,7 +185,7 @@ const CodeBlockMessage = ({
164185
className="pf-chatbot__message-code-toggle"
165186
{...expandableSectionToggleProps}
166187
>
167-
{isExpanded ? expandedText : collapsedText}
188+
{isExpanded ? finalExpandedText : finalCollapsedText}
168189
</ExpandableSectionToggle>
169190
)}
170191
</CodeBlock>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ class ExpandableSectionForSyntaxHighlighter extends Component<ExpandableSectionP
176176
contentId,
177177
toggleId,
178178
variant,
179+
// eslint-disable-next-line
180+
truncateMaxLines,
179181
...props
180182
} = this.props;
181183

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { rehypeCodeBlockToggle } from './rehypeCodeBlockToggle';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { visit } from 'unist-util-visit';
2+
import { Element } from 'hast';
3+
import { Node } from 'unist';
4+
5+
// Rehype plugin to add language information to code block props
6+
// Per Eric, Ideally any toggle buttons that can be navigated to would have unique accessible names
7+
// For the purposes of our examples this should suffice, but in a real-world use case they may need to be more unique
8+
export const rehypeCodeBlockToggle = () => (tree: Node) => {
9+
visit(tree, 'element', (node: Element) => {
10+
if (node.tagName === 'code' && node.properties?.className) {
11+
const className = node.properties.className as string[];
12+
const languageMatch = className.find((cls) => cls.startsWith('language-'));
13+
14+
if (languageMatch) {
15+
const language = languageMatch.replace('language-', '').toUpperCase();
16+
17+
// Add the language and toggle text as data attributes
18+
node.properties['data-language'] = language;
19+
node.properties['data-expanded-text'] = `Show less ${language} code`;
20+
node.properties['data-collapsed-text'] = `Show more ${language} code`;
21+
}
22+
}
23+
});
24+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { default } from './Message';
2+
export { rehypeCodeBlockToggle } from './Plugins/rehypeCodeBlockToggle';
23

34
export * from './Message';

0 commit comments

Comments
 (0)