@patternfly/chatbot 6.5.0-prerelease.1 → 6.5.0-prerelease.11

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 (118) hide show
  1. package/dist/cjs/AttachMenu/AttachMenu.d.ts +8 -2
  2. package/dist/cjs/AttachMenu/AttachMenu.js +2 -2
  3. package/dist/cjs/ChatbotContent/ChatbotContent.d.ts +2 -0
  4. package/dist/cjs/ChatbotContent/ChatbotContent.js +2 -2
  5. package/dist/cjs/ChatbotContent/ChatbotContent.test.js +4 -0
  6. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
  7. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
  8. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
  9. package/dist/cjs/ChatbotFooter/ChatbotFooter.d.ts +5 -2
  10. package/dist/cjs/ChatbotFooter/ChatbotFooter.js +2 -2
  11. package/dist/cjs/ChatbotFooter/ChatbotFooter.test.js +5 -1
  12. package/dist/cjs/CodeModal/CodeModal.js +40 -4
  13. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
  14. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
  15. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
  16. package/dist/cjs/Message/Message.d.ts +7 -20
  17. package/dist/cjs/Message/Message.js +11 -8
  18. package/dist/cjs/Message/Message.test.js +42 -0
  19. package/dist/cjs/Message/MessageLoading.d.ts +2 -1
  20. package/dist/cjs/Message/MessageLoading.js +1 -1
  21. package/dist/cjs/Message/TableMessage/TableMessage.d.ts +4 -1
  22. package/dist/cjs/Message/TableMessage/TableMessage.js +2 -2
  23. package/dist/cjs/Message/TextMessage/TextMessage.d.ts +4 -1
  24. package/dist/cjs/Message/TextMessage/TextMessage.js +2 -2
  25. package/dist/cjs/MessageBar/AttachButton.d.ts +2 -0
  26. package/dist/cjs/MessageBar/AttachButton.js +2 -2
  27. package/dist/cjs/MessageBar/AttachButton.test.js +4 -0
  28. package/dist/cjs/MessageBar/MessageBar.d.ts +16 -6
  29. package/dist/cjs/MessageBar/MessageBar.js +6 -5
  30. package/dist/cjs/MessageBar/MessageBar.test.js +62 -0
  31. package/dist/cjs/__mocks__/monaco-editor.d.ts +11 -0
  32. package/dist/cjs/__mocks__/monaco-editor.js +18 -0
  33. package/dist/cjs/__mocks__/rehype-highlight.d.ts +2 -0
  34. package/dist/cjs/__mocks__/rehype-highlight.js +4 -0
  35. package/dist/css/main.css +84 -13
  36. package/dist/css/main.css.map +1 -1
  37. package/dist/esm/AttachMenu/AttachMenu.d.ts +8 -2
  38. package/dist/esm/AttachMenu/AttachMenu.js +2 -2
  39. package/dist/esm/ChatbotContent/ChatbotContent.d.ts +2 -0
  40. package/dist/esm/ChatbotContent/ChatbotContent.js +2 -2
  41. package/dist/esm/ChatbotContent/ChatbotContent.test.js +4 -0
  42. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
  43. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
  44. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
  45. package/dist/esm/ChatbotFooter/ChatbotFooter.d.ts +5 -2
  46. package/dist/esm/ChatbotFooter/ChatbotFooter.js +2 -2
  47. package/dist/esm/ChatbotFooter/ChatbotFooter.test.js +5 -1
  48. package/dist/esm/CodeModal/CodeModal.js +42 -6
  49. package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
  50. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
  51. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
  52. package/dist/esm/Message/Message.d.ts +7 -20
  53. package/dist/esm/Message/Message.js +11 -8
  54. package/dist/esm/Message/Message.test.js +43 -1
  55. package/dist/esm/Message/MessageLoading.d.ts +2 -1
  56. package/dist/esm/Message/MessageLoading.js +1 -1
  57. package/dist/esm/Message/TableMessage/TableMessage.d.ts +4 -1
  58. package/dist/esm/Message/TableMessage/TableMessage.js +2 -2
  59. package/dist/esm/Message/TextMessage/TextMessage.d.ts +4 -1
  60. package/dist/esm/Message/TextMessage/TextMessage.js +2 -2
  61. package/dist/esm/MessageBar/AttachButton.d.ts +2 -0
  62. package/dist/esm/MessageBar/AttachButton.js +2 -2
  63. package/dist/esm/MessageBar/AttachButton.test.js +4 -0
  64. package/dist/esm/MessageBar/MessageBar.d.ts +16 -6
  65. package/dist/esm/MessageBar/MessageBar.js +6 -5
  66. package/dist/esm/MessageBar/MessageBar.test.js +62 -0
  67. package/dist/esm/__mocks__/monaco-editor.d.ts +11 -0
  68. package/dist/esm/__mocks__/monaco-editor.js +18 -0
  69. package/dist/esm/__mocks__/rehype-highlight.d.ts +2 -0
  70. package/dist/esm/__mocks__/rehype-highlight.js +2 -0
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +5 -2
  73. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +1 -0
  74. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +1 -0
  75. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +3 -1
  76. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithActions.tsx +14 -14
  77. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSelection.tsx +14 -14
  78. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarAttach.tsx +2 -2
  79. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarIndicatorThinking.tsx +15 -0
  80. package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +1 -1
  81. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +10 -0
  82. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +12 -4
  83. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +2 -2
  84. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +1 -1
  85. package/patternfly-docs/content/extensions/chatbot/examples/demos/WhiteEmbeddedChatbot.tsx +451 -0
  86. package/patternfly-docs/patternfly-docs.config.js +1 -0
  87. package/src/AttachMenu/AttachMenu.tsx +26 -11
  88. package/src/Chatbot/Chatbot.scss +23 -1
  89. package/src/ChatbotContent/ChatbotContent.scss +4 -0
  90. package/src/ChatbotContent/ChatbotContent.test.tsx +5 -0
  91. package/src/ChatbotContent/ChatbotContent.tsx +4 -1
  92. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +5 -0
  93. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +7 -4
  94. package/src/ChatbotFooter/ChatbotFooter.scss +21 -0
  95. package/src/ChatbotFooter/ChatbotFooter.test.tsx +10 -1
  96. package/src/ChatbotFooter/ChatbotFooter.tsx +10 -3
  97. package/src/ChatbotHeader/ChatbotHeader.scss +19 -0
  98. package/src/CodeModal/CodeModal.tsx +58 -7
  99. package/src/FileDetailsLabel/FileDetailsLabel.tsx +2 -2
  100. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +7 -2
  101. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +9 -2
  102. package/src/Message/Message.scss +3 -3
  103. package/src/Message/Message.test.tsx +60 -1
  104. package/src/Message/Message.tsx +23 -33
  105. package/src/Message/MessageLoading.scss +7 -0
  106. package/src/Message/MessageLoading.tsx +2 -2
  107. package/src/Message/TableMessage/TableMessage.scss +4 -0
  108. package/src/Message/TableMessage/TableMessage.tsx +6 -2
  109. package/src/Message/TextMessage/TextMessage.scss +12 -0
  110. package/src/Message/TextMessage/TextMessage.tsx +11 -2
  111. package/src/Message/UserFeedback/UserFeedback.scss +2 -1
  112. package/src/MessageBar/AttachButton.test.tsx +4 -0
  113. package/src/MessageBar/AttachButton.tsx +4 -1
  114. package/src/MessageBar/MessageBar.scss +11 -5
  115. package/src/MessageBar/MessageBar.test.tsx +102 -1
  116. package/src/MessageBar/MessageBar.tsx +44 -11
  117. package/src/__mocks__/monaco-editor.ts +19 -0
  118. package/src/__mocks__/rehype-highlight.ts +3 -0
@@ -16,12 +16,12 @@ import { Button, Icon, Tooltip } from '@patternfly/react-core';
16
16
  import { useDropzone } from 'react-dropzone';
17
17
  import { PaperclipIcon } from '@patternfly/react-icons/dist/esm/icons/paperclip-icon';
18
18
  const AttachButtonBase = (_a) => {
19
- var { onAttachAccepted, onClick, isDisabled, className, tooltipProps, innerRef, tooltipContent = 'Attach', inputTestId, isCompact, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps } = _a, props = __rest(_a, ["onAttachAccepted", "onClick", "isDisabled", "className", "tooltipProps", "innerRef", "tooltipContent", "inputTestId", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps"]);
19
+ var { onAttachAccepted, onClick, isDisabled, className, tooltipProps, innerRef, tooltipContent = 'Attach', inputTestId, isCompact, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps, icon = _jsx(PaperclipIcon, {}) } = _a, props = __rest(_a, ["onAttachAccepted", "onClick", "isDisabled", "className", "tooltipProps", "innerRef", "tooltipContent", "inputTestId", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps", "icon"]);
20
20
  const { open, getInputProps } = useDropzone(Object.assign({ multiple: true, onDropAccepted: onAttachAccepted, accept: allowedFileTypes, minSize,
21
21
  maxSize,
22
22
  maxFiles, disabled: isAttachmentDisabled, onDrop: onAttach, onDropRejected: onAttachRejected, validator }, dropzoneProps));
23
23
  return (_jsxs(_Fragment, { children: [_jsx("input", Object.assign({ "data-testid": inputTestId }, getInputProps(), { hidden: true })), _jsx(Tooltip, Object.assign({ id: "pf-chatbot__tooltip--attach", content: tooltipContent, position: "top", entryDelay: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.entryDelay) || 0, exitDelay: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.exitDelay) || 0, distance: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.distance) || 8, animationDuration: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.animationDuration) || 0,
24
24
  // prevents VO announcements of both aria label and tooltip
25
- aria: "none" }, tooltipProps, { children: _jsx(Button, Object.assign({ variant: "plain", ref: innerRef, className: `pf-chatbot__button--attach ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": props['aria-label'] || 'Attach', isDisabled: isDisabled, onClick: onClick !== null && onClick !== void 0 ? onClick : open, icon: _jsx(Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children: _jsx(PaperclipIcon, {}) }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
25
+ aria: "none" }, tooltipProps, { children: _jsx(Button, Object.assign({ variant: "plain", ref: innerRef, className: `pf-chatbot__button--attach ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": props['aria-label'] || 'Attach', isDisabled: isDisabled, onClick: onClick !== null && onClick !== void 0 ? onClick : open, icon: _jsx(Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children: icon }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
26
26
  };
27
27
  export const AttachButton = forwardRef((props, ref) => (_jsx(AttachButtonBase, Object.assign({ innerRef: ref }, props))));
@@ -140,4 +140,8 @@ describe('Attach button', () => {
140
140
  expect(validator).toHaveBeenCalledWith(file);
141
141
  expect(onAttachRejected).toHaveBeenCalled();
142
142
  }));
143
+ it('should handle icon prop', () => {
144
+ render(_jsx(AttachButton, { icon: _jsx("img", { alt: "", src: "" }) }));
145
+ expect(screen.getByRole('img')).toBeVisible();
146
+ });
143
147
  });
@@ -1,6 +1,7 @@
1
1
  import type { FunctionComponent } from 'react';
2
2
  import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
3
- import { ButtonProps, TextAreaProps, TooltipProps } from '@patternfly/react-core';
3
+ import { ButtonProps, MenuSearchInputProps, MenuSearchProps, SearchInputProps, TextAreaProps, TooltipProps } from '@patternfly/react-core';
4
+ import { AttachButtonProps } from './AttachButton';
4
5
  import { ChatbotDisplayMode } from '../Chatbot';
5
6
  export interface MessageBarWithAttachMenuProps {
6
7
  /** Flag to enable whether attach menu is open */
@@ -12,7 +13,7 @@ export interface MessageBarWithAttachMenuProps {
12
13
  /** A callback for when the attachment menu toggle is clicked */
13
14
  onAttachMenuToggleClick: () => void;
14
15
  /** A callback for when the input value in the menu changes. */
15
- onAttachMenuInputChange: (value: string) => void;
16
+ onAttachMenuInputChange?: (value: string) => void;
16
17
  /** Function callback called when user selects item in menu. */
17
18
  onAttachMenuSelect?: (event?: React.MouseEvent<Element, MouseEvent>, value?: string | number) => void;
18
19
  /** Placeholder for search input */
@@ -21,6 +22,12 @@ export interface MessageBarWithAttachMenuProps {
21
22
  onAttachMenuOnOpenChangeKeys?: string[];
22
23
  /** Callback to change the open state of the menu. Triggered by clicking outside of the menu. */
23
24
  onAttachMenuOpenChange?: (isOpen: boolean) => void;
25
+ /** Additional props passed to MenuSearch component in attach menu */
26
+ menuSearchProps?: Omit<MenuSearchProps, 'ref'>;
27
+ /** Additional props passed to MenuSearchInput component in attach menu */
28
+ menuSearchInputProps?: Omit<MenuSearchInputProps, 'ref'>;
29
+ /** Additional props passed to SearchInput component in attach menu */
30
+ searchInputProps?: SearchInputProps;
24
31
  }
25
32
  export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
26
33
  /** Callback to get the value of input message by user */
@@ -71,11 +78,8 @@ export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
71
78
  isSendButtonDisabled?: boolean;
72
79
  /** Prop to allow passage of additional props to buttons */
73
80
  buttonProps?: {
74
- attach?: {
75
- tooltipContent?: string;
81
+ attach?: AttachButtonProps & {
76
82
  props?: ButtonProps;
77
- inputTestId?: string;
78
- tooltipProps?: Omit<TooltipProps, 'content'>;
79
83
  };
80
84
  stop?: {
81
85
  tooltipContent?: string;
@@ -105,6 +109,12 @@ export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
105
109
  isCompact?: boolean;
106
110
  /** Ref applied to message bar textarea, for use with focus or other custom behaviors */
107
111
  innerRef?: React.Ref<HTMLTextAreaElement>;
112
+ /** Sets background color to primary */
113
+ isPrimary?: boolean;
114
+ /** @beta Flag indicating whether the message bar has an AI indicator border. */
115
+ hasAiIndicator?: boolean;
116
+ /** @beta Flag indicating whether the chatbot is thinking in response to a query, adding an animation to the message bar. */
117
+ isThinking?: boolean;
108
118
  }
109
119
  export declare const MessageBarBase: FunctionComponent<MessageBarProps>;
110
120
  declare const MessageBar: import("react").ForwardRefExoticComponent<MessageBarProps & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
14
14
  import { TextArea } from '@patternfly/react-core';
15
+ import { css } from '@patternfly/react-styles';
15
16
  // Import Chatbot components
16
17
  import SendButton from './SendButton';
17
18
  import MicrophoneButton from './MicrophoneButton';
@@ -20,7 +21,7 @@ import AttachMenu from '../AttachMenu';
20
21
  import StopButton from './StopButton';
21
22
  export const MessageBarBase = (_a) => {
22
23
  var _b;
23
- var { onSendMessage, className, alwayShowSendButton, placeholder = 'Send a message...', hasAttachButton = true, hasMicrophoneButton, listeningText = 'Listening', handleAttach, attachMenuProps, isSendButtonDisabled, handleStopButton, hasStopButton, buttonProps, onChange, displayMode, value, isCompact = false, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps, innerRef } = _a, props = __rest(_a, ["onSendMessage", "className", "alwayShowSendButton", "placeholder", "hasAttachButton", "hasMicrophoneButton", "listeningText", "handleAttach", "attachMenuProps", "isSendButtonDisabled", "handleStopButton", "hasStopButton", "buttonProps", "onChange", "displayMode", "value", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps", "innerRef"]);
24
+ var { onSendMessage, className, alwayShowSendButton, placeholder = 'Send a message...', hasAttachButton = true, hasMicrophoneButton, listeningText = 'Listening', handleAttach, attachMenuProps, isSendButtonDisabled, handleStopButton, hasStopButton, buttonProps, onChange, displayMode, value, isCompact = false, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps, innerRef, isPrimary, hasAiIndicator, isThinking } = _a, props = __rest(_a, ["onSendMessage", "className", "alwayShowSendButton", "placeholder", "hasAttachButton", "hasMicrophoneButton", "listeningText", "handleAttach", "attachMenuProps", "isSendButtonDisabled", "handleStopButton", "hasStopButton", "buttonProps", "onChange", "displayMode", "value", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps", "innerRef", "isPrimary", "hasAiIndicator", "isThinking"]);
24
25
  // Text Input
25
26
  // --------------------------------------------------------------------------
26
27
  const [message, setMessage] = useState(value !== null && value !== void 0 ? value : '');
@@ -187,11 +188,11 @@ export const MessageBarBase = (_a) => {
187
188
  onChange && onChange({}, message);
188
189
  };
189
190
  const renderButtons = () => {
190
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
191
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
191
192
  if (hasStopButton && handleStopButton) {
192
193
  return (_jsx(StopButton, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact, tooltipProps: (_b = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _b === void 0 ? void 0 : _b.tooltipProps }, (_c = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _c === void 0 ? void 0 : _c.props)));
193
194
  }
194
- return (_jsxs(_Fragment, { children: [attachMenuProps && (_jsx(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))), !attachMenuProps && hasAttachButton && (_jsx(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))), hasMicrophoneButton && (_jsx(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))), (alwayShowSendButton || message) && (_jsx(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))] }));
195
+ return (_jsxs(_Fragment, { children: [attachMenuProps && (_jsx(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach))), !attachMenuProps && hasAttachButton && (_jsx(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.tooltipContent, inputTestId: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.inputTestId, isCompact: isCompact, tooltipProps: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach, (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.props))), hasMicrophoneButton && (_jsx(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _k === void 0 ? void 0 : _k.tooltipContent, language: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.language, isCompact: isCompact, tooltipProps: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.tooltipProps }, (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.props))), (alwayShowSendButton || message) && (_jsx(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _p === void 0 ? void 0 : _p.tooltipContent, isCompact: isCompact, tooltipProps: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipProps }, (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.props)))] }));
195
196
  };
196
197
  const messageBarContents = (_jsxs(_Fragment, { children: [_jsx("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: _jsx(TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd }, props)) }), _jsx("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
197
198
  if (attachMenuProps) {
@@ -200,9 +201,9 @@ export const MessageBarBase = (_a) => {
200
201
  (_a = attachButtonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
201
202
  attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.setIsAttachMenuOpen(isAttachMenuOpen);
202
203
  (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuOpenChange) && (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuOpenChange(isAttachMenuOpen));
203
- }, onOpenChangeKeys: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuOnOpenChangeKeys, onSelect: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuSelect }, (attachMenuProps && { handleTextInputChange: attachMenuProps.onAttachMenuInputChange }), { popperProps: { direction: 'up', distance: 8 }, searchInputPlaceholder: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.attachMenuInputPlaceholder })));
204
+ }, onOpenChangeKeys: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuOnOpenChangeKeys, onSelect: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuSelect }, (attachMenuProps && { handleTextInputChange: attachMenuProps.onAttachMenuInputChange }), { popperProps: { direction: 'up', distance: 8 }, searchInputPlaceholder: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.attachMenuInputPlaceholder }, attachMenuProps)));
204
205
  }
205
- return _jsx("div", { className: `pf-chatbot__message-bar ${className !== null && className !== void 0 ? className : ''}`, children: messageBarContents });
206
+ return (_jsx("div", { className: css('pf-chatbot__message-bar', isPrimary && 'pf-m-primary', hasAiIndicator && 'pf-v6-m-ai-indicator', isThinking && 'pf-v6-m-thinking', className), children: messageBarContents }));
206
207
  };
207
208
  const MessageBar = forwardRef((props, ref) => (_jsx(MessageBarBase, Object.assign({ innerRef: ref }, props))));
208
209
  export { MessageBar };
@@ -154,6 +154,48 @@ describe('Message bar', () => {
154
154
  yield userEvent.click(attachButton);
155
155
  expect(attachToggleClickSpy).toHaveBeenCalledTimes(1);
156
156
  }));
157
+ it('can pass searchInputProps to search input in AttachMenu', () => {
158
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, value: "test", attachMenuProps: {
159
+ isAttachMenuOpen: true,
160
+ setIsAttachMenuOpen: jest.fn(),
161
+ onAttachMenuToggleClick: jest.fn(),
162
+ onAttachMenuInputChange: jest.fn(),
163
+ attachMenuItems: ATTACH_MENU_ITEMS,
164
+ searchInputProps: { isDisabled: true }
165
+ } }));
166
+ expect(screen.getByRole('textbox', { name: /Filter menu items/i })).toBeDisabled();
167
+ });
168
+ it('can pass menuSearchProps to search input in AttachMenu', () => {
169
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, value: "test", attachMenuProps: {
170
+ isAttachMenuOpen: true,
171
+ setIsAttachMenuOpen: jest.fn(),
172
+ onAttachMenuToggleClick: jest.fn(),
173
+ onAttachMenuInputChange: jest.fn(),
174
+ attachMenuItems: ATTACH_MENU_ITEMS,
175
+ menuSearchProps: { 'data-testid': 'menu-search' }
176
+ } }));
177
+ expect(screen.getByTestId('menu-search')).toBeTruthy();
178
+ });
179
+ it('can pass menuSearchInputProps to search input in AttachMenu', () => {
180
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, value: "test", attachMenuProps: {
181
+ isAttachMenuOpen: true,
182
+ setIsAttachMenuOpen: jest.fn(),
183
+ onAttachMenuToggleClick: jest.fn(),
184
+ onAttachMenuInputChange: jest.fn(),
185
+ attachMenuItems: ATTACH_MENU_ITEMS,
186
+ menuSearchInputProps: { 'data-testid': 'menu-search-input' }
187
+ } }));
188
+ expect(screen.getByTestId('menu-search-input')).toBeTruthy();
189
+ });
190
+ it('can remove input from attach menu', () => __awaiter(void 0, void 0, void 0, function* () {
191
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, attachMenuProps: {
192
+ isAttachMenuOpen: true,
193
+ setIsAttachMenuOpen: jest.fn(),
194
+ onAttachMenuToggleClick: jest.fn(),
195
+ attachMenuItems: ATTACH_MENU_ITEMS
196
+ } }));
197
+ expect(screen.queryByRole('textbox', { name: /Filter menu items/i })).not.toBeInTheDocument();
198
+ }));
157
199
  it('can hide attach button', () => {
158
200
  render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: false }));
159
201
  expect(screen.queryByRole('button', { name: 'Attach' })).toBeFalsy();
@@ -185,6 +227,14 @@ describe('Message bar', () => {
185
227
  render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: { attach: { props: { 'aria-label': 'Test' } } } }));
186
228
  yield userEvent.click(screen.getByRole('button', { name: 'Test' }));
187
229
  }));
230
+ it('can change attach button icon', () => {
231
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: {
232
+ attach: {
233
+ icon: _jsx("img", { alt: "", src: "" })
234
+ }
235
+ } }));
236
+ expect(screen.getByRole('img')).toBeVisible();
237
+ });
188
238
  // Stop button
189
239
  // --------------------------------------------------------------------------
190
240
  it('can show stop button', () => {
@@ -264,4 +314,16 @@ describe('Message bar', () => {
264
314
  (_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus();
265
315
  expect(document.activeElement).toBe(screen.getByRole('textbox'));
266
316
  });
317
+ it('should handle isPrimary', () => {
318
+ const { container } = render(_jsx(MessageBar, { isPrimary: true, onSendMessage: jest.fn }));
319
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
320
+ });
321
+ it('Renders with class pf-v6-m-ai-indicator when hasAiIndicator is true', () => {
322
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAiIndicator: true }));
323
+ expect(screen.getByRole('textbox').closest('.pf-chatbot__message-bar')).toHaveClass('pf-v6-m-ai-indicator');
324
+ });
325
+ it('Renders with class pf-v6-m-thinking when isThinking is true', () => {
326
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, isThinking: true }));
327
+ expect(screen.getByRole('textbox').closest('.pf-chatbot__message-bar')).toHaveClass('pf-v6-m-thinking');
328
+ });
267
329
  });
@@ -0,0 +1,11 @@
1
+ declare const mockEditor: {
2
+ layout: jest.Mock<any, any, any>;
3
+ focus: jest.Mock<any, any, any>;
4
+ dispose: jest.Mock<any, any, any>;
5
+ getModel: jest.Mock<any, any, any>;
6
+ updateOptions: jest.Mock<any, any, any>;
7
+ };
8
+ declare const mockModel: {
9
+ updateOptions: jest.Mock<any, any, any>;
10
+ dispose: jest.Mock<any, any, any>;
11
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ const mockEditor = {
3
+ layout: jest.fn(),
4
+ focus: jest.fn(),
5
+ dispose: jest.fn(),
6
+ getModel: jest.fn(),
7
+ updateOptions: jest.fn()
8
+ };
9
+ const mockModel = {
10
+ updateOptions: jest.fn(),
11
+ dispose: jest.fn()
12
+ };
13
+ module.exports = {
14
+ editor: {
15
+ create: jest.fn(() => mockEditor),
16
+ getModels: jest.fn(() => [mockModel])
17
+ }
18
+ };
@@ -0,0 +1,2 @@
1
+ declare const rehypeHighlight: () => (tree: any) => any;
2
+ export default rehypeHighlight;
@@ -0,0 +1,2 @@
1
+ const rehypeHighlight = () => (tree) => tree;
2
+ export default rehypeHighlight;
@@ -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/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.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/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/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/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/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/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../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/SuperscriptMessage/SuperscriptMessage.tsx","../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/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/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/SourcesCardBase/SourcesCardBase.test.tsx","../src/SourcesCardBase/SourcesCardBase.tsx","../src/SourcesCardBase/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolCall/ToolCall.test.tsx","../src/ToolCall/ToolCall.tsx","../src/ToolCall/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/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/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.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/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/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/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/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/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../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/SuperscriptMessage/SuperscriptMessage.tsx","../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/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/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/SourcesCardBase/SourcesCardBase.test.tsx","../src/SourcesCardBase/SourcesCardBase.tsx","../src/SourcesCardBase/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolCall/ToolCall.test.tsx","../src/ToolCall/ToolCall.tsx","../src/ToolCall/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/monaco-editor.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-highlight.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.5.0-prerelease.1",
3
+ "version": "6.5.0-prerelease.11",
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",
@@ -37,12 +37,15 @@
37
37
  "@patternfly/react-core": "^6.1.0",
38
38
  "@patternfly/react-icons": "^6.1.0",
39
39
  "@patternfly/react-table": "^6.1.0",
40
+ "@patternfly/react-styles": "^6.1.0",
40
41
  "@segment/analytics-next": "^1.76.0",
41
42
  "clsx": "^2.1.0",
43
+ "monaco-editor": "^0.54.0",
42
44
  "path-browserify": "^1.0.1",
43
45
  "posthog-js": "^1.194.4",
44
46
  "react-markdown": "^9.0.1",
45
47
  "rehype-external-links": "^3.0.0",
48
+ "rehype-highlight": "^7.0.0",
46
49
  "rehype-sanitize": "^6.0.0",
47
50
  "rehype-unwrap-images": "^1.0.0",
48
51
  "remark-gfm": "^4.0.0",
@@ -54,7 +57,7 @@
54
57
  },
55
58
  "devDependencies": {
56
59
  "@octokit/rest": "^18.0.0",
57
- "@patternfly/documentation-framework": "6.28.6",
60
+ "@patternfly/documentation-framework": "6.28.9",
58
61
  "@patternfly/patternfly": "^6.1.0",
59
62
  "@patternfly/patternfly-a11y": "^5.0.0",
60
63
  "@types/dom-speech-recognition": "^0.0.4",
@@ -318,6 +318,7 @@ _Italic text, formatted with single underscores_
318
318
  content="This bot has a square avatar. You can further customize the avatar by applying an additional class or passing [PatternFly avatar props](/components/avatar) to the `<Message>` component via `avatarProps`."
319
319
  hasRoundAvatar={false}
320
320
  />
321
+ <Message name="Bot" role="bot" content="This is a message from a bot with no avatar." />
321
322
  <Select
322
323
  id="single-select"
323
324
  isOpen={isOpen}
@@ -333,6 +333,7 @@ _Italic text, formatted with single underscores_
333
333
  avatar={userAvatar}
334
334
  avatarProps={{ isBordered: true }}
335
335
  />
336
+ <Message name="User" role="user" content="This is a user message with no avatar" />
336
337
  <Message
337
338
  name="User"
338
339
  role="user"
@@ -366,7 +366,9 @@ Setting up cluster console...`;
366
366
  <FlexItem>{stage.name}</FlexItem>
367
367
  </Flex>
368
368
  </AccordionToggle>
369
- <AccordionContent id={stage.id.replace('-toggle', '')}>{renderCodeBlock(stage)}</AccordionContent>
369
+ <AccordionContent id={stage.id.replace('-toggle', '')} style={{ border: '0px' }}>
370
+ {renderCodeBlock(stage)}
371
+ </AccordionContent>
370
372
  </AccordionItem>
371
373
  ))}
372
374
  </Accordion>
@@ -5,8 +5,8 @@ import ChatbotConversationHistoryNav, {
5
5
  } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
6
6
  import { Checkbox, DropdownItem, DropdownList } from '@patternfly/react-core';
7
7
 
8
- const menuItems = [
9
- <DropdownList key="list-1">
8
+ const generateMenuItems = (id: string) => [
9
+ <DropdownList key={`header-drawer-with-actions-example-conversation-${id}-dropdown`}>
10
10
  <DropdownItem value="Download" id="Download">
11
11
  Download
12
12
  </DropdownItem>
@@ -23,29 +23,29 @@ const menuItems = [
23
23
  ];
24
24
 
25
25
  const conversations: { [key: string]: Conversation[] } = {
26
- Today: [{ id: '1', text: 'Red Hat products and services', menuItems }],
26
+ Today: [{ id: '1', text: 'Red Hat products and services', menuItems: generateMenuItems('1') }],
27
27
  'This month': [
28
28
  {
29
29
  id: '2',
30
30
  text: 'Enterprise Linux installation and setup',
31
- menuItems
31
+ menuItems: generateMenuItems('2')
32
32
  },
33
- { id: '3', text: 'Troubleshoot system crash', menuItems }
33
+ { id: '3', text: 'Troubleshoot system crash', menuItems: generateMenuItems('3') }
34
34
  ],
35
35
  March: [
36
- { id: '4', text: 'Ansible security and updates', menuItems },
37
- { id: '5', text: 'Red Hat certification', menuItems },
38
- { id: '6', text: 'Lightspeed user documentation', menuItems }
36
+ { id: '4', text: 'Ansible security and updates', menuItems: generateMenuItems('4') },
37
+ { id: '5', text: 'Red Hat certification', menuItems: generateMenuItems('5') },
38
+ { id: '6', text: 'Lightspeed user documentation', menuItems: generateMenuItems('6') }
39
39
  ],
40
40
  February: [
41
- { id: '7', text: 'Crashing pod assistance', menuItems },
42
- { id: '8', text: 'OpenShift AI pipelines', menuItems },
43
- { id: '9', text: 'Updating subscription plan', menuItems },
44
- { id: '10', text: 'Red Hat licensing options', menuItems }
41
+ { id: '7', text: 'Crashing pod assistance', menuItems: generateMenuItems('7') },
42
+ { id: '8', text: 'OpenShift AI pipelines', menuItems: generateMenuItems('8') },
43
+ { id: '9', text: 'Updating subscription plan', menuItems: generateMenuItems('9') },
44
+ { id: '10', text: 'Red Hat licensing options', menuItems: generateMenuItems('10') }
45
45
  ],
46
46
  January: [
47
- { id: '11', text: 'RHEL system performance', menuItems },
48
- { id: '12', text: 'Manage user accounts', menuItems }
47
+ { id: '11', text: 'RHEL system performance', menuItems: generateMenuItems('11') },
48
+ { id: '12', text: 'Manage user accounts', menuItems: generateMenuItems('12') }
49
49
  ]
50
50
  };
51
51
 
@@ -5,8 +5,8 @@ import ChatbotConversationHistoryNav, {
5
5
  } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
6
6
  import { Checkbox, DropdownItem, DropdownList } from '@patternfly/react-core';
7
7
 
8
- const menuItems = [
9
- <DropdownList key="list-1">
8
+ const generateMenuItems = (id: string) => [
9
+ <DropdownList key={`header-drawer-with-selections-example-conversation-${id}-dropdown`}>
10
10
  <DropdownItem value="Download" id="Download">
11
11
  Download
12
12
  </DropdownItem>
@@ -29,29 +29,29 @@ export const ChatbotHeaderDrawerWithSelection: FunctionComponent = () => {
29
29
  const displayMode = ChatbotDisplayMode.embedded;
30
30
 
31
31
  const conversations: { [key: string]: Conversation[] } = {
32
- Today: [{ id: '1', text: 'Red Hat products and services', menuItems }],
32
+ Today: [{ id: '1', text: 'Red Hat products and services', menuItems: generateMenuItems('1') }],
33
33
  'This month': [
34
34
  {
35
35
  id: '2',
36
36
  text: 'Enterprise Linux installation and setup',
37
- menuItems
37
+ menuItems: generateMenuItems('2')
38
38
  },
39
- { id: '3', text: 'Troubleshoot system crash', menuItems }
39
+ { id: '3', text: 'Troubleshoot system crash', menuItems: generateMenuItems('3') }
40
40
  ],
41
41
  March: [
42
- { id: '4', text: 'Ansible security and updates', menuItems },
43
- { id: '5', text: 'Red Hat certification', menuItems },
44
- { id: '6', text: 'Lightspeed user documentation', menuItems }
42
+ { id: '4', text: 'Ansible security and updates', menuItems: generateMenuItems('4') },
43
+ { id: '5', text: 'Red Hat certification', menuItems: generateMenuItems('5') },
44
+ { id: '6', text: 'Lightspeed user documentation', menuItems: generateMenuItems('6') }
45
45
  ],
46
46
  February: [
47
- { id: '7', text: 'Crashing pod assistance', menuItems },
48
- { id: '8', text: 'OpenShift AI pipelines', menuItems },
49
- { id: '9', text: 'Updating subscription plan', menuItems },
50
- { id: '10', text: 'Red Hat licensing options', menuItems }
47
+ { id: '7', text: 'Crashing pod assistance', menuItems: generateMenuItems('7') },
48
+ { id: '8', text: 'OpenShift AI pipelines', menuItems: generateMenuItems('8') },
49
+ { id: '9', text: 'Updating subscription plan', menuItems: generateMenuItems('9') },
50
+ { id: '10', text: 'Red Hat licensing options', menuItems: generateMenuItems('10') }
51
51
  ],
52
52
  January: [
53
- { id: '11', text: 'RHEL system performance', menuItems },
54
- { id: '12', text: 'Manage user accounts', menuItems }
53
+ { id: '11', text: 'RHEL system performance', menuItems: generateMenuItems('11') },
54
+ { id: '12', text: 'Manage user accounts', menuItems: generateMenuItems('12') }
55
55
  ]
56
56
  };
57
57
 
@@ -66,7 +66,7 @@ export const ChatbotMessageBarDefaultAttachExample: FunctionComponent = () => {
66
66
  };
67
67
 
68
68
  const initialMenuItems = [
69
- <DropdownList key="list-1">
69
+ <DropdownList key="message-bar-attach-menu-items">
70
70
  <DropdownItem className="pf-chatbot-source-details-dropdown-item" value="auth-operator Pod" id="0">
71
71
  <SourceDetailsMenuItem
72
72
  icon={
@@ -93,7 +93,7 @@ export const ChatbotMessageBarDefaultAttachExample: FunctionComponent = () => {
93
93
  />
94
94
  </DropdownItem>
95
95
  </DropdownList>,
96
- <DropdownGroup key="group2">
96
+ <DropdownGroup key="message-bar-attach-dropdown-group">
97
97
  <DropdownList>
98
98
  <DropdownItem value="Alerts" id="1" icon={<BellIcon />}>
99
99
  Alerts
@@ -0,0 +1,15 @@
1
+ import { FunctionComponent, useState } from 'react';
2
+ import { MessageBar } from '@patternfly/chatbot/dist/dynamic/MessageBar';
3
+
4
+ export const ChatbotMessageBarIndicatorThinking: FunctionComponent = () => {
5
+ const [isThinking, setIsThinking] = useState(false);
6
+ const handleSend = (_message: string | number) => {
7
+ setIsThinking(true);
8
+
9
+ setTimeout(() => {
10
+ setIsThinking(false);
11
+ }, 10000);
12
+ };
13
+
14
+ return <MessageBar onSendMessage={handleSend} hasAiIndicator isThinking={isThinking} />;
15
+ };
@@ -180,7 +180,7 @@ export const SettingsDemo: FunctionComponent = () => {
180
180
  },
181
181
  {
182
182
  id: 'archive-all',
183
- label: 'Archive all chat',
183
+ label: 'Archive all chats',
184
184
  field: (
185
185
  // We want to add the id property here as well so the label is coupled
186
186
  // with the button on screen readers.
@@ -314,6 +314,16 @@ To enable the stop button, set `hasStopButton` to `true` and pass in a `handleSt
314
314
 
315
315
  ```
316
316
 
317
+ ### Message bar with AI indicator styles
318
+
319
+ To add a more pronounced AI indicator style to the message bar, pass `hasAiIndicator` to the `<MessageBar>` component. You can also enable a "thinking" animation by passing in `isThinking`.
320
+
321
+ This example shows a simplified method of handling the "thinking" animation: after a user sends a message, the `isThinking` property is set to `true` to trigger the animation, then returns to `false` after 10 seconds to halt the animation.
322
+
323
+ ```ts file="./ChatbotMessageBarIndicatorThinking.tsx" isBeta
324
+
325
+ ```
326
+
317
327
  ## Navigation
318
328
 
319
329
  ### Side nav in a drawer
@@ -131,15 +131,23 @@ This demo displays a ChatBot in a static, inline drawer. This demo includes:
131
131
 
132
132
  ```
133
133
 
134
+ ### Primary color background
135
+
136
+ This demo displays an embedded ChatBot with a [primary background color](/design-foundations/colors#background-colors). This example includes the same features as the [Embedded ChatBot demo](/patternfly-ai/chatbot/overview/demo/#embedded-chatbot)&mdash;the only differences are that the background color is adjusted via the `isPrimary` prop and some of the sample Messages have changed. You can use the same logic to adjust the background color in any ChatBot layout.
137
+
138
+ ```js file="./WhiteEmbeddedChatbot.tsx" isFullscreen
139
+
140
+ ```
141
+
134
142
  ### Display mode switcher
135
143
 
136
144
  This demo showcases how the ChatBot can be rendered in different display modes to suit various application layouts. It demonstrates how to dynamically change the page structure in response to the user's selection. This demo includes:
137
145
 
138
146
  1. The ability to switch between overlay, drawer, and fullscreen modes using the [`<ChatbotHeaderOptionsDropdown>`](/patternfly-ai/chatbot/ui#header-options) in the header.
139
147
  2. A conditional page layout that renders the ChatBot for each display mode option:
140
- - **Overlay:** As a floating window on top of the page content.
141
- - **Drawer:** Inside an inline PatternFly `<Drawer>` as a side panel.
142
- - **Fullscreen:** As a top-level component that covers the entire screen for an embedded experience.
148
+ - **Overlay:** As a floating window on top of the page content.
149
+ - **Drawer:** Inside an inline PatternFly `<Drawer>` as a side panel.
150
+ - **Fullscreen:** As a top-level component that covers the entire screen for an embedded experience.
143
151
  3. Logic to show or hide the `<ChatbotToggle>` button, which is only present in the default overlay mode.
144
152
  4. A [basic ChatBot](#basic-chatbot) with a header, welcome prompt, and message bar to populate the different layouts.
145
153
 
@@ -170,7 +178,7 @@ Your code structure should look like this:
170
178
 
171
179
  ### Chat transcripts
172
180
 
173
- This demo illustrates how you could add downloadable transcripts to your ChatBot, which outline conversation details in a Markdown file. This approach allows users to easily share information from a conversation with others.
181
+ This demo illustrates how you could add downloadable transcripts to your ChatBot, which outline conversation details in a Markdown file. This approach allows users to easily share information from a conversation with others.
174
182
 
175
183
  A message transcript includes details from a single chat message. To download a sample message transcript in this demo, click the "Download" action under a bot message.
176
184