@patternfly/chatbot 6.5.0-prerelease.2 → 6.5.0-prerelease.21

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 (153) 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/ChatbotFooter/ChatbotFooter.d.ts +5 -2
  4. package/dist/cjs/ChatbotFooter/ChatbotFooter.js +2 -2
  5. package/dist/cjs/ChatbotFooter/ChatbotFooter.test.js +5 -1
  6. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +29 -2
  7. package/dist/cjs/CodeModal/CodeModal.d.ts +2 -0
  8. package/dist/cjs/CodeModal/CodeModal.js +53 -8
  9. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
  10. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  11. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
  12. package/dist/cjs/Message/Message.d.ts +21 -3
  13. package/dist/cjs/Message/Message.js +11 -8
  14. package/dist/cjs/Message/Message.test.js +161 -2
  15. package/dist/cjs/Message/MessageLoading.d.ts +2 -1
  16. package/dist/cjs/Message/MessageLoading.js +1 -1
  17. package/dist/cjs/Message/TableMessage/TableMessage.d.ts +4 -1
  18. package/dist/cjs/Message/TableMessage/TableMessage.js +2 -2
  19. package/dist/cjs/Message/TextMessage/TextMessage.d.ts +4 -1
  20. package/dist/cjs/Message/TextMessage/TextMessage.js +2 -2
  21. package/dist/cjs/MessageBar/AttachButton.d.ts +2 -0
  22. package/dist/cjs/MessageBar/AttachButton.js +2 -2
  23. package/dist/cjs/MessageBar/AttachButton.test.js +4 -0
  24. package/dist/cjs/MessageBar/MessageBar.d.ts +16 -6
  25. package/dist/cjs/MessageBar/MessageBar.js +6 -5
  26. package/dist/cjs/MessageBar/MessageBar.test.js +62 -0
  27. package/dist/cjs/Onboarding/Onboarding.d.ts +36 -0
  28. package/dist/cjs/Onboarding/Onboarding.js +37 -0
  29. package/dist/cjs/Onboarding/Onboarding.test.d.ts +1 -0
  30. package/dist/cjs/Onboarding/Onboarding.test.js +80 -0
  31. package/dist/cjs/Onboarding/index.d.ts +2 -0
  32. package/dist/cjs/Onboarding/index.js +23 -0
  33. package/dist/cjs/ResponseActions/ResponseActions.d.ts +3 -0
  34. package/dist/cjs/ResponseActions/ResponseActions.js +28 -7
  35. package/dist/cjs/ResponseActions/ResponseActions.test.js +67 -12
  36. package/dist/cjs/__mocks__/monaco-editor.d.ts +11 -0
  37. package/dist/cjs/__mocks__/monaco-editor.js +18 -0
  38. package/dist/cjs/__mocks__/rehype-highlight.d.ts +2 -0
  39. package/dist/cjs/__mocks__/rehype-highlight.js +4 -0
  40. package/dist/cjs/index.d.ts +2 -0
  41. package/dist/cjs/index.js +4 -1
  42. package/dist/css/main.css +229 -21
  43. package/dist/css/main.css.map +1 -1
  44. package/dist/dynamic/Onboarding/package.json +1 -0
  45. package/dist/esm/AttachMenu/AttachMenu.d.ts +8 -2
  46. package/dist/esm/AttachMenu/AttachMenu.js +2 -2
  47. package/dist/esm/ChatbotFooter/ChatbotFooter.d.ts +5 -2
  48. package/dist/esm/ChatbotFooter/ChatbotFooter.js +2 -2
  49. package/dist/esm/ChatbotFooter/ChatbotFooter.test.js +5 -1
  50. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +30 -3
  51. package/dist/esm/CodeModal/CodeModal.d.ts +2 -0
  52. package/dist/esm/CodeModal/CodeModal.js +54 -9
  53. package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
  54. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  55. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
  56. package/dist/esm/Message/Message.d.ts +21 -3
  57. package/dist/esm/Message/Message.js +11 -8
  58. package/dist/esm/Message/Message.test.js +161 -2
  59. package/dist/esm/Message/MessageLoading.d.ts +2 -1
  60. package/dist/esm/Message/MessageLoading.js +1 -1
  61. package/dist/esm/Message/TableMessage/TableMessage.d.ts +4 -1
  62. package/dist/esm/Message/TableMessage/TableMessage.js +2 -2
  63. package/dist/esm/Message/TextMessage/TextMessage.d.ts +4 -1
  64. package/dist/esm/Message/TextMessage/TextMessage.js +2 -2
  65. package/dist/esm/MessageBar/AttachButton.d.ts +2 -0
  66. package/dist/esm/MessageBar/AttachButton.js +2 -2
  67. package/dist/esm/MessageBar/AttachButton.test.js +4 -0
  68. package/dist/esm/MessageBar/MessageBar.d.ts +16 -6
  69. package/dist/esm/MessageBar/MessageBar.js +6 -5
  70. package/dist/esm/MessageBar/MessageBar.test.js +62 -0
  71. package/dist/esm/Onboarding/Onboarding.d.ts +36 -0
  72. package/dist/esm/Onboarding/Onboarding.js +30 -0
  73. package/dist/esm/Onboarding/Onboarding.test.d.ts +1 -0
  74. package/dist/esm/Onboarding/Onboarding.test.js +75 -0
  75. package/dist/esm/Onboarding/index.d.ts +2 -0
  76. package/dist/esm/Onboarding/index.js +2 -0
  77. package/dist/esm/ResponseActions/ResponseActions.d.ts +3 -0
  78. package/dist/esm/ResponseActions/ResponseActions.js +28 -7
  79. package/dist/esm/ResponseActions/ResponseActions.test.js +67 -12
  80. package/dist/esm/__mocks__/monaco-editor.d.ts +11 -0
  81. package/dist/esm/__mocks__/monaco-editor.js +18 -0
  82. package/dist/esm/__mocks__/rehype-highlight.d.ts +2 -0
  83. package/dist/esm/__mocks__/rehype-highlight.js +2 -0
  84. package/dist/esm/index.d.ts +2 -0
  85. package/dist/esm/index.js +2 -0
  86. package/dist/tsconfig.tsbuildinfo +1 -1
  87. package/package.json +14 -2
  88. package/patternfly-docs/content/extensions/chatbot/chatbot.md +57 -0
  89. package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +12 -12
  90. package/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md +1 -1
  91. package/patternfly-docs/content/extensions/chatbot/examples/Customizing Messages/Customizing Messages.md +1 -1
  92. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +1 -0
  93. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMultipleActionGroups.tsx +61 -0
  94. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithPersistedActions.tsx +22 -0
  95. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickResponses.tsx +11 -0
  96. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +36 -4
  97. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +1 -0
  98. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +3 -1
  99. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarIndicatorThinking.tsx +15 -0
  100. package/patternfly-docs/content/extensions/chatbot/examples/UI/CompactOnboarding.tsx +141 -0
  101. package/patternfly-docs/content/extensions/chatbot/examples/UI/Onboarding.tsx +151 -0
  102. package/patternfly-docs/content/extensions/chatbot/examples/UI/RH-Hat-Image.svg +9 -0
  103. package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +1 -1
  104. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +55 -27
  105. package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +18 -18
  106. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +29 -21
  107. package/patternfly-docs/content/extensions/chatbot/examples/demos/WhiteEmbeddedChatbot.tsx +451 -0
  108. package/patternfly-docs/patternfly-docs.config.js +2 -1
  109. package/patternfly-docs/patternfly-docs.source.js +1 -1
  110. package/src/AttachMenu/AttachMenu.tsx +26 -11
  111. package/src/Chatbot/Chatbot.scss +23 -1
  112. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +25 -0
  113. package/src/ChatbotFooter/ChatbotFooter.scss +21 -0
  114. package/src/ChatbotFooter/ChatbotFooter.test.tsx +10 -1
  115. package/src/ChatbotFooter/ChatbotFooter.tsx +10 -3
  116. package/src/ChatbotHeader/ChatbotHeader.scss +19 -0
  117. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +56 -14
  118. package/src/ChatbotModal/ChatbotModal.scss +3 -0
  119. package/src/CodeModal/CodeModal.tsx +72 -23
  120. package/src/DeepThinking/DeepThinking.scss +1 -1
  121. package/src/FileDetailsLabel/FileDetailsLabel.tsx +2 -2
  122. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +12 -0
  123. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +4 -1
  124. package/src/Message/Message.scss +11 -7
  125. package/src/Message/Message.test.tsx +239 -2
  126. package/src/Message/Message.tsx +61 -17
  127. package/src/Message/MessageLoading.scss +7 -0
  128. package/src/Message/MessageLoading.tsx +2 -2
  129. package/src/Message/TableMessage/TableMessage.scss +6 -1
  130. package/src/Message/TableMessage/TableMessage.tsx +6 -2
  131. package/src/Message/TextMessage/TextMessage.scss +10 -0
  132. package/src/Message/TextMessage/TextMessage.tsx +11 -2
  133. package/src/Message/UserFeedback/UserFeedback.scss +2 -1
  134. package/src/MessageBar/AttachButton.test.tsx +4 -0
  135. package/src/MessageBar/AttachButton.tsx +4 -1
  136. package/src/MessageBar/MessageBar.scss +40 -3
  137. package/src/MessageBar/MessageBar.test.tsx +102 -1
  138. package/src/MessageBar/MessageBar.tsx +44 -11
  139. package/src/Onboarding/Onboarding.scss +101 -0
  140. package/src/Onboarding/Onboarding.test.tsx +148 -0
  141. package/src/Onboarding/Onboarding.tsx +126 -0
  142. package/src/Onboarding/index.ts +3 -0
  143. package/src/ResponseActions/ResponseActions.scss +12 -1
  144. package/src/ResponseActions/ResponseActions.test.tsx +111 -12
  145. package/src/ResponseActions/ResponseActions.tsx +38 -10
  146. package/src/ToolCall/ToolCall.scss +1 -1
  147. package/src/ToolResponse/ToolResponse.scss +3 -3
  148. package/src/__mocks__/monaco-editor.ts +19 -0
  149. package/src/__mocks__/rehype-highlight.ts +3 -0
  150. package/src/index.ts +3 -0
  151. package/src/main.scss +1 -0
  152. package/tsconfig.json +1 -1
  153. package/patternfly-docs/content/extensions/chatbot/about-chatbot.md +0 -44
@@ -1,10 +1,10 @@
1
1
  import type { FunctionComponent } from 'react';
2
- import { DropdownProps, DropdownToggleProps, PopperOptions } from '@patternfly/react-core';
2
+ import { DropdownProps, DropdownToggleProps, PopperOptions, MenuSearchInputProps, SearchInputProps, MenuSearchProps } from '@patternfly/react-core';
3
3
  export interface AttachMenuProps extends DropdownProps {
4
4
  /** Items in menu */
5
5
  filteredItems: React.ReactNode;
6
6
  /** A callback for when the input value changes. */
7
- handleTextInputChange: (value: string) => void;
7
+ handleTextInputChange?: (value: string) => void;
8
8
  /** Flag to indicate if menu is opened. */
9
9
  isOpen: boolean;
10
10
  /** Additional properties to pass to the Popper */
@@ -21,6 +21,12 @@ export interface AttachMenuProps extends DropdownProps {
21
21
  searchInputAriaLabel?: string;
22
22
  /** Toggle to be rendered */
23
23
  toggle: DropdownToggleProps | ((toggleRef: React.RefObject<any>) => React.ReactNode);
24
+ /** Additional props passed to MenuSearch component */
25
+ menuSearchProps?: Omit<MenuSearchProps, 'ref'>;
26
+ /** Additional props passed to MenuSearchInput component */
27
+ menuSearchInputProps?: Omit<MenuSearchInputProps, 'ref'>;
28
+ /** Additional props passed to SearchInput component */
29
+ searchInputProps?: SearchInputProps;
24
30
  }
25
31
  export declare const AttachMenu: FunctionComponent<AttachMenuProps>;
26
32
  export default AttachMenu;
@@ -16,8 +16,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
16
16
  // Import PatternFly components
17
17
  const react_core_1 = require("@patternfly/react-core");
18
18
  const AttachMenu = (_a) => {
19
- var { className, filteredItems, handleTextInputChange, isOpen, popperProps = undefined, onOpenChange, onOpenChangeKeys, onSelect, searchInputPlaceholder, searchInputAriaLabel = 'Filter menu items', toggle } = _a, props = __rest(_a, ["className", "filteredItems", "handleTextInputChange", "isOpen", "popperProps", "onOpenChange", "onOpenChangeKeys", "onSelect", "searchInputPlaceholder", "searchInputAriaLabel", "toggle"]);
20
- return ((0, jsx_runtime_1.jsxs)(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__menu ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOpen, onOpenChange: (isOpen) => onOpenChange(isOpen), onOpenChangeKeys: onOpenChangeKeys !== null && onOpenChangeKeys !== void 0 ? onOpenChangeKeys : ['Esc'], toggle: toggle, popperProps: popperProps, onSelect: onSelect }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.MenuSearch, { children: (0, jsx_runtime_1.jsx)(react_core_1.MenuSearchInput, { children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, { "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }) }) }), filteredItems] })));
19
+ var { className, filteredItems, handleTextInputChange, isOpen, popperProps = undefined, onOpenChange, onOpenChangeKeys, onSelect, searchInputPlaceholder, searchInputAriaLabel = 'Filter menu items', toggle, menuSearchProps, menuSearchInputProps, searchInputProps } = _a, props = __rest(_a, ["className", "filteredItems", "handleTextInputChange", "isOpen", "popperProps", "onOpenChange", "onOpenChangeKeys", "onSelect", "searchInputPlaceholder", "searchInputAriaLabel", "toggle", "menuSearchProps", "menuSearchInputProps", "searchInputProps"]);
20
+ return ((0, jsx_runtime_1.jsxs)(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__menu ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOpen, onOpenChange: (isOpen) => onOpenChange(isOpen), onOpenChangeKeys: onOpenChangeKeys !== null && onOpenChangeKeys !== void 0 ? onOpenChangeKeys : ['Esc'], toggle: toggle, popperProps: popperProps, onSelect: onSelect }, props, { children: [handleTextInputChange && ((0, jsx_runtime_1.jsx)(react_core_1.MenuSearch, Object.assign({}, menuSearchProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.MenuSearchInput, Object.assign({}, menuSearchInputProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) })) }))), filteredItems] })));
21
21
  };
22
22
  exports.AttachMenu = AttachMenu;
23
23
  exports.default = exports.AttachMenu;
@@ -1,10 +1,13 @@
1
1
  import type { HTMLProps, FunctionComponent } from 'react';
2
2
  export interface ChatbotFooterProps extends HTMLProps<HTMLDivElement> {
3
- /** Children for the Footer that supports MessageBar and FootNote components*/
3
+ /** Children for the footer - supports MessageBar and FootNote components*/
4
4
  children?: React.ReactNode;
5
- /** Custom classname for the Footer component */
5
+ /** Custom classname for the footer component */
6
6
  className?: string;
7
+ /** Sets footer to compact styling. */
7
8
  isCompact?: boolean;
9
+ /** Sets background color to primary */
10
+ isPrimary?: boolean;
8
11
  }
9
12
  export declare const ChatbotFooter: FunctionComponent<ChatbotFooterProps>;
10
13
  export default ChatbotFooter;
@@ -15,8 +15,8 @@ exports.ChatbotFooter = void 0;
15
15
  const jsx_runtime_1 = require("react/jsx-runtime");
16
16
  const react_core_1 = require("@patternfly/react-core");
17
17
  const ChatbotFooter = (_a) => {
18
- var { children, className, isCompact } = _a, props = __rest(_a, ["children", "className", "isCompact"]);
19
- return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: `pf-chatbot__footer ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__footer-container", children: children })] })));
18
+ var { children, className, isCompact, isPrimary } = _a, props = __rest(_a, ["children", "className", "isCompact", "isPrimary"]);
19
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: `pf-chatbot__footer ${isCompact ? 'pf-m-compact' : ''} ${isPrimary ? 'pf-m-primary' : ''} ${className !== null && className !== void 0 ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__footer-container", children: children })] })));
20
20
  };
21
21
  exports.ChatbotFooter = ChatbotFooter;
22
22
  exports.default = exports.ChatbotFooter;
@@ -17,7 +17,11 @@ describe('ChatbotFooter', () => {
17
17
  expect(container.querySelector('.custom-class')).toBeTruthy();
18
18
  });
19
19
  it('should handle isCompact', () => {
20
- (0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, { className: "custom-class", isCompact: true, "data-testid": "footer", children: "Chatbot Content" }));
20
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, { isCompact: true, "data-testid": "footer", children: "Chatbot Content" }));
21
21
  expect(react_1.screen.getByTestId('footer')).toHaveClass('pf-m-compact');
22
22
  });
23
+ it('should handle isPrimary', () => {
24
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, { isPrimary: true, "data-testid": "footer", children: "Chatbot Content" }));
25
+ expect(react_1.screen.getByTestId('footer')).toHaveClass('pf-m-primary');
26
+ });
23
27
  });
@@ -21,8 +21,35 @@ const react_core_1 = require("@patternfly/react-core");
21
21
  const bars_icon_1 = __importDefault(require("@patternfly/react-icons/dist/esm/icons/bars-icon"));
22
22
  const ChatbotHeaderMenuBase = (_a) => {
23
23
  var { className, onMenuToggle, tooltipProps, menuAriaLabel = 'Chat history menu', innerRef, tooltipContent = 'Chat history menu', isCompact } = _a, props = __rest(_a, ["className", "onMenuToggle", "tooltipProps", "menuAriaLabel", "innerRef", "tooltipContent", "isCompact"]);
24
- return ((0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__menu ${className}`, children: (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
24
+ const [isDrawerAnimating, setIsDrawerAnimating] = (0, react_1.useState)(false);
25
+ // I'd like to use a prop here later if this works
26
+ const drawerState = props['aria-expanded'];
27
+ const isDrawerOpen = drawerState === true;
28
+ const prevDrawerStateRef = (0, react_1.useRef)(isDrawerOpen);
29
+ const buttonRef = (0, react_1.useRef)(null);
30
+ (0, react_1.useEffect)(() => {
31
+ if (drawerState !== undefined) {
32
+ const wasDrawerOpen = prevDrawerStateRef.current === true;
33
+ const isDrawerClosing = wasDrawerOpen && !isDrawerOpen;
34
+ setIsDrawerAnimating(true);
35
+ const timeout = setTimeout(() => {
36
+ setIsDrawerAnimating(false);
37
+ if (isDrawerClosing) {
38
+ requestAnimationFrame(() => {
39
+ var _a;
40
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
41
+ });
42
+ }
43
+ }, 350);
44
+ prevDrawerStateRef.current = isDrawerOpen;
45
+ return () => clearTimeout(timeout);
46
+ }
47
+ }, [drawerState, isDrawerOpen]);
48
+ const button = (0, react_1.useMemo)(() => ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onMenuToggle, "aria-label": menuAriaLabel, ref: innerRef !== null && innerRef !== void 0 ? innerRef : buttonRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(bars_icon_1.default, {}) }), size: isCompact ? 'sm' : undefined }, props))),
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ [isCompact, menuAriaLabel, onMenuToggle, innerRef, buttonRef]);
51
+ return ((0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__menu ${className}`, children: isDrawerAnimating ? (button) : ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
25
52
  // prevents VO announcements of both aria label and tooltip
26
- aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onMenuToggle, "aria-label": menuAriaLabel, ref: innerRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(bars_icon_1.default, {}) }), size: isCompact ? 'sm' : undefined }, props)) })) }));
53
+ aria: "none" }, tooltipProps, { children: button }))) }));
27
54
  };
28
55
  exports.ChatbotHeaderMenu = (0, react_1.forwardRef)((props, ref) => ((0, jsx_runtime_1.jsx)(ChatbotHeaderMenuBase, Object.assign({ innerRef: ref }, props))));
@@ -37,6 +37,8 @@ export interface CodeModalProps {
37
37
  modalBodyClassName?: string;
38
38
  /** Class applied to modal footer */
39
39
  modalFooterClassName?: string;
40
+ /** Aria label applied to spinner when loading Monaco */
41
+ spinnerAriaLabel?: string;
40
42
  }
41
43
  export declare const CodeModal: FunctionComponent<CodeModalProps>;
42
44
  export default CodeModal;
@@ -22,6 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
25
34
  var __rest = (this && this.__rest) || function (s, e) {
26
35
  var t = {};
27
36
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -47,12 +56,39 @@ const react_core_1 = require("@patternfly/react-core");
47
56
  const FileDetails_1 = __importStar(require("../FileDetails"));
48
57
  const Chatbot_1 = require("../Chatbot");
49
58
  const ChatbotModal_1 = __importDefault(require("../ChatbotModal/ChatbotModal"));
59
+ // Try to lazy load - some consumers need to be below a certain bundle size, but can't use the CDN and don't have webpack
60
+ let monacoInstance = null;
61
+ const loadMonaco = () => __awaiter(void 0, void 0, void 0, function* () {
62
+ if (!monacoInstance) {
63
+ const [monaco, { loader }] = yield Promise.all([Promise.resolve().then(() => __importStar(require('monaco-editor'))), Promise.resolve().then(() => __importStar(require('@monaco-editor/react')))]);
64
+ monacoInstance = monaco;
65
+ loader.config({ monaco });
66
+ }
67
+ return monacoInstance;
68
+ });
50
69
  const CodeModal = (_a) => {
51
- var { fileName, code, codeEditorControlClassName: codeEditorClassName, handleModalToggle, isCopyEnabled, isLineNumbersVisible, isModalOpen, isReadOnly, onPrimaryAction, onSecondaryAction, primaryActionBtn, secondaryActionBtn, title, displayMode = Chatbot_1.ChatbotDisplayMode.default, isCompact, modalHeaderClassName, modalBodyClassName, modalFooterClassName } = _a, props = __rest(_a, ["fileName", "code", "codeEditorControlClassName", "handleModalToggle", "isCopyEnabled", "isLineNumbersVisible", "isModalOpen", "isReadOnly", "onPrimaryAction", "onSecondaryAction", "primaryActionBtn", "secondaryActionBtn", "title", "displayMode", "isCompact", "modalHeaderClassName", "modalBodyClassName", "modalFooterClassName"]);
70
+ var { fileName, code, codeEditorControlClassName: codeEditorClassName, handleModalToggle, isCopyEnabled, isLineNumbersVisible, isModalOpen, isReadOnly, onPrimaryAction, onSecondaryAction, primaryActionBtn, secondaryActionBtn, title, displayMode = Chatbot_1.ChatbotDisplayMode.default, isCompact, modalHeaderClassName, modalBodyClassName, modalFooterClassName, spinnerAriaLabel = 'Loading' } = _a, props = __rest(_a, ["fileName", "code", "codeEditorControlClassName", "handleModalToggle", "isCopyEnabled", "isLineNumbersVisible", "isModalOpen", "isReadOnly", "onPrimaryAction", "onSecondaryAction", "primaryActionBtn", "secondaryActionBtn", "title", "displayMode", "isCompact", "modalHeaderClassName", "modalBodyClassName", "modalFooterClassName", "spinnerAriaLabel"]);
52
71
  const [newCode, setNewCode] = (0, react_1.useState)(code);
53
72
  const [editorInstance, setEditorInstance] = (0, react_1.useState)(null);
54
73
  const [isEditorReady, setIsEditorReady] = (0, react_1.useState)(false);
74
+ const [isMonacoLoading, setIsMonacoLoading] = (0, react_1.useState)(false);
75
+ const [isMonacoLoaded, setIsMonacoLoaded] = (0, react_1.useState)(false);
55
76
  const containerRef = (0, react_1.useRef)(null);
77
+ (0, react_1.useEffect)(() => {
78
+ if (isModalOpen && !isMonacoLoaded && !isMonacoLoading) {
79
+ setIsMonacoLoading(true);
80
+ loadMonaco()
81
+ .then(() => {
82
+ setIsMonacoLoaded(true);
83
+ setIsMonacoLoading(false);
84
+ })
85
+ .catch((error) => {
86
+ // eslint-disable-next-line no-console
87
+ console.error('Failed to load Monaco editor:', error);
88
+ setIsMonacoLoading(false);
89
+ });
90
+ }
91
+ }, [isModalOpen, isMonacoLoaded, isMonacoLoading]);
56
92
  (0, react_1.useEffect)(() => {
57
93
  if (!isModalOpen || !isEditorReady || !editorInstance || !containerRef.current) {
58
94
  return;
@@ -102,13 +138,22 @@ const CodeModal = (_a) => {
102
138
  setNewCode(value);
103
139
  }
104
140
  };
105
- const modal = ((0, jsx_runtime_1.jsxs)(ChatbotModal_1.default, { isOpen: isModalOpen, onClose: handleModalToggle, ouiaId: "CodeModal", "aria-labelledby": "code-modal-title", "aria-describedby": "code-modal", className: `pf-chatbot__code-modal ${isCompact ? 'pf-m-compact' : ''} pf-chatbot__code-modal--${displayMode}`, displayMode: displayMode, isCompact: isCompact, children: [(0, jsx_runtime_1.jsx)(react_core_1.ModalHeader, { className: modalHeaderClassName, title: title, labelId: "code-modal-title" }), (0, jsx_runtime_1.jsx)(react_core_1.ModalBody, { className: modalBodyClassName, id: "code-modal-body", children: (0, jsx_runtime_1.jsxs)(react_core_1.Stack, { className: "pf-chatbot__code-modal-body", children: [(0, jsx_runtime_1.jsx)(react_core_1.StackItem, { className: "pf-chatbot__code-modal-file-details", children: (0, jsx_runtime_1.jsx)(FileDetails_1.default, { fileName: fileName }) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-v6-l-stack__item pf-chatbot__code-modal-editor", ref: containerRef, children: (0, jsx_runtime_1.jsx)(react_code_editor_1.CodeEditor, Object.assign({ isDarkTheme: true, isLineNumbersVisible: isLineNumbersVisible, isLanguageLabelVisible: true, isCopyEnabled: isCopyEnabled, isReadOnly: isReadOnly, code: newCode, language: FileDetails_1.extensionToLanguage[path_browserify_1.default.extname(fileName).slice(1)], onEditorDidMount: onEditorDidMount, onCodeChange: onCodeChange, className: codeEditorClassName, isFullHeight: true, options: {
106
- glyphMargin: false,
107
- folding: false,
108
- // prevents Monaco from handling resizing itself
109
- // was causing ResizeObserver issues
110
- automaticLayout: false
111
- } }, props)) })] }) }), (0, jsx_runtime_1.jsxs)(react_core_1.ModalFooter, { className: modalFooterClassName, children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "primary", onClick: handlePrimaryAction, form: "code-modal-form", children: primaryActionBtn }, "code-modal-primary"), (0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "link", onClick: handleSecondaryAction, children: secondaryActionBtn }, "code-modal-secondary")] })] }));
141
+ const renderMonacoEditor = () => {
142
+ if (isMonacoLoading) {
143
+ return ((0, jsx_runtime_1.jsx)(react_core_1.Bullseye, { children: (0, jsx_runtime_1.jsx)(react_core_1.Spinner, { "aria-label": spinnerAriaLabel }) }));
144
+ }
145
+ if (isMonacoLoaded) {
146
+ return ((0, jsx_runtime_1.jsx)(react_code_editor_1.CodeEditor, Object.assign({ isDarkTheme: true, isLineNumbersVisible: isLineNumbersVisible, isLanguageLabelVisible: true, isCopyEnabled: isCopyEnabled, isReadOnly: isReadOnly, code: newCode, language: FileDetails_1.extensionToLanguage[path_browserify_1.default.extname(fileName).slice(1)], onEditorDidMount: onEditorDidMount, onCodeChange: onCodeChange, className: codeEditorClassName, isFullHeight: true, options: {
147
+ glyphMargin: false,
148
+ folding: false,
149
+ // prevents Monaco from handling resizing itself
150
+ // was causing ResizeObserver issues
151
+ automaticLayout: false
152
+ } }, props)));
153
+ }
154
+ return null;
155
+ };
156
+ const modal = ((0, jsx_runtime_1.jsxs)(ChatbotModal_1.default, { isOpen: isModalOpen, onClose: handleModalToggle, ouiaId: "CodeModal", "aria-labelledby": "code-modal-title", "aria-describedby": "code-modal", className: `pf-chatbot__code-modal ${isCompact ? 'pf-m-compact' : ''} pf-chatbot__code-modal--${displayMode}`, displayMode: displayMode, isCompact: isCompact, children: [(0, jsx_runtime_1.jsx)(react_core_1.ModalHeader, { className: modalHeaderClassName, title: title, labelId: "code-modal-title" }), (0, jsx_runtime_1.jsx)(react_core_1.ModalBody, { className: modalBodyClassName, id: "code-modal-body", children: (0, jsx_runtime_1.jsxs)(react_core_1.Stack, { className: "pf-chatbot__code-modal-body", children: [(0, jsx_runtime_1.jsx)(react_core_1.StackItem, { className: "pf-chatbot__code-modal-file-details", children: (0, jsx_runtime_1.jsx)(FileDetails_1.default, { fileName: fileName }) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-v6-l-stack__item pf-chatbot__code-modal-editor", ref: containerRef, children: renderMonacoEditor() })] }) }), (0, jsx_runtime_1.jsxs)(react_core_1.ModalFooter, { className: modalFooterClassName, children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "primary", onClick: handlePrimaryAction, form: "code-modal-form", children: primaryActionBtn }, "code-modal-primary"), (0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "link", onClick: handleSecondaryAction, children: secondaryActionBtn }, "code-modal-secondary")] })] }));
112
157
  return modal;
113
158
  };
114
159
  exports.CodeModal = CodeModal;
@@ -1,5 +1,6 @@
1
1
  import { PropsWithChildren } from 'react';
2
- export interface FileDetailsLabelProps {
2
+ import { LabelProps } from '@patternfly/react-core';
3
+ export interface FileDetailsLabelProps extends Omit<LabelProps, 'onClose' | 'onClick'> {
3
4
  /** Name of file, including extension */
4
5
  fileName: string;
5
6
  /** Unique id of file */
@@ -18,6 +18,8 @@ export interface CodeBlockMessageProps {
18
18
  collapsedText?: string;
19
19
  /** Custom actions added to header of code block, after any default actions such as the "copy" action. */
20
20
  customActions?: React.ReactNode;
21
+ /** Sets background colors to be appropriate on primary chatbot background */
22
+ isPrimary?: boolean;
21
23
  }
22
- declare const CodeBlockMessage: ({ children, className, "aria-label": ariaLabel, isExpandable, expandableSectionProps, expandableSectionToggleProps, expandedText, collapsedText, customActions, ...props }: CodeBlockMessageProps) => import("react/jsx-runtime").JSX.Element;
24
+ declare const CodeBlockMessage: ({ children, className, "aria-label": ariaLabel, isExpandable, expandableSectionProps, expandableSectionToggleProps, expandedText, collapsedText, customActions, isPrimary, ...props }: CodeBlockMessageProps) => import("react/jsx-runtime").JSX.Element;
23
25
  export default CodeBlockMessage;
@@ -24,7 +24,7 @@ const DEFAULT_EXPANDED_TEXT = 'Show less';
24
24
  const DEFAULT_COLLAPSED_TEXT = 'Show more';
25
25
  const CodeBlockMessage = (_a) => {
26
26
  var _b;
27
- var { children, className, 'aria-label': ariaLabel, isExpandable = false, expandableSectionProps, expandableSectionToggleProps, expandedText = DEFAULT_EXPANDED_TEXT, collapsedText = DEFAULT_COLLAPSED_TEXT, customActions } = _a, props = __rest(_a, ["children", "className", 'aria-label', "isExpandable", "expandableSectionProps", "expandableSectionToggleProps", "expandedText", "collapsedText", "customActions"]);
27
+ var { children, className, 'aria-label': ariaLabel, isExpandable = false, expandableSectionProps, expandableSectionToggleProps, expandedText = DEFAULT_EXPANDED_TEXT, collapsedText = DEFAULT_COLLAPSED_TEXT, customActions, isPrimary } = _a, props = __rest(_a, ["children", "className", 'aria-label', "isExpandable", "expandableSectionProps", "expandableSectionToggleProps", "expandedText", "collapsedText", "customActions", "isPrimary"]);
28
28
  const [copied, setCopied] = (0, react_1.useState)(false);
29
29
  const [isExpanded, setIsExpanded] = (0, react_1.useState)(false);
30
30
  const buttonRef = (0, react_1.useRef)();
@@ -61,7 +61,7 @@ const CodeBlockMessage = (_a) => {
61
61
  }
62
62
  });
63
63
  if (!String(children).includes('\n')) {
64
- return ((0, jsx_runtime_1.jsx)("code", Object.assign({}, props, { className: "pf-chatbot__message-inline-code", children: children })));
64
+ return ((0, jsx_runtime_1.jsx)("code", Object.assign({}, props, { className: `pf-chatbot__message-inline-code ${isPrimary ? 'pf-m-primary' : ''}`, children: children })));
65
65
  }
66
66
  // Setup code block header
67
67
  const actions = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_core_1.CodeBlockAction, { className: "pf-chatbot__message-code-block-default-action", children: [language && (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-code-block-language", children: language }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { ref: buttonRef, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : 'Copy code', variant: "plain", className: "pf-chatbot__button--copy", onClick: (event) => handleCopy(event, children), children: copied ? (0, jsx_runtime_1.jsx)(check_icon_1.CheckIcon, {}) : (0, jsx_runtime_1.jsx)(copy_icon_1.CopyIcon, {}) }), (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { id: tooltipID, content: "Copy", position: "top", triggerRef: buttonRef })] }), customActions] }));
@@ -10,6 +10,7 @@ import QuickResponse from './QuickResponse/QuickResponse';
10
10
  import { UserFeedbackProps } from './UserFeedback/UserFeedback';
11
11
  import { UserFeedbackCompleteProps } from './UserFeedback/UserFeedbackComplete';
12
12
  import { TableProps } from '@patternfly/react-table';
13
+ import 'highlight.js/styles/vs2015.css';
13
14
  import { PluggableList } from 'unified';
14
15
  import { ToolResponseProps } from '../ToolResponse';
15
16
  import { DeepThinkingProps } from '../DeepThinking';
@@ -52,17 +53,32 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
52
53
  /** Name of the user */
53
54
  name?: string;
54
55
  /** Avatar src for the user */
55
- avatar: string;
56
+ avatar?: string;
56
57
  /** Timestamp for the message */
57
58
  timestamp?: string;
58
59
  /** Set this to true if message is being loaded */
59
60
  isLoading?: boolean;
60
61
  /** Array of attachments attached to a message */
61
62
  attachments?: MessageAttachment[];
62
- /** Props for message actions, such as feedback (positive or negative), copy button, edit message, share, and listen */
63
+ /** Props for message actions, such as feedback (positive or negative), copy button, edit message, share, and listen.
64
+ * Can be a single actions object or an array of action group objects. When passing an array, you can pass an object of actions or
65
+ * an object that contains an actions property for finer control of selection persistence.
66
+ */
63
67
  actions?: {
64
68
  [key: string]: ActionProps;
65
- };
69
+ } | {
70
+ [key: string]: ActionProps;
71
+ }[] | {
72
+ actions: {
73
+ [key: string]: ActionProps;
74
+ };
75
+ persistActionSelection?: boolean;
76
+ }[];
77
+ /** When true, the selected action will persist even when clicking outside the component.
78
+ * When false (default), clicking outside or clicking another action will deselect the current selection.
79
+ * For finer control of multiple action groups, use persistActionSelection on each group.
80
+ */
81
+ persistActionSelection?: boolean;
66
82
  /** Sources for message */
67
83
  sources?: SourcesCardProps;
68
84
  /** Label for the English word "AI," used to tag messages with role "bot" */
@@ -144,6 +160,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
144
160
  toolCall?: ToolCallProps;
145
161
  /** Whether user messages default to stripping out images in markdown */
146
162
  hasNoImagesInUserMessages?: boolean;
163
+ /** Sets background colors to be appropriate on primary chatbot background */
164
+ isPrimary?: boolean;
147
165
  }
148
166
  export declare const MessageBase: FunctionComponent<MessageProps>;
149
167
  declare const Message: import("react").ForwardRefExoticComponent<Omit<MessageProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -46,6 +46,9 @@ const ImageMessage_1 = __importDefault(require("./ImageMessage/ImageMessage"));
46
46
  const rehype_unwrap_images_1 = __importDefault(require("rehype-unwrap-images"));
47
47
  const rehype_external_links_1 = __importDefault(require("rehype-external-links"));
48
48
  const rehype_sanitize_1 = __importDefault(require("rehype-sanitize"));
49
+ const rehype_highlight_1 = __importDefault(require("rehype-highlight"));
50
+ // see the full list of styles here: https://highlightjs.org/examples
51
+ require("highlight.js/styles/vs2015.css");
49
52
  const LinkMessage_1 = __importDefault(require("./LinkMessage/LinkMessage"));
50
53
  const ErrorMessage_1 = __importDefault(require("./ErrorMessage/ErrorMessage"));
51
54
  const MessageInput_1 = __importDefault(require("./MessageInput"));
@@ -55,13 +58,13 @@ const DeepThinking_1 = __importDefault(require("../DeepThinking"));
55
58
  const SuperscriptMessage_1 = __importDefault(require("./SuperscriptMessage/SuperscriptMessage"));
56
59
  const ToolCall_1 = __importDefault(require("../ToolCall"));
57
60
  const MessageBase = (_a) => {
58
- var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps, toolCall, hasNoImagesInUserMessages = true } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps", "toolCall", "hasNoImagesInUserMessages"]);
61
+ var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, persistActionSelection, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps, toolCall, hasNoImagesInUserMessages = true, isPrimary } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "persistActionSelection", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps", "toolCall", "hasNoImagesInUserMessages", "isPrimary"]);
59
62
  const [messageText, setMessageText] = (0, react_1.useState)(content);
60
63
  (0, react_1.useEffect)(() => {
61
64
  setMessageText(content);
62
65
  }, [content]);
63
66
  const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
64
- let rehypePlugins = [rehype_unwrap_images_1.default, rehypeMoveImagesOutOfParagraphs_1.rehypeMoveImagesOutOfParagraphs];
67
+ let rehypePlugins = [rehype_unwrap_images_1.default, rehypeMoveImagesOutOfParagraphs_1.rehypeMoveImagesOutOfParagraphs, rehype_highlight_1.default];
65
68
  if (openLinkInNewTab) {
66
69
  rehypePlugins = rehypePlugins.concat([[rehype_external_links_1.default, { target: '_blank' }, rehype_sanitize_1.default]]);
67
70
  }
@@ -94,13 +97,13 @@ const MessageBase = (_a) => {
94
97
  p: (props) => {
95
98
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
96
99
  const { node } = props, rest = __rest(props, ["node"]);
97
- return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, rest));
100
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, rest, { isPrimary: isPrimary }));
98
101
  },
99
102
  code: (_a) => {
100
103
  var { children } = _a, props = __rest(_a, ["children"]);
101
104
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
102
105
  const { node } = props, codeProps = __rest(props, ["node"]);
103
- return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, codeProps, codeBlockProps, { children: children })));
106
+ return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, codeProps, codeBlockProps, { isPrimary: isPrimary, children: children })));
104
107
  },
105
108
  h1: (props) => {
106
109
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -153,7 +156,7 @@ const MessageBase = (_a) => {
153
156
  return (0, jsx_runtime_1.jsx)(ListItemMessage_1.default, Object.assign({}, rest));
154
157
  },
155
158
  // table requires node attribute for calculating headers for mobile breakpoint
156
- table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps)),
159
+ table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps, { isPrimary: isPrimary })),
157
160
  tbody: (props) => {
158
161
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
162
  const { node } = props, rest = __rest(props, ["node"]);
@@ -206,7 +209,7 @@ const MessageBase = (_a) => {
206
209
  };
207
210
  const renderMessage = () => {
208
211
  if (isLoading) {
209
- return (0, jsx_runtime_1.jsx)(MessageLoading_1.default, { loadingWord: loadingWord });
212
+ return (0, jsx_runtime_1.jsx)(MessageLoading_1.default, { loadingWord: loadingWord, isPrimary: isPrimary });
210
213
  }
211
214
  if (isEditable) {
212
215
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [beforeMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: beforeMainContent }), (0, jsx_runtime_1.jsx)(MessageInput_1.default, Object.assign({ content: messageText, editPlaceholder: editPlaceholder, updateWord: updateWord, cancelWord: cancelWord, onEditUpdate: (event, value) => {
@@ -216,9 +219,9 @@ const MessageBase = (_a) => {
216
219
  }
217
220
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [beforeMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: beforeMainContent }), error ? (0, jsx_runtime_1.jsx)(ErrorMessage_1.default, Object.assign({}, error)) : handleMarkdown()] }));
218
221
  };
219
- return ((0, jsx_runtime_1.jsxs)("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}`, "aria-live": isLiveRegion ? 'polite' : undefined, "aria-atomic": isLiveRegion ? false : undefined, ref: innerRef }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps)), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-contents", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-meta", children: [name && ((0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__message-name", children: (0, jsx_runtime_1.jsx)(react_core_1.Truncate, { content: name }) })), role === 'bot' && ((0, jsx_runtime_1.jsx)(react_core_1.Label, { variant: "outline", isCompact: true, children: botWord })), (0, jsx_runtime_1.jsx)(react_core_1.Timestamp, { date: date, children: timestamp })] }), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-response", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-and-actions", children: [renderMessage(), afterMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: afterMainContent }), toolResponse && (0, jsx_runtime_1.jsx)(ToolResponse_1.default, Object.assign({}, toolResponse)), deepThinking && (0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, deepThinking)), toolCall && (0, jsx_runtime_1.jsx)(ToolCall_1.default, Object.assign({}, toolCall)), !isLoading && sources && (0, jsx_runtime_1.jsx)(SourcesCard_1.default, Object.assign({}, sources, { isCompact: isCompact })), quickStarts && quickStarts.quickStart && ((0, jsx_runtime_1.jsx)(QuickStartTile_1.default, { quickStart: quickStarts.quickStart, onSelectQuickStart: quickStarts.onSelectQuickStart, minuteWord: quickStarts.minuteWord, minuteWordPlural: quickStarts.minuteWordPlural, prerequisiteWord: quickStarts.prerequisiteWord, prerequisiteWordPlural: quickStarts.prerequisiteWordPlural, quickStartButtonAriaLabel: quickStarts.quickStartButtonAriaLabel, isCompact: isCompact })), !isLoading && !isEditable && actions && (0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actions }), userFeedbackForm && (0, jsx_runtime_1.jsx)(UserFeedback_1.default, Object.assign({}, userFeedbackForm, { timestamp: dateString, isCompact: isCompact })), userFeedbackComplete && ((0, jsx_runtime_1.jsx)(UserFeedbackComplete_1.default, Object.assign({}, userFeedbackComplete, { timestamp: dateString, isCompact: isCompact }))), !isLoading && quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, isCompact: isCompact }))] }), attachments && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachments-container", children: attachments.map((attachment) => {
222
+ return ((0, jsx_runtime_1.jsxs)("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}`, "aria-live": isLiveRegion ? 'polite' : undefined, "aria-atomic": isLiveRegion ? false : undefined, ref: innerRef }, props, { children: [avatar && ((0, jsx_runtime_1.jsx)(react_core_1.Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps))), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-contents", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-meta", children: [name && ((0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__message-name", children: (0, jsx_runtime_1.jsx)(react_core_1.Truncate, { content: name }) })), role === 'bot' && ((0, jsx_runtime_1.jsx)(react_core_1.Label, { variant: "outline", isCompact: true, children: botWord })), (0, jsx_runtime_1.jsx)(react_core_1.Timestamp, { date: date, children: timestamp })] }), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-response", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-and-actions", children: [renderMessage(), afterMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: afterMainContent }), toolResponse && (0, jsx_runtime_1.jsx)(ToolResponse_1.default, Object.assign({}, toolResponse)), deepThinking && (0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, deepThinking)), toolCall && (0, jsx_runtime_1.jsx)(ToolCall_1.default, Object.assign({}, toolCall)), !isLoading && sources && (0, jsx_runtime_1.jsx)(SourcesCard_1.default, Object.assign({}, sources, { isCompact: isCompact })), quickStarts && quickStarts.quickStart && ((0, jsx_runtime_1.jsx)(QuickStartTile_1.default, { quickStart: quickStarts.quickStart, onSelectQuickStart: quickStarts.onSelectQuickStart, minuteWord: quickStarts.minuteWord, minuteWordPlural: quickStarts.minuteWordPlural, prerequisiteWord: quickStarts.prerequisiteWord, prerequisiteWordPlural: quickStarts.prerequisiteWordPlural, quickStartButtonAriaLabel: quickStarts.quickStartButtonAriaLabel, isCompact: isCompact })), !isLoading && !isEditable && actions && ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: Array.isArray(actions) ? ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__response-actions-groups", children: actions.map((actionGroup, index) => ((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actionGroup.actions || actionGroup, persistActionSelection: persistActionSelection || actionGroup.persistActionSelection }, index))) })) : ((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actions, persistActionSelection: persistActionSelection })) })), userFeedbackForm && (0, jsx_runtime_1.jsx)(UserFeedback_1.default, Object.assign({}, userFeedbackForm, { timestamp: dateString, isCompact: isCompact })), userFeedbackComplete && ((0, jsx_runtime_1.jsx)(UserFeedbackComplete_1.default, Object.assign({}, userFeedbackComplete, { timestamp: dateString, isCompact: isCompact }))), !isLoading && quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, isCompact: isCompact }))] }), attachments && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachments-container", children: attachments.map((attachment) => {
220
223
  var _a;
221
- return ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachment", children: (0, jsx_runtime_1.jsx)(FileDetailsLabel_1.default, { fileName: attachment.name, fileId: attachment.id, onClose: attachment.onClose, onClick: attachment.onClick, isLoading: attachment.isLoading, closeButtonAriaLabel: attachment.closeButtonAriaLabel, languageTestId: attachment.languageTestId, spinnerTestId: attachment.spinnerTestId }) }, (_a = attachment.id) !== null && _a !== void 0 ? _a : attachment.name));
224
+ return ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachment", children: (0, jsx_runtime_1.jsx)(FileDetailsLabel_1.default, { fileName: attachment.name, fileId: attachment.id, onClose: attachment.onClose, onClick: attachment.onClick, isLoading: attachment.isLoading, closeButtonAriaLabel: attachment.closeButtonAriaLabel, languageTestId: attachment.languageTestId, spinnerTestId: attachment.spinnerTestId, variant: isPrimary ? 'outline' : undefined }) }, (_a = attachment.id) !== null && _a !== void 0 ? _a : attachment.name));
222
225
  }) })), !isLoading && endContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: endContent })] })] })] })));
223
226
  };
224
227
  exports.MessageBase = MessageBase;
@@ -209,6 +209,10 @@ describe('Message', () => {
209
209
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./testImg", role: "bot", name: "Bot", content: "Hi" }));
210
210
  expect(react_2.screen.getByRole('img')).toHaveAttribute('src', './testImg');
211
211
  });
212
+ it('should not render avatar if no avatar prop is passed', () => {
213
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { role: "bot", name: "Bot", content: "Hi" }));
214
+ expect(react_2.screen.queryByRole('img')).not.toBeInTheDocument();
215
+ });
212
216
  it('should render botWord correctly', () => {
213
217
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", botWord: "\u4EBA\u5DE5\u77E5\u80FD" }));
214
218
  expect(react_2.screen.getByText('Bot')).toBeTruthy();
@@ -356,7 +360,7 @@ describe('Message', () => {
356
360
  expect(react_2.screen.queryByRole('button', { name: /No/i })).toBeFalsy();
357
361
  expect(react_2.screen.getByRole('button', { name: /1 more/i }));
358
362
  }));
359
- it('should be able to show actions', () => __awaiter(void 0, void 0, void 0, function* () {
363
+ it('Renders response actions when a single actions object is passed', () => __awaiter(void 0, void 0, void 0, function* () {
360
364
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", actions: {
361
365
  // eslint-disable-next-line no-console
362
366
  positive: { onClick: () => console.log('Good response') },
@@ -374,9 +378,132 @@ describe('Message', () => {
374
378
  listen: { onClick: () => console.log('Listen') }
375
379
  } }));
376
380
  ALL_ACTIONS.forEach(({ label }) => {
377
- expect(react_2.screen.getByRole('button', { name: label })).toBeTruthy();
381
+ expect(react_2.screen.getByRole('button', { name: label })).toBeVisible();
382
+ });
383
+ }));
384
+ it('Renders response actions when an array of actions objects is passed', () => __awaiter(void 0, void 0, void 0, function* () {
385
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", actions: [
386
+ {
387
+ // eslint-disable-next-line no-console
388
+ positive: { onClick: () => console.log('Good response') },
389
+ // eslint-disable-next-line no-console
390
+ negative: { onClick: () => console.log('Bad response') }
391
+ },
392
+ {
393
+ // eslint-disable-next-line no-console
394
+ copy: { onClick: () => console.log('Copy') },
395
+ // eslint-disable-next-line no-console
396
+ edit: { onClick: () => console.log('Edit') },
397
+ // eslint-disable-next-line no-console
398
+ share: { onClick: () => console.log('Share') },
399
+ // eslint-disable-next-line no-console
400
+ download: { onClick: () => console.log('Download') }
401
+ },
402
+ {
403
+ // eslint-disable-next-line no-console
404
+ listen: { onClick: () => console.log('Listen') }
405
+ }
406
+ ] }));
407
+ ALL_ACTIONS.forEach(({ label }) => {
408
+ expect(react_2.screen.getByRole('button', { name: label })).toBeVisible();
409
+ });
410
+ }));
411
+ it('Renders response actions when an array of objects containing actions objects is passed', () => __awaiter(void 0, void 0, void 0, function* () {
412
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", actions: [
413
+ {
414
+ actions: {
415
+ // eslint-disable-next-line no-console
416
+ positive: { onClick: () => console.log('Good response') },
417
+ // eslint-disable-next-line no-console
418
+ negative: { onClick: () => console.log('Bad response') }
419
+ }
420
+ },
421
+ {
422
+ actions: {
423
+ // eslint-disable-next-line no-console
424
+ copy: { onClick: () => console.log('Copy') },
425
+ // eslint-disable-next-line no-console
426
+ edit: { onClick: () => console.log('Edit') },
427
+ // eslint-disable-next-line no-console
428
+ share: { onClick: () => console.log('Share') },
429
+ // eslint-disable-next-line no-console
430
+ download: { onClick: () => console.log('Download') }
431
+ }
432
+ },
433
+ {
434
+ actions: {
435
+ // eslint-disable-next-line no-console
436
+ listen: { onClick: () => console.log('Listen') }
437
+ }
438
+ }
439
+ ] }));
440
+ ALL_ACTIONS.forEach(({ label }) => {
441
+ expect(react_2.screen.getByRole('button', { name: label })).toBeVisible();
378
442
  });
379
443
  }));
444
+ it('should handle persistActionSelection correctly when a single actions object is passed', () => __awaiter(void 0, void 0, void 0, function* () {
445
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Test message", persistActionSelection: true, actions: {
446
+ positive: { onClick: jest.fn() },
447
+ negative: { onClick: jest.fn() }
448
+ } }));
449
+ const goodBtn = react_2.screen.getByRole('button', { name: /Good response/i });
450
+ const badBtn = react_2.screen.getByRole('button', { name: /Bad response/i });
451
+ yield user_event_1.default.click(goodBtn);
452
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
453
+ yield user_event_1.default.click(react_2.screen.getByText('Test message'));
454
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
455
+ yield user_event_1.default.click(badBtn);
456
+ expect(react_2.screen.getByRole('button', { name: /Bad response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
457
+ expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
458
+ }));
459
+ it('should handle persistActionSelection correctly when an array of actions objects is passed', () => __awaiter(void 0, void 0, void 0, function* () {
460
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Test message", persistActionSelection: true, actions: [
461
+ {
462
+ positive: { onClick: jest.fn() },
463
+ negative: { onClick: jest.fn() }
464
+ },
465
+ {
466
+ copy: { onClick: jest.fn() }
467
+ }
468
+ ] }));
469
+ const goodBtn = react_2.screen.getByRole('button', { name: /Good response/i });
470
+ const copyBtn = react_2.screen.getByRole('button', { name: /Copy/i });
471
+ yield user_event_1.default.click(goodBtn);
472
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
473
+ yield user_event_1.default.click(react_2.screen.getByText('Test message'));
474
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
475
+ yield user_event_1.default.click(copyBtn);
476
+ expect(react_2.screen.getByRole('button', { name: /Copied/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
477
+ yield user_event_1.default.click(react_2.screen.getByText('Test message'));
478
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
479
+ expect(react_2.screen.getByRole('button', { name: /Copied/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
480
+ }));
481
+ it('should handle persistActionSelection correctly when an array of objects containing actions objects is passed', () => __awaiter(void 0, void 0, void 0, function* () {
482
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Test message", actions: [
483
+ {
484
+ actions: {
485
+ positive: { onClick: jest.fn() },
486
+ negative: { onClick: jest.fn() }
487
+ },
488
+ persistActionSelection: true
489
+ },
490
+ {
491
+ actions: {
492
+ copy: { onClick: jest.fn() }
493
+ },
494
+ persistActionSelection: false
495
+ }
496
+ ] }));
497
+ const goodBtn = react_2.screen.getByRole('button', { name: /Good response/i });
498
+ const copyBtn = react_2.screen.getByRole('button', { name: /Copy/i });
499
+ yield user_event_1.default.click(goodBtn);
500
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
501
+ yield user_event_1.default.click(copyBtn);
502
+ expect(react_2.screen.getByRole('button', { name: /Copied/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
503
+ yield user_event_1.default.click(react_2.screen.getByText('Test message'));
504
+ expect(react_2.screen.getByRole('button', { name: /Good response recorded/i })).toHaveClass('pf-chatbot__button--response-action-clicked');
505
+ expect(copyBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
506
+ }));
380
507
  it('should not show actions if loading', () => __awaiter(void 0, void 0, void 0, function* () {
381
508
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", isLoading: true, actions: {
382
509
  // eslint-disable-next-line no-console
@@ -831,4 +958,36 @@ describe('Message', () => {
831
958
  expect(react_2.screen.getByText('Thought for 3 seconds')).toBeTruthy();
832
959
  expect(react_2.screen.getByText("Here's why I said this.")).toBeTruthy();
833
960
  });
961
+ it('should handle isPrimary correctly for inline code when it is true', () => {
962
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: INLINE_CODE, isPrimary: true }));
963
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
964
+ });
965
+ it('should handle isPrimary correctly for inline code when it is false', () => {
966
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: INLINE_CODE }));
967
+ expect(container.querySelector('.pf-m-primary')).toBeFalsy();
968
+ });
969
+ it('should handle isPrimary correctly for table when it is true', () => {
970
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: TABLE, isPrimary: true }));
971
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
972
+ });
973
+ it('should handle isPrimary correctly for table when it is false', () => {
974
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: TABLE }));
975
+ expect(container.querySelector('.pf-m-primary')).toBeFalsy();
976
+ });
977
+ it('should handle isPrimary correctly for loading when it is true', () => {
978
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isPrimary: true, isLoading: true }));
979
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
980
+ });
981
+ it('should handle isPrimary correctly for loading when it is false', () => {
982
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isLoading: true }));
983
+ expect(container.querySelector('.pf-m-primary')).toBeFalsy();
984
+ });
985
+ it('should handle isPrimary correctly for attachments when it is true', () => {
986
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isPrimary: true, attachments: [{ name: 'testAttachment' }] }));
987
+ expect(container.querySelector('.pf-m-outline')).toBeTruthy();
988
+ });
989
+ it('should handle isPrimary correctly for attachments when it is false', () => {
990
+ const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", attachments: [{ name: 'testAttachment' }] }));
991
+ expect(container.querySelector('.pf-m-outline')).toBeFalsy();
992
+ });
834
993
  });