import { CSSProperties, useState, Fragment, FunctionComponent, MouseEvent as ReactMouseEvent, KeyboardEvent as ReactKeyboardEvent, Ref } from 'react'; import Message from '@patternfly/chatbot/dist/dynamic/Message'; import patternflyAvatar from './patternfly_avatar.jpg'; import squareImg from './PF-social-color-square.svg'; import { AlertActionLink, MenuToggle, MenuToggleElement, Select, SelectList, SelectOption } from '@patternfly/react-core'; import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle'; export const BotMessageExample: FunctionComponent = () => { const [variant, setVariant] = useState('Code'); const [isOpen, setIsOpen] = useState(false); const [selected, setSelected] = useState('Message content type'); const [isExpandable, setIsExpanded] = useState(false); /* eslint-disable indent */ const renderContent = () => { switch (variant) { case 'Code': case 'Expandable code': return code; case 'Heading': return heading; case 'Emphasis': return emphasis; case 'Block quotes': return blockQuotes; case 'Ordered list': return orderedList; case 'Unordered list': return unorderedList; case 'More complex list': return moreComplexList; case 'Inline code': return inlineCode; case 'Link': return link; case 'Table': return table; case 'Image': return image; case 'Footnote': return footnote; default: return; } }; /* eslint-enable indent */ const code = ` Here is some YAML code: ~~~yaml apiVersion: helm.openshift.io/v1beta1/ kind: HelmChartRepository metadata: name: azure-sample-repo0oooo00ooo spec: connectionConfig: url: https://raw.githubusercontent.com/Azure-Samples/helm-charts/master/docs ~~~ Here is some JavaScript code: ~~~js const MessageLoading = () => (
Loading message
); export default MessageLoading; ~~~ `; const heading = ` # h1 Heading ## h2 Heading ### h3 Heading #### h4 Heading ##### h5 Heading ###### h6 Heading `; const emphasis = ` **Bold text, formatted with double asterisks** __Bold text, formatted with double underscores__ *Italic text, formatted with single asterisks* _Italic text, formatted with single underscores_ ~~Strikethrough~~ `; const blockQuotes = `> Blockquotes can also be nested... >> ...by using additional greater-than signs (>) right next to each other... > > > ...or with spaces between each sign.`; const orderedList = ` Here is an ordered list: 1. Item 1 2. Item 2 3. Item 3`; const unorderedList = ` Here is an unordered list: * Item 1 * Item 2 * Item 3`; const moreComplexList = `You may be wondering whether you can display more complex lists with formatting. In response to your question, I will explain how to spread butter on toast. 1. **Using a \`toaster\`:** - Place \`bread\` in a \`toaster\`. - Once \`bread\` is lightly browned, remove from \`toaster\`. 2. **Using a \`knife\`:** Acquire 1 tablespoon of room temperature \`butter\`. Use \`knife\` to spread butter on \`toast\`. Bon appétit! `; const link = `A paragraph with a URL: https://reactjs.org.`; const inlineCode = `Here is an inline code - \`() => void\``; const table = `To customize your table, you can use [PatternFly TableProps](/components/table#table) | Version | GA date | User role |-|-|-| | 2.5 | September 30, 2024 | Administrator | | 2.5 | June 27, 2023 | Editor | | 3.0 | April 1, 2025 | Administrator `; const image = `![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`; const footnote = `This is some text that has a short footnote[^1] and this is text with a longer footnote.[^bignote] [^1]: This is a short footnote. To return the highlight to the original message, click the arrow. [^bignote]: This is a long footnote with multiple paragraphs and formatting. To break long footnotes into paragraphs, indent the text. Add as many paragraphs as you like. You can include *italic text*, **bold text**, and \`code\`. > You can even include blockquotes in footnotes!`; const error = { title: 'Could not load chat', children: 'Wait a few minutes and check your network settings. If the issue persists: ', actionLinks: ( Start a new chat Contact support ) }; const onSelect = (_event: ReactMouseEvent | undefined, value: string | number | undefined) => { setVariant(value as string); setSelected(value as string); setIsOpen(false); if (value === 'Expandable code') { setIsExpanded(true); } else { setIsExpanded(false); } }; const onToggleClick = () => { setIsOpen(!isOpen); }; const toggle = (toggleRef: Ref) => ( {selected} ); const handleFootnoteNavigation = (event: ReactMouseEvent | ReactKeyboardEvent) => { const target = event.target as HTMLElement; // Depending on whether it is a click event or keyboard event, target may be a link or something like a span // Look for the closest anchor element (could be a parent) const anchorElement = target.closest('a'); const href = anchorElement?.getAttribute('href'); // Check if this is a footnote link - we only have internal links in this example, so this is all we need here if (href && href.startsWith('#')) { // Prevent default behavior to avoid page re-render on click in PatternFly docs framework event.preventDefault(); let targetElement: HTMLElement | null = null; const targetId = href.replace('#', ''); targetElement = document.querySelector(`[id="${targetId}"]`); if (targetElement) { let focusTarget = targetElement; // If we found a footnote definition container, focus on the parent li element if (targetElement.id?.startsWith('bot-message-fn-')) { // Find the parent li element that contains the footnote const parentLi = targetElement.closest('li'); if (parentLi) { focusTarget = parentLi as HTMLElement; } } focusTarget.focus(); let elementToHighlight = targetElement; // If this is a backref link (going back to footnote reference), // we want to highlight more of the ref line and not just the link itself // since the target is so small if (targetElement.id?.startsWith('bot-message-fnref-')) { const refLink = targetElement; // Walk up the DOM to find a meaningful container let parent = refLink.parentElement; while (parent && parent.tagName.toLowerCase() !== 'p' && parent !== document.body) { parent = parent.parentElement; } // Use if found, otherwise use the immediate parent or target as a fallback elementToHighlight = parent || refLink.parentElement || targetElement; } // Briefly highlight the target element for fun to show what you can do const originalBackground = elementToHighlight.style.backgroundColor; const originalTransition = elementToHighlight.style.transition; elementToHighlight.style.transition = 'background-color 0.3s ease'; elementToHighlight.style.backgroundColor = 'var(--pf-t--global--background--color--tertiary--default)'; setTimeout(() => { elementToHighlight.style.backgroundColor = originalBackground; setTimeout(() => { elementToHighlight.style.transition = originalTransition; }, 300); }, 1000); } } }; const onClick = (event: ReactMouseEvent | ReactKeyboardEvent) => { handleFootnoteNavigation(event); }; return ( <> ); };