@patternfly/chatbot 6.3.0-prerelease.17 → 6.3.0-prerelease.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +20 -2
  2. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +14 -3
  3. package/dist/cjs/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.d.ts +62 -0
  4. package/dist/cjs/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.js +136 -0
  5. package/dist/cjs/Message/Message.d.ts +16 -1
  6. package/dist/cjs/Message/Message.test.js +24 -0
  7. package/dist/css/main.css +10 -0
  8. package/dist/css/main.css.map +1 -1
  9. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +20 -2
  10. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +15 -4
  11. package/dist/esm/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.d.ts +62 -0
  12. package/dist/esm/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.js +130 -0
  13. package/dist/esm/Message/Message.d.ts +16 -1
  14. package/dist/esm/Message/Message.test.js +24 -0
  15. package/dist/tsconfig.tsbuildinfo +1 -1
  16. package/package.json +1 -1
  17. package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +10 -0
  18. package/patternfly-docs/content/extensions/chatbot/examples/Customizing Messages/Customizing Messages.md +51 -0
  19. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +9 -0
  20. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +9 -0
  21. package/patternfly-docs/content/extensions/chatbot/img/quick-response-confirmation.svg +67 -0
  22. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +7 -0
  23. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +99 -12
  24. package/src/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.tsx +220 -0
  25. package/src/Message/Message.test.tsx +30 -0
  26. package/src/Message/Message.tsx +17 -0
@@ -0,0 +1,130 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { Component, createRef } from 'react';
14
+ import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section';
15
+ import { css } from '@patternfly/react-styles';
16
+ import lineClamp from '@patternfly/react-tokens/dist/esm/c_expandable_section_m_truncate__content_LineClamp';
17
+ import { debounce, getResizeObserver, getUniqueId } from '@patternfly/react-core';
18
+ export var ExpandableSectionVariant;
19
+ (function (ExpandableSectionVariant) {
20
+ ExpandableSectionVariant["default"] = "default";
21
+ ExpandableSectionVariant["truncate"] = "truncate";
22
+ })(ExpandableSectionVariant || (ExpandableSectionVariant = {}));
23
+ const setLineClamp = (element, lines, language, isExpanded) => {
24
+ if (!element || !lines || lines < 1 || typeof isExpanded === 'undefined') {
25
+ return;
26
+ }
27
+ if (language) {
28
+ const selector = `.language-${language.toLowerCase()}`;
29
+ const childElement = element.querySelector(selector);
30
+ if (!childElement) {
31
+ return;
32
+ }
33
+ if (isExpanded) {
34
+ // Reset all truncation-related styles to their default values
35
+ childElement.style.removeProperty('-webkit-line-clamp');
36
+ childElement.style.removeProperty('display');
37
+ childElement.style.removeProperty('-webkit-box-orient');
38
+ childElement.style.removeProperty('overflow');
39
+ }
40
+ else {
41
+ childElement.style.setProperty('-webkit-line-clamp', lines.toString());
42
+ childElement.style.setProperty('display', '-webkit-box');
43
+ childElement.style.setProperty('-webkit-box-orient', 'vertical');
44
+ childElement.style.setProperty('overflow', 'hidden');
45
+ }
46
+ }
47
+ };
48
+ class ExpandableSectionForSyntaxHighlighter extends Component {
49
+ constructor(props) {
50
+ var _a;
51
+ super(props);
52
+ this.expandableContentRef = createRef();
53
+ /* eslint-disable-next-line */
54
+ this.observer = () => { };
55
+ this.checkToggleVisibility = () => {
56
+ var _a;
57
+ if ((_a = this.expandableContentRef) === null || _a === void 0 ? void 0 : _a.current) {
58
+ const maxLines = this.props.truncateMaxLines || parseInt(lineClamp.value);
59
+ const totalLines = this.expandableContentRef.current.scrollHeight /
60
+ parseInt(getComputedStyle(this.expandableContentRef.current).lineHeight);
61
+ this.setState({
62
+ hasToggle: totalLines > maxLines
63
+ });
64
+ }
65
+ };
66
+ this.resize = () => {
67
+ if (this.expandableContentRef.current) {
68
+ const { offsetWidth } = this.expandableContentRef.current;
69
+ if (this.state.previousWidth !== offsetWidth) {
70
+ this.setState({ previousWidth: offsetWidth });
71
+ this.checkToggleVisibility();
72
+ }
73
+ }
74
+ };
75
+ this.handleResize = debounce(this.resize, 250);
76
+ this.state = {
77
+ isExpanded: (_a = props.isExpanded) !== null && _a !== void 0 ? _a : false,
78
+ hasToggle: true,
79
+ previousWidth: undefined
80
+ };
81
+ }
82
+ componentDidMount() {
83
+ if (this.props.variant === ExpandableSectionVariant.truncate) {
84
+ const expandableContent = this.expandableContentRef.current;
85
+ if (expandableContent) {
86
+ this.setState({ previousWidth: expandableContent.offsetWidth });
87
+ this.observer = getResizeObserver(expandableContent, this.handleResize, false);
88
+ if (this.props.truncateMaxLines) {
89
+ setLineClamp(expandableContent, this.props.truncateMaxLines, this.props.language, this.state.isExpanded);
90
+ }
91
+ }
92
+ this.checkToggleVisibility();
93
+ }
94
+ }
95
+ componentDidUpdate(prevProps) {
96
+ if (this.props.variant === ExpandableSectionVariant.truncate &&
97
+ (prevProps.truncateMaxLines !== this.props.truncateMaxLines ||
98
+ prevProps.children !== this.props.children ||
99
+ prevProps.isExpanded !== this.props.isExpanded)) {
100
+ const expandableContent = this.expandableContentRef.current;
101
+ setLineClamp(expandableContent, this.props.truncateMaxLines, this.props.language, this.props.isExpanded);
102
+ this.checkToggleVisibility();
103
+ }
104
+ }
105
+ componentWillUnmount() {
106
+ if (this.props.variant === ExpandableSectionVariant.truncate) {
107
+ this.observer();
108
+ }
109
+ }
110
+ render() {
111
+ const _a = this.props, { className, children, isExpanded, isDetached, displaySize, isWidthLimited, isIndented, contentId, toggleId, variant } = _a, props = __rest(_a, ["className", "children", "isExpanded", "isDetached", "displaySize", "isWidthLimited", "isIndented", "contentId", "toggleId", "variant"]);
112
+ if (isDetached && !toggleId) {
113
+ /* eslint-disable no-console */
114
+ console.warn('ExpandableSection: The toggleId value must be passed in and must match the toggleId of the ExpandableSectionToggle.');
115
+ }
116
+ const uniqueContentId = contentId || getUniqueId('expandable-section-content');
117
+ const uniqueToggleId = toggleId || getUniqueId('expandable-section-toggle');
118
+ return (_jsx("div", Object.assign({ className: css(styles.expandableSection, isExpanded && styles.modifiers.expanded, displaySize === 'lg' && styles.modifiers.displayLg, isWidthLimited && styles.modifiers.limitWidth, isIndented && styles.modifiers.indented, variant === ExpandableSectionVariant.truncate && styles.modifiers.truncate, className) }, props, { children: _jsx("div", { ref: this.expandableContentRef, className: css(styles.expandableSectionContent), hidden: variant !== ExpandableSectionVariant.truncate && !isExpanded, id: uniqueContentId, "aria-labelledby": uniqueToggleId, role: "region", children: children }) })));
119
+ }
120
+ }
121
+ ExpandableSectionForSyntaxHighlighter.displayName = 'ExpandableSection';
122
+ ExpandableSectionForSyntaxHighlighter.defaultProps = {
123
+ className: '',
124
+ isDetached: false,
125
+ displaySize: 'default',
126
+ isWidthLimited: false,
127
+ isIndented: false,
128
+ variant: 'default'
129
+ };
130
+ export { ExpandableSectionForSyntaxHighlighter };
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import type { FunctionComponent, HTMLProps, MouseEvent as ReactMouseEvent, Ref } from 'react';
3
- import { AlertProps, AvatarProps, ButtonProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
3
+ import { AlertProps, AvatarProps, ButtonProps, ExpandableSectionProps, ExpandableSectionToggleProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
4
4
  import { ActionProps } from '../ResponseActions/ResponseActions';
5
5
  import { SourcesCardProps } from '../SourcesCard';
6
6
  import { QuickStart, QuickstartAction } from './QuickStarts/types';
@@ -64,9 +64,24 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
64
64
  botWord?: string;
65
65
  /** Label for the English "Loading message," displayed to screenreaders when loading a message */
66
66
  loadingWord?: string;
67
+ /** Props for code blocks */
67
68
  codeBlockProps?: {
69
+ /** Aria label applied to code blocks */
68
70
  'aria-label'?: string;
71
+ /** Class name applied to code blocks */
69
72
  className?: string;
73
+ /** Whether code blocks are expandable */
74
+ isExpandable?: boolean;
75
+ /** Length of text initially shown in expandable code blocks; defaults to 10 characters */
76
+ maxLength?: number;
77
+ /** Additional props passed to expandable section if isExpandable is applied */
78
+ expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
79
+ /** Additional props passed to expandable toggle if isExpandable is applied */
80
+ expandableSectionToggleProps?: ExpandableSectionToggleProps;
81
+ /** Link text applied to expandable toggle when expanded */
82
+ expandedText?: string;
83
+ /** Link text applied to expandable toggle when collapsed */
84
+ collapsedText?: string;
70
85
  };
71
86
  /** Props for quick responses */
72
87
  quickResponses?: QuickResponse[];
@@ -403,6 +403,30 @@ describe('Message', () => {
403
403
  expect(screen.getByText(/url:/i)).toBeTruthy();
404
404
  expect(screen.getByText(/https:\/\/raw.githubusercontent.com\/Azure-Samples\/helm-charts\/master\/docs/i)).toBeTruthy();
405
405
  });
406
+ it('should render expandable code correctly', () => {
407
+ render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { isExpandable: true } }));
408
+ expect(screen.getByText('Here is some YAML code:')).toBeTruthy();
409
+ expect(screen.getByRole('button', { name: 'Copy code' })).toBeTruthy();
410
+ expect(screen.getByText(/yaml/)).toBeTruthy();
411
+ expect(screen.getByText(/apiVersion/i)).toBeTruthy();
412
+ expect(screen.getByRole('button', { name: /Show more/i })).toBeTruthy();
413
+ });
414
+ it('should handle click on expandable code correctly', () => __awaiter(void 0, void 0, void 0, function* () {
415
+ render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { isExpandable: true } }));
416
+ const button = screen.getByRole('button', { name: /Show more/i });
417
+ yield userEvent.click(button);
418
+ expect(screen.getByRole('button', { name: /Show less/i })).toBeTruthy();
419
+ expect(screen.getByText(/yaml/)).toBeTruthy();
420
+ expect(screen.getByText(/apiVersion:/i)).toBeTruthy();
421
+ expect(screen.getByText(/helm.openshift.io\/v1beta1/i)).toBeTruthy();
422
+ expect(screen.getByText(/metadata:/i)).toBeTruthy();
423
+ expect(screen.getByText(/name:/i)).toBeTruthy();
424
+ expect(screen.getByText(/azure-sample-repo0oooo00ooo/i)).toBeTruthy();
425
+ expect(screen.getByText(/spec/i)).toBeTruthy();
426
+ expect(screen.getByText(/connectionConfig:/i)).toBeTruthy();
427
+ expect(screen.getByText(/url:/i)).toBeTruthy();
428
+ expect(screen.getByText(/https:\/\/raw.githubusercontent.com\/Azure-Samples\/helm-charts\/master\/docs/i)).toBeTruthy();
429
+ }));
406
430
  it('can click copy code button', () => __awaiter(void 0, void 0, void 0, function* () {
407
431
  // need explicit setup since RTL stubs clipboard if you do this
408
432
  const user = userEvent.setup();
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.3.0-prerelease.17",
3
+ "version": "6.3.0-prerelease.18",
4
4
  "description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -261,6 +261,16 @@ Each time a user begins a new conversation, display a [welcome message, with pro
261
261
 
262
262
  As much as possible, the suggested prompts should consider the user’s location in the service or application, or the situation their project is undergoing.
263
263
 
264
+ ### Executing user requests
265
+
266
+ Instead of automatically initiating what sounds like a request from a user, the ChatBot should ask users to confirm or deny their intent. This differentiates moments where users are simply asking about feasibility, rather than actually making a request.
267
+
268
+ This can be done using the [quick response](/patternfly-ai/chatbot/messages#messages-with-quick-responses) buttons:
269
+
270
+ <div class="ws-docs-content-img">
271
+ ![Confirmation options from a bot in response to a user's request.](./img/quick-response-confirmation.svg)
272
+ </div>
273
+
264
274
  ### Using the conversation history menu
265
275
 
266
276
  The ChatBot history menu contains a log of a users' previous chats. Clicking the menu icon opens a side drawer in the ChatBot window.
@@ -0,0 +1,51 @@
1
+ ---
2
+ # Sidenav top-level section
3
+ # should be the same for all markdown files
4
+ section: PatternFly-AI
5
+ subsection: ChatBot
6
+ # Sidenav secondary level section
7
+ # should be the same for all markdown files
8
+ id: Customizing messages
9
+ source: Customizing messages
10
+ # Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
11
+ # If you use typescript, the name of the interface to display props for
12
+ # These are found through the sourceProps function provided in patternfly-docs.source.js
13
+ sortValue: 60
14
+ ---
15
+
16
+ ## Modifying static content
17
+
18
+ The ChatBot extension `<Message>` component transforms Markdown to PatternFly React components via [react-markdown](https://github.com/remarkjs/react-markdown), which supports both [rehype](https://unifiedjs.com/explore/package/rehype/) and [remark](https://unifiedjs.com/explore/package/remark/) plugins for further output customization.
19
+
20
+ remark parses Markdown as input and serializes Markdown as output, while rehype does the same for HTML. This allows you to target and make transformations at specific checkpoints in the transformation process: either while the text tree is still in Markdown, or while the text tree is in HTML format. For more detailed information on the architecture of this library, see the [react-markdown documentation](https://github.com/remarkjs/react-markdown?tab=readme-ov-file#architecture).
21
+
22
+ You may need these plugins if, for example, you wanted to change the `href` on a link based on the link text. The `<Message>` prop `rehypePlugins` will accept any custom rehype plugins. We use already use these plugins in ChatBot to [render images a certain way](https://www.npmjs.com/package/rehype-unwrap-images) and [handle external links](https://www.npmjs.com/package/rehype-external-links).
23
+
24
+ There are many open source libraries available for other common customization needs. If you can't find one for your use case, [Unified](https://unifiedjs.com/) has a helpful [guide on creating custom plugins](https://unifiedjs.com/learn/guide/create-a-rehype-plugin/).
25
+ For a more direct example, if we wanted to change the `href` on links that included the text string `react`, we could write a very basic plugin like this:
26
+
27
+ ```
28
+ import { visit } from 'unist-util-visit';
29
+
30
+ export const rehypeLinkHrefUpdater = (options) => (tree) => {
31
+ visit(tree, 'element', (node) => {
32
+ if (node.tagName === 'a' && node.properties) {
33
+ if (node.properties.href.includes('react')) {
34
+ node.properties.href = '#';
35
+ }
36
+ }
37
+ });
38
+ };
39
+
40
+ ```
41
+
42
+ You could then pass `[rehypeLinkHrefUpdater]` to the `additionalRehypePlugins` prop on `<Message>` to have this applied to all relevant links read by that `<Message>` component.
43
+
44
+ ## Modifying dynamic content
45
+
46
+ Props can also be used to modify dynamic content in messages.
47
+
48
+ Continuing with our link modification example, let's say you also wanted to add custom `onClick` events. In this case, you would not use `remark` or `rehype`, since they're for static tree manipulation.
49
+
50
+ Instead, you can utilize ChatBot features to customize dynamic content. We offer many `<Message>` props that allow you to implement custom behavior.
51
+ For example, you can use `linkProps` to pass `onClick` events and other PatternFly `<Button>` props down to links. A very basic example would be `linkProps={{onClick: (event) => console.log(event}}`, which would apply to every link in the `<Message>`. Or, you could use the `event.target`, adding your own custom `onClick` logic based on the `innerText`, `innerHTML`, or other attributes of the `event.target`.
@@ -15,11 +15,13 @@ export const BotMessageExample: FunctionComponent = () => {
15
15
  const [variant, setVariant] = useState<string>('Code');
16
16
  const [isOpen, setIsOpen] = useState(false);
17
17
  const [selected, setSelected] = useState<string>('Message content type');
18
+ const [isExpandable, setIsExpanded] = useState(false);
18
19
 
19
20
  /* eslint-disable indent */
20
21
  const renderContent = () => {
21
22
  switch (variant) {
22
23
  case 'Code':
24
+ case 'Expandable code':
23
25
  return code;
24
26
  case 'Heading':
25
27
  return heading;
@@ -166,6 +168,11 @@ _Italic text, formatted with single underscores_
166
168
  setVariant(value);
167
169
  setSelected(value as string);
168
170
  setIsOpen(false);
171
+ if (value === 'Expandable code') {
172
+ setIsExpanded(true);
173
+ } else {
174
+ setIsExpanded(false);
175
+ }
169
176
  };
170
177
 
171
178
  const onToggleClick = () => {
@@ -237,6 +244,7 @@ _Italic text, formatted with single underscores_
237
244
  >
238
245
  <SelectList>
239
246
  <SelectOption value="Code">Code</SelectOption>
247
+ <SelectOption value="Expandable code">Expandable code</SelectOption>
240
248
  <SelectOption value="Inline code">Inline code</SelectOption>
241
249
  <SelectOption value="Heading">Heading</SelectOption>
242
250
  <SelectOption value="Block quotes">Block quotes</SelectOption>
@@ -259,6 +267,7 @@ _Italic text, formatted with single underscores_
259
267
  variant === 'Table' ? { 'aria-label': 'App information and user roles for bot messages' } : undefined
260
268
  }
261
269
  error={variant === 'Error' ? error : undefined}
270
+ codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
262
271
  />
263
272
  </>
264
273
  );
@@ -15,11 +15,13 @@ export const UserMessageExample: FunctionComponent = () => {
15
15
  const [isEditable, setIsEditable] = useState<boolean>(true);
16
16
  const [isOpen, setIsOpen] = useState<boolean>(false);
17
17
  const [selected, setSelected] = useState<string>('Message content type');
18
+ const [isExpandable, setIsExpanded] = useState(false);
18
19
 
19
20
  /* eslint-disable indent */
20
21
  const renderContent = () => {
21
22
  switch (variant) {
22
23
  case 'Code':
24
+ case 'Expandable code':
23
25
  return code;
24
26
  case 'Inline code':
25
27
  return inlineCode;
@@ -166,6 +168,11 @@ _Italic text, formatted with single underscores_
166
168
  setVariant(value);
167
169
  setSelected(value as string);
168
170
  setIsOpen(false);
171
+ if (value === 'Expandable code') {
172
+ setIsExpanded(true);
173
+ } else {
174
+ setIsExpanded(false);
175
+ }
169
176
  };
170
177
 
171
178
  const onToggleClick = () => {
@@ -215,6 +222,7 @@ _Italic text, formatted with single underscores_
215
222
  >
216
223
  <SelectList>
217
224
  <SelectOption value="Code">Code</SelectOption>
225
+ <SelectOption value="Expandable code">Expandable code</SelectOption>
218
226
  <SelectOption value="Inline code">Inline code</SelectOption>
219
227
  <SelectOption value="Heading">Heading</SelectOption>
220
228
  <SelectOption value="Block quotes">Block quotes</SelectOption>
@@ -241,6 +249,7 @@ _Italic text, formatted with single underscores_
241
249
  error={variant === 'Error' ? error : undefined}
242
250
  onEditUpdate={() => setIsEditable(false)}
243
251
  onEditCancel={() => setIsEditable(false)}
252
+ codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
244
253
  />
245
254
  </>
246
255
  );