@patternfly/chatbot 6.4.0-prerelease.2 → 6.4.0-prerelease.20

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 (186) hide show
  1. package/dist/cjs/Chatbot/Chatbot.js +1 -7
  2. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
  4. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +22 -2
  5. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +15 -9
  6. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +40 -2
  7. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
  8. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
  9. package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
  10. package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.js +25 -0
  11. package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
  12. package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +22 -0
  13. package/dist/cjs/ChatbotHeader/index.d.ts +1 -0
  14. package/dist/cjs/ChatbotHeader/index.js +1 -0
  15. package/dist/cjs/DeepThinking/DeepThinking.d.ts +18 -0
  16. package/dist/cjs/DeepThinking/DeepThinking.js +18 -0
  17. package/dist/cjs/DeepThinking/DeepThinking.test.d.ts +1 -0
  18. package/dist/cjs/DeepThinking/DeepThinking.test.js +48 -0
  19. package/dist/cjs/DeepThinking/index.d.ts +2 -0
  20. package/dist/cjs/DeepThinking/index.js +23 -0
  21. package/dist/cjs/FilePreview/FilePreview.d.ts +26 -0
  22. package/dist/cjs/FilePreview/FilePreview.js +26 -0
  23. package/dist/cjs/FilePreview/FilePreview.test.d.ts +1 -0
  24. package/dist/cjs/FilePreview/FilePreview.test.js +97 -0
  25. package/dist/cjs/FilePreview/index.d.ts +2 -0
  26. package/dist/cjs/FilePreview/index.js +23 -0
  27. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
  28. package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +2 -1
  29. package/dist/cjs/Message/LinkMessage/LinkMessage.js +7 -3
  30. package/dist/cjs/Message/ListMessage/ListItemMessage.d.ts +1 -1
  31. package/dist/cjs/Message/ListMessage/ListItemMessage.js +16 -1
  32. package/dist/cjs/Message/Message.d.ts +15 -0
  33. package/dist/cjs/Message/Message.js +129 -32
  34. package/dist/cjs/Message/Message.test.js +71 -0
  35. package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
  36. package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.js +5 -0
  37. package/dist/cjs/Message/UserFeedback/UserFeedback.d.ts +15 -1
  38. package/dist/cjs/Message/UserFeedback/UserFeedback.js +4 -4
  39. package/dist/cjs/Message/UserFeedback/UserFeedback.test.js +44 -0
  40. package/dist/cjs/MessageBar/MessageBar.js +19 -4
  41. package/dist/cjs/MessageBox/JumpButton.d.ts +5 -0
  42. package/dist/cjs/MessageBox/JumpButton.js +1 -1
  43. package/dist/cjs/MessageBox/JumpButton.test.js +4 -4
  44. package/dist/cjs/MessageBox/MessageBox.d.ts +9 -0
  45. package/dist/cjs/MessageBox/MessageBox.js +2 -2
  46. package/dist/cjs/MessageBox/MessageBox.test.js +2 -2
  47. package/dist/cjs/SourcesCard/SourcesCard.d.ts +13 -1
  48. package/dist/cjs/SourcesCard/SourcesCard.js +6 -6
  49. package/dist/cjs/SourcesCard/SourcesCard.test.js +49 -0
  50. package/dist/cjs/ToolResponse/ToolResponse.d.ts +30 -0
  51. package/dist/cjs/ToolResponse/ToolResponse.js +18 -0
  52. package/dist/cjs/ToolResponse/ToolResponse.test.d.ts +1 -0
  53. package/dist/cjs/ToolResponse/ToolResponse.test.js +60 -0
  54. package/dist/cjs/ToolResponse/index.d.ts +2 -0
  55. package/dist/cjs/ToolResponse/index.js +23 -0
  56. package/dist/cjs/index.d.ts +6 -0
  57. package/dist/cjs/index.js +10 -1
  58. package/dist/css/main.css +273 -17
  59. package/dist/css/main.css.map +1 -1
  60. package/dist/dynamic/DeepThinking/package.json +1 -0
  61. package/dist/dynamic/FilePreview/package.json +1 -0
  62. package/dist/dynamic/ToolResponse/package.json +1 -0
  63. package/dist/esm/Chatbot/Chatbot.js +1 -7
  64. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
  65. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
  66. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +22 -2
  67. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +17 -11
  68. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +41 -3
  69. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
  70. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
  71. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
  72. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.js +22 -0
  73. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
  74. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +20 -0
  75. package/dist/esm/ChatbotHeader/index.d.ts +1 -0
  76. package/dist/esm/ChatbotHeader/index.js +1 -0
  77. package/dist/esm/DeepThinking/DeepThinking.d.ts +18 -0
  78. package/dist/esm/DeepThinking/DeepThinking.js +14 -0
  79. package/dist/esm/DeepThinking/DeepThinking.test.d.ts +1 -0
  80. package/dist/esm/DeepThinking/DeepThinking.test.js +43 -0
  81. package/dist/esm/DeepThinking/index.d.ts +2 -0
  82. package/dist/esm/DeepThinking/index.js +2 -0
  83. package/dist/esm/FilePreview/FilePreview.d.ts +26 -0
  84. package/dist/esm/FilePreview/FilePreview.js +21 -0
  85. package/dist/esm/FilePreview/FilePreview.test.d.ts +1 -0
  86. package/dist/esm/FilePreview/FilePreview.test.js +92 -0
  87. package/dist/esm/FilePreview/index.d.ts +2 -0
  88. package/dist/esm/FilePreview/index.js +2 -0
  89. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +5 -5
  90. package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +2 -1
  91. package/dist/esm/Message/LinkMessage/LinkMessage.js +7 -3
  92. package/dist/esm/Message/ListMessage/ListItemMessage.d.ts +1 -1
  93. package/dist/esm/Message/ListMessage/ListItemMessage.js +16 -1
  94. package/dist/esm/Message/Message.d.ts +15 -0
  95. package/dist/esm/Message/Message.js +129 -32
  96. package/dist/esm/Message/Message.test.js +71 -0
  97. package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
  98. package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.js +3 -0
  99. package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +15 -1
  100. package/dist/esm/Message/UserFeedback/UserFeedback.js +4 -4
  101. package/dist/esm/Message/UserFeedback/UserFeedback.test.js +45 -1
  102. package/dist/esm/MessageBar/MessageBar.js +19 -4
  103. package/dist/esm/MessageBox/JumpButton.d.ts +5 -0
  104. package/dist/esm/MessageBox/JumpButton.js +1 -1
  105. package/dist/esm/MessageBox/JumpButton.test.js +4 -4
  106. package/dist/esm/MessageBox/MessageBox.d.ts +9 -0
  107. package/dist/esm/MessageBox/MessageBox.js +2 -2
  108. package/dist/esm/MessageBox/MessageBox.test.js +2 -2
  109. package/dist/esm/SourcesCard/SourcesCard.d.ts +13 -1
  110. package/dist/esm/SourcesCard/SourcesCard.js +6 -6
  111. package/dist/esm/SourcesCard/SourcesCard.test.js +50 -1
  112. package/dist/esm/ToolResponse/ToolResponse.d.ts +30 -0
  113. package/dist/esm/ToolResponse/ToolResponse.js +14 -0
  114. package/dist/esm/ToolResponse/ToolResponse.test.d.ts +1 -0
  115. package/dist/esm/ToolResponse/ToolResponse.test.js +55 -0
  116. package/dist/esm/ToolResponse/index.d.ts +2 -0
  117. package/dist/esm/ToolResponse/index.js +2 -0
  118. package/dist/esm/index.d.ts +6 -0
  119. package/dist/esm/index.js +6 -0
  120. package/dist/tsconfig.tsbuildinfo +1 -1
  121. package/package.json +7 -6
  122. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +101 -3
  123. package/patternfly-docs/content/extensions/chatbot/examples/Messages/FilePreview.tsx +33 -0
  124. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +17 -0
  125. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +111 -85
  126. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithSources.tsx +70 -0
  127. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +135 -0
  128. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +28 -4
  129. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +107 -2
  130. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +616 -3
  131. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotConversationEditing.tsx +202 -0
  132. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx +17 -3
  133. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +36 -5
  134. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +12 -2
  135. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +22 -3
  136. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +1 -1
  137. package/patternfly-docs/patternfly-docs.config.js +1 -1
  138. package/src/Chatbot/Chatbot.scss +9 -2
  139. package/src/Chatbot/Chatbot.tsx +18 -31
  140. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +5 -1
  141. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +28 -10
  142. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +132 -3
  143. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +80 -33
  144. package/src/ChatbotHeader/ChatbotHeaderMenu.test.tsx +1 -1
  145. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +2 -2
  146. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx +25 -0
  147. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx +64 -0
  148. package/src/ChatbotHeader/index.ts +1 -0
  149. package/src/ChatbotModal/ChatbotModal.scss +1 -1
  150. package/src/DeepThinking/DeepThinking.scss +24 -0
  151. package/src/DeepThinking/DeepThinking.test.tsx +61 -0
  152. package/src/DeepThinking/DeepThinking.tsx +68 -0
  153. package/src/DeepThinking/index.ts +3 -0
  154. package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +6 -9
  155. package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +6 -9
  156. package/src/FilePreview/FilePreview.scss +22 -0
  157. package/src/FilePreview/FilePreview.test.tsx +112 -0
  158. package/src/FilePreview/FilePreview.tsx +58 -0
  159. package/src/FilePreview/index.ts +3 -0
  160. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +2 -1
  161. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +6 -5
  162. package/src/Message/LinkMessage/LinkMessage.tsx +6 -2
  163. package/src/Message/ListMessage/ListItemMessage.tsx +5 -1
  164. package/src/Message/ListMessage/ListMessage.scss +17 -0
  165. package/src/Message/Message.scss +44 -0
  166. package/src/Message/Message.test.tsx +90 -0
  167. package/src/Message/Message.tsx +171 -46
  168. package/src/Message/SuperscriptMessage/SuperscriptMessage.scss +8 -0
  169. package/src/Message/SuperscriptMessage/SuperscriptMessage.tsx +13 -0
  170. package/src/Message/TextMessage/TextMessage.scss +46 -5
  171. package/src/Message/UserFeedback/UserFeedback.test.tsx +107 -0
  172. package/src/Message/UserFeedback/UserFeedback.tsx +41 -6
  173. package/src/MessageBar/MessageBar.tsx +23 -3
  174. package/src/MessageBox/JumpButton.test.tsx +4 -4
  175. package/src/MessageBox/JumpButton.tsx +20 -4
  176. package/src/MessageBox/MessageBox.test.tsx +2 -2
  177. package/src/MessageBox/MessageBox.tsx +22 -1
  178. package/src/SourcesCard/SourcesCard.scss +17 -0
  179. package/src/SourcesCard/SourcesCard.test.tsx +93 -0
  180. package/src/SourcesCard/SourcesCard.tsx +116 -80
  181. package/src/ToolResponse/ToolResponse.scss +36 -0
  182. package/src/ToolResponse/ToolResponse.test.tsx +78 -0
  183. package/src/ToolResponse/ToolResponse.tsx +95 -0
  184. package/src/ToolResponse/index.ts +3 -0
  185. package/src/index.ts +9 -0
  186. package/src/main.scss +3 -0
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("@testing-library/react");
8
+ require("@testing-library/jest-dom");
9
+ const FilePreview_1 = __importDefault(require("./FilePreview"));
10
+ const Chatbot_1 = require("../Chatbot");
11
+ const react_core_1 = require("@patternfly/react-core");
12
+ describe('FilePreview', () => {
13
+ const defaultProps = {
14
+ isModalOpen: true,
15
+ handleModalToggle: jest.fn(),
16
+ fileName: 'test-file.txt',
17
+ children: 'File content preview'
18
+ };
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ });
22
+ it('should render with basic props', () => {
23
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps)));
24
+ expect(react_1.screen.getByText('File preview')).toBeInTheDocument();
25
+ expect(react_1.screen.getByText('test-file.txt')).toBeInTheDocument();
26
+ });
27
+ it('should render with custom title', () => {
28
+ const customTitle = 'Custom file preview title';
29
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { title: customTitle })));
30
+ expect(react_1.screen.getByRole('heading', { name: customTitle })).toBeTruthy();
31
+ });
32
+ it('should handle modal toggle when closed', () => {
33
+ const mockToggle = jest.fn();
34
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { isModalOpen: false, handleModalToggle: mockToggle })));
35
+ expect(react_1.screen.queryByRole('dialog')).not.toBeInTheDocument();
36
+ });
37
+ it('should apply default display mode class', () => {
38
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps)));
39
+ const modal = react_1.screen.getByRole('dialog');
40
+ expect(modal).toHaveClass('pf-chatbot__file-preview-modal--default');
41
+ });
42
+ it('should apply custom display mode class', () => {
43
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen })));
44
+ const modal = react_1.screen.getByRole('dialog');
45
+ expect(modal).toHaveClass('pf-chatbot__file-preview-modal--fullscreen');
46
+ });
47
+ it('should apply compact styling when isCompact is true', () => {
48
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { isCompact: true })));
49
+ const modal = react_1.screen.getByRole('dialog');
50
+ expect(modal).toHaveClass('pf-m-compact');
51
+ });
52
+ it('should not apply compact styling when isCompact is false', () => {
53
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { isCompact: false })));
54
+ const modal = react_1.screen.getByRole('dialog');
55
+ expect(modal).not.toHaveClass('pf-m-compact');
56
+ });
57
+ it('should apply custom className', () => {
58
+ const customClass = 'custom-file-preview';
59
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { className: customClass })));
60
+ const modal = react_1.screen.getByRole('dialog');
61
+ expect(modal).toHaveClass(customClass);
62
+ });
63
+ it('should pass through additional props to ChatbotModal', () => {
64
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { "data-testid": "file-preview-modal" })));
65
+ const modal = react_1.screen.getByTestId('file-preview-modal');
66
+ expect(modal).toBeInTheDocument();
67
+ });
68
+ it('should pass modalHeaderProps to ModalHeader', () => {
69
+ const modalHeaderProps = {
70
+ 'data-testid': 'custom-header'
71
+ };
72
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { modalHeaderProps: modalHeaderProps })));
73
+ const header = react_1.screen.getByTestId('custom-header');
74
+ expect(header).toBeInTheDocument();
75
+ });
76
+ it('should pass modalBodyProps to ModalBody', () => {
77
+ const modalBodyProps = {
78
+ 'data-testid': 'custom-body'
79
+ };
80
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { modalBodyProps: modalBodyProps })));
81
+ const body = react_1.screen.getByTestId('custom-body');
82
+ expect(body).toBeInTheDocument();
83
+ });
84
+ it('should pass ouiaId to ChatbotModal', () => {
85
+ const ouiaId = 'file-preview-ouia-id';
86
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { ouiaId: ouiaId })));
87
+ const modal = react_1.screen.getByRole('dialog');
88
+ expect(modal).toHaveAttribute('data-ouia-component-id', ouiaId);
89
+ });
90
+ it('should handle complex children', () => {
91
+ const complexChildren = ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: "File details" }), (0, jsx_runtime_1.jsx)("p", { children: "Size: 1.2 MB" }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { children: "Download" })] }));
92
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(FilePreview_1.default, Object.assign({}, defaultProps, { children: complexChildren })));
93
+ expect(react_1.screen.getByRole('heading', { name: /File details/i })).toBeTruthy();
94
+ expect(react_1.screen.getByText('Size: 1.2 MB')).toBeTruthy();
95
+ expect(react_1.screen.getByRole('button', { name: /Download/i })).toBeTruthy();
96
+ });
97
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from './FilePreview';
2
+ export * from './FilePreview';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.default = void 0;
21
+ var FilePreview_1 = require("./FilePreview");
22
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(FilePreview_1).default; } });
23
+ __exportStar(require("./FilePreview"), exports);
@@ -28,9 +28,9 @@ const CodeBlockMessage = (_a) => {
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)();
31
- const tooltipID = (0, react_1.useId)();
32
- const toggleId = (0, react_1.useId)();
33
- const contentId = (0, react_1.useId)();
31
+ const tooltipID = (0, react_core_1.getUniqueId)();
32
+ const toggleId = (0, react_core_1.getUniqueId)();
33
+ const contentId = (0, react_core_1.getUniqueId)();
34
34
  const codeBlockRef = (0, react_1.useRef)(null);
35
35
  const language = (_b = /language-(\w+)/.exec(className || '')) === null || _b === void 0 ? void 0 : _b[1];
36
36
  // Get custom toggle text from data attributes if available - for use with rehype plugins
@@ -1,3 +1,4 @@
1
1
  import { ButtonProps } from '@patternfly/react-core';
2
- declare const LinkMessage: ({ children, target, href, ...props }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
2
+ import { ExtraProps } from 'react-markdown';
3
+ declare const LinkMessage: ({ children, target, href, id, ...props }: ButtonProps & ExtraProps) => import("react/jsx-runtime").JSX.Element;
3
4
  export default LinkMessage;
@@ -18,10 +18,14 @@ const jsx_runtime_1 = require("react/jsx-runtime");
18
18
  const react_core_1 = require("@patternfly/react-core");
19
19
  const react_icons_1 = require("@patternfly/react-icons");
20
20
  const LinkMessage = (_a) => {
21
- var { children, target, href } = _a, props = __rest(_a, ["children", "target", "href"]);
21
+ var { children, target, href, id } = _a, props = __rest(_a, ["children", "target", "href", "id"]);
22
22
  if (target === '_blank') {
23
- return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: "link", href: href, icon: (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkSquareAltIcon, {}), iconPosition: "end", isInline: true, target: target }, props, { children: children })));
23
+ return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: "link", href: href, icon: (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkSquareAltIcon, {}), iconPosition: "end", isInline: true, target: target,
24
+ // need to explicitly call this out or id doesn't seem to get passed - required for footnotes
25
+ id: id }, props, { children: children })));
24
26
  }
25
- return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ isInline: true, component: "a", href: href, variant: "link" }, props, { children: children })));
27
+ return (
28
+ // need to explicitly call this out or id doesn't seem to get passed - required for footnotes
29
+ (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ isInline: true, component: "a", href: href, variant: "link", id: id }, props, { children: children })));
26
30
  };
27
31
  exports.default = LinkMessage;
@@ -1,3 +1,3 @@
1
1
  import { ExtraProps } from 'react-markdown';
2
- declare const ListItemMessage: ({ children }: JSX.IntrinsicElements["li"] & ExtraProps) => import("react/jsx-runtime").JSX.Element;
2
+ declare const ListItemMessage: ({ children, ...props }: JSX.IntrinsicElements["li"] & ExtraProps) => import("react/jsx-runtime").JSX.Element;
3
3
  export default ListItemMessage;
@@ -1,6 +1,21 @@
1
1
  "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
2
13
  Object.defineProperty(exports, "__esModule", { value: true });
3
14
  const jsx_runtime_1 = require("react/jsx-runtime");
4
15
  const react_core_1 = require("@patternfly/react-core");
5
- const ListItemMessage = ({ children }) => (0, jsx_runtime_1.jsx)(react_core_1.ListItem, { children: children });
16
+ const ListItemMessage = (_a) => {
17
+ var _b;
18
+ var { children } = _a, props = __rest(_a, ["children"]);
19
+ return ((0, jsx_runtime_1.jsx)(react_core_1.ListItem, Object.assign({}, props, { tabIndex: ((_b = props === null || props === void 0 ? void 0 : props.id) === null || _b === void 0 ? void 0 : _b.includes('fn-')) ? -1 : props === null || props === void 0 ? void 0 : props.tabIndex, children: children })));
20
+ };
6
21
  exports.default = ListItemMessage;
@@ -1,5 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import type { FunctionComponent, HTMLProps, MouseEvent as ReactMouseEvent, Ref } from 'react';
3
+ import { Options } from 'react-markdown';
3
4
  import { AlertProps, AvatarProps, ButtonProps, ExpandableSectionProps, ExpandableSectionToggleProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
4
5
  import { ActionProps } from '../ResponseActions/ResponseActions';
5
6
  import { SourcesCardProps } from '../SourcesCard';
@@ -9,6 +10,8 @@ import { UserFeedbackProps } from './UserFeedback/UserFeedback';
9
10
  import { UserFeedbackCompleteProps } from './UserFeedback/UserFeedbackComplete';
10
11
  import { TableProps } from '@patternfly/react-table';
11
12
  import { PluggableList } from 'unified';
13
+ import { ToolResponseProps } from '../ToolResponse';
14
+ import { DeepThinkingProps } from '../DeepThinking';
12
15
  export interface MessageAttachment {
13
16
  /** Name of file attached to the message */
14
17
  name: string;
@@ -116,6 +119,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
116
119
  tableProps?: Required<Pick<TableProps, 'aria-label'>> & TableProps;
117
120
  /** Additional rehype plugins passed from the consumer */
118
121
  additionalRehypePlugins?: PluggableList;
122
+ /** Additional remark plugins passed from the consumer */
123
+ additionalRemarkPlugins?: PluggableList;
119
124
  /** Whether to open links in message in new tab. */
120
125
  openLinkInNewTab?: boolean;
121
126
  /** Optional inline error message that can be displayed in the message */
@@ -140,6 +145,16 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
140
145
  editFormProps?: FormProps;
141
146
  /** Sets message to compact styling. */
142
147
  isCompact?: boolean;
148
+ /** Disables markdown parsing for message, allowing only text input */
149
+ isMarkdownDisabled?: boolean;
150
+ /** Allows passing additional props down to markdown parser react-markdown, such as allowedElements and disallowedElements. See https://github.com/remarkjs/react-markdown?tab=readme-ov-file#options for options */
151
+ reactMarkdownProps?: Options;
152
+ /** Props for tool response card */
153
+ toolResponse?: ToolResponseProps;
154
+ /** Props for deep thinking card */
155
+ deepThinking?: DeepThinkingProps;
156
+ /** Allows passing additional props down to remark-gfm. See https://github.com/remarkjs/remark-gfm?tab=readme-ov-file#options for options */
157
+ remarkGfmProps?: Options;
143
158
  }
144
159
  export declare const MessageBase: FunctionComponent<MessageProps>;
145
160
  declare const Message: import("react").ForwardRefExoticComponent<Omit<MessageProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -50,8 +50,11 @@ const LinkMessage_1 = __importDefault(require("./LinkMessage/LinkMessage"));
50
50
  const ErrorMessage_1 = __importDefault(require("./ErrorMessage/ErrorMessage"));
51
51
  const MessageInput_1 = __importDefault(require("./MessageInput"));
52
52
  const rehypeMoveImagesOutOfParagraphs_1 = require("./Plugins/rehypeMoveImagesOutOfParagraphs");
53
+ const ToolResponse_1 = __importDefault(require("../ToolResponse"));
54
+ const DeepThinking_1 = __importDefault(require("../DeepThinking"));
55
+ const SuperscriptMessage_1 = __importDefault(require("./SuperscriptMessage/SuperscriptMessage"));
53
56
  const MessageBase = (_a) => {
54
- 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 = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact } = _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", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact"]);
57
+ 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 } = _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"]);
55
58
  const [messageText, setMessageText] = (0, react_1.useState)(content);
56
59
  (0, react_1.useEffect)(() => {
57
60
  setMessageText(content);
@@ -73,6 +76,129 @@ const MessageBase = (_a) => {
73
76
  // Keep timestamps consistent between Timestamp component and aria-label
74
77
  const date = new Date();
75
78
  const dateString = timestamp !== null && timestamp !== void 0 ? timestamp : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
79
+ const handleMarkdown = () => {
80
+ if (isMarkdownDisabled) {
81
+ return ((0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, props, { children: messageText })));
82
+ }
83
+ return ((0, jsx_runtime_1.jsx)(react_markdown_1.default, Object.assign({ components: {
84
+ section: (props) => {
85
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
86
+ const { node } = props, rest = __rest(props, ["node"]);
87
+ return (0, jsx_runtime_1.jsx)("section", Object.assign({}, rest, { className: `pf-chatbot__message-text ${rest === null || rest === void 0 ? void 0 : rest.className}` }));
88
+ },
89
+ p: (props) => {
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
91
+ const { node } = props, rest = __rest(props, ["node"]);
92
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, rest));
93
+ },
94
+ code: (_a) => {
95
+ var { children } = _a, props = __rest(_a, ["children"]);
96
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
97
+ const { node } = props, codeProps = __rest(props, ["node"]);
98
+ return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, codeProps, codeBlockProps, { children: children })));
99
+ },
100
+ h1: (props) => {
101
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
102
+ const { node } = props, rest = __rest(props, ["node"]);
103
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h1 }, rest));
104
+ },
105
+ h2: (props) => {
106
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
107
+ const { node } = props, rest = __rest(props, ["node"]);
108
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h2 }, rest));
109
+ },
110
+ h3: (props) => {
111
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
112
+ const { node } = props, rest = __rest(props, ["node"]);
113
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h3 }, rest));
114
+ },
115
+ h4: (props) => {
116
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
117
+ const { node } = props, rest = __rest(props, ["node"]);
118
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h4 }, rest));
119
+ },
120
+ h5: (props) => {
121
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
122
+ const { node } = props, rest = __rest(props, ["node"]);
123
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h5 }, rest));
124
+ },
125
+ h6: (props) => {
126
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
127
+ const { node } = props, rest = __rest(props, ["node"]);
128
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h6 }, rest));
129
+ },
130
+ blockquote: (props) => {
131
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
132
+ const { node } = props, rest = __rest(props, ["node"]);
133
+ return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.blockquote }, rest));
134
+ },
135
+ ul: (props) => {
136
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
137
+ const { node } = props, rest = __rest(props, ["node"]);
138
+ return (0, jsx_runtime_1.jsx)(UnorderedListMessage_1.default, Object.assign({}, rest));
139
+ },
140
+ ol: (props) => {
141
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
142
+ const { node } = props, rest = __rest(props, ["node"]);
143
+ return (0, jsx_runtime_1.jsx)(OrderedListMessage_1.default, Object.assign({}, rest));
144
+ },
145
+ li: (props) => {
146
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
147
+ const { node } = props, rest = __rest(props, ["node"]);
148
+ return (0, jsx_runtime_1.jsx)(ListItemMessage_1.default, Object.assign({}, rest));
149
+ },
150
+ // table requires node attribute for calculating headers for mobile breakpoint
151
+ table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps)),
152
+ tbody: (props) => {
153
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
154
+ const { node } = props, rest = __rest(props, ["node"]);
155
+ return (0, jsx_runtime_1.jsx)(TbodyMessage_1.default, Object.assign({}, rest));
156
+ },
157
+ thead: (props) => {
158
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
+ const { node } = props, rest = __rest(props, ["node"]);
160
+ return (0, jsx_runtime_1.jsx)(TheadMessage_1.default, Object.assign({}, rest));
161
+ },
162
+ tr: (props) => {
163
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
164
+ const { node } = props, rest = __rest(props, ["node"]);
165
+ return (0, jsx_runtime_1.jsx)(TrMessage_1.default, Object.assign({}, rest));
166
+ },
167
+ td: (props) => {
168
+ // Conflicts with Td type
169
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
170
+ const { node, width } = props, rest = __rest(props, ["node", "width"]);
171
+ return (0, jsx_runtime_1.jsx)(TdMessage_1.default, Object.assign({}, rest));
172
+ },
173
+ th: (props) => {
174
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
175
+ const { node } = props, rest = __rest(props, ["node"]);
176
+ return (0, jsx_runtime_1.jsx)(ThMessage_1.default, Object.assign({}, rest));
177
+ },
178
+ img: (props) => {
179
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
180
+ const { node } = props, rest = __rest(props, ["node"]);
181
+ return (0, jsx_runtime_1.jsx)(ImageMessage_1.default, Object.assign({}, rest));
182
+ },
183
+ a: (props) => {
184
+ // node is just the details of the document structure - not needed
185
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
186
+ const { node } = props, rest = __rest(props, ["node"]);
187
+ return (
188
+ // some a types conflict with ButtonProps, but it's ok because we are using an a tag
189
+ // there are too many to handle manually
190
+ (0, jsx_runtime_1.jsx)(LinkMessage_1.default, Object.assign({}, rest, linkProps, { children: props.children })));
191
+ },
192
+ // used for footnotes
193
+ sup: (props) => {
194
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
195
+ const { node } = props, rest = __rest(props, ["node"]);
196
+ return (0, jsx_runtime_1.jsx)(SuperscriptMessage_1.default, Object.assign({}, rest));
197
+ }
198
+ }, remarkPlugins: [[remark_gfm_1.default, Object.assign({}, remarkGfmProps)], ...additionalRemarkPlugins], rehypePlugins: rehypePlugins }, reactMarkdownProps, { remarkRehypeOptions: Object.assign({
199
+ // removes sr-only class from footnote labels applied by default
200
+ footnoteLabelProperties: { className: [''] } }, reactMarkdownProps === null || reactMarkdownProps === void 0 ? void 0 : reactMarkdownProps.remarkRehypeOptions), children: messageText })));
201
+ };
76
202
  const renderMessage = () => {
77
203
  if (isLoading) {
78
204
  return (0, jsx_runtime_1.jsx)(MessageLoading_1.default, { loadingWord: loadingWord });
@@ -83,38 +209,9 @@ const MessageBase = (_a) => {
83
209
  setMessageText(value);
84
210
  }, onEditCancel: onEditCancel, inputRef: inputRef }, editFormProps))] }));
85
211
  }
86
- 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))) : ((0, jsx_runtime_1.jsx)(react_markdown_1.default, { components: {
87
- p: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, props)),
88
- code: (_a) => {
89
- var { children } = _a, props = __rest(_a, ["children"]);
90
- return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, props, codeBlockProps, { children: children })));
91
- },
92
- h1: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h1 }, props)),
93
- h2: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h2 }, props)),
94
- h3: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h3 }, props)),
95
- h4: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h4 }, props)),
96
- h5: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h5 }, props)),
97
- h6: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.h6 }, props)),
98
- blockquote: (props) => (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.blockquote }, props)),
99
- ul: (props) => (0, jsx_runtime_1.jsx)(UnorderedListMessage_1.default, Object.assign({}, props)),
100
- ol: (props) => (0, jsx_runtime_1.jsx)(OrderedListMessage_1.default, Object.assign({}, props)),
101
- li: (props) => (0, jsx_runtime_1.jsx)(ListItemMessage_1.default, Object.assign({}, props)),
102
- table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps)),
103
- tbody: (props) => (0, jsx_runtime_1.jsx)(TbodyMessage_1.default, Object.assign({}, props)),
104
- thead: (props) => (0, jsx_runtime_1.jsx)(TheadMessage_1.default, Object.assign({}, props)),
105
- tr: (props) => (0, jsx_runtime_1.jsx)(TrMessage_1.default, Object.assign({}, props)),
106
- td: (props) => {
107
- // Conflicts with Td type
108
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
- const { width } = props, rest = __rest(props, ["width"]);
110
- return (0, jsx_runtime_1.jsx)(TdMessage_1.default, Object.assign({}, rest));
111
- },
112
- th: (props) => (0, jsx_runtime_1.jsx)(ThMessage_1.default, Object.assign({}, props)),
113
- img: (props) => (0, jsx_runtime_1.jsx)(ImageMessage_1.default, Object.assign({}, props)),
114
- a: (props) => ((0, jsx_runtime_1.jsx)(LinkMessage_1.default, Object.assign({ href: props.href, rel: props.rel, target: props.target }, linkProps, { children: props.children })))
115
- }, remarkPlugins: [remark_gfm_1.default], rehypePlugins: rehypePlugins, children: messageText }))] }));
212
+ 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()] }));
116
213
  };
117
- 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 }), !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) => {
214
+ 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)), !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) => {
118
215
  var _a;
119
216
  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));
120
217
  }) })), !isLoading && endContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: endContent })] })] })] })));
@@ -141,8 +141,26 @@ const EMPTY_TABLE = `
141
141
  | |
142
142
 
143
143
  `;
144
+ const FOOTNOTE = `This is some text with a footnote[^1] and here's a longer one.[^bignote]
145
+
146
+ You can also reference the same footnote multiple times[^1].
147
+
148
+ [^1]: This is the full footnote text. You can click the arrow to go back up.
149
+
150
+ [^bignote]: Here's one with multiple paragraphs and **formatting**.
151
+
152
+ Indent paragraphs to include them in the footnote.
153
+
154
+ Add as many paragraphs as you like. You can include *italic text*, **bold text**, and even \`code\`.
155
+
156
+ > You can even include blockquotes in footnotes!`;
144
157
  const IMAGE = `![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
145
158
  const INLINE_IMAGE = `inline text ![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
159
+ const DEEP_THINKING = {
160
+ toggleContent: 'Show thinking',
161
+ subheading: 'Thought for 3 seconds',
162
+ body: "Here's why I said this."
163
+ };
146
164
  const ERROR = {
147
165
  title: 'Could not load chat',
148
166
  children: 'Wait a few minutes and check your network settings. If the issue persists: ',
@@ -526,6 +544,20 @@ describe('Message', () => {
526
544
  } }));
527
545
  expect(react_2.screen.getAllByRole('img')[1]).toHaveAttribute('src', 'test.png');
528
546
  }));
547
+ it('should handle tool response correctly', () => __awaiter(void 0, void 0, void 0, function* () {
548
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", toolResponse: {
549
+ toggleContent: 'Tool response: Name',
550
+ subheading: 'Thought for 3 seconds',
551
+ body: 'Lorem ipsum dolor sit amet',
552
+ cardTitle: 'Card title',
553
+ cardBody: 'Card body'
554
+ } }));
555
+ expect(react_2.screen.getByRole('button', { name: /Tool response: Name/i })).toBeTruthy();
556
+ expect(react_2.screen.getByText('Thought for 3 seconds')).toBeTruthy();
557
+ expect(react_2.screen.getByText('Lorem ipsum dolor sit amet')).toBeTruthy();
558
+ expect(react_2.screen.getByText('Card title')).toBeTruthy();
559
+ expect(react_2.screen.getByText('Card body')).toBeTruthy();
560
+ }));
529
561
  it('should handle block quote correctly', () => {
530
562
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: BLOCK_QUOTES }));
531
563
  expect(react_2.screen.getByText(/Blockquotes can also be nested.../)).toBeTruthy();
@@ -591,6 +623,28 @@ describe('Message', () => {
591
623
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: TABLE, tableProps: { 'aria-label': 'Test' } }));
592
624
  expect(react_2.screen.getByRole('grid', { name: /Test/i })).toBeTruthy();
593
625
  });
626
+ it('should render footnote correctly', () => {
627
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: FOOTNOTE }));
628
+ expect(react_2.screen.getByText(/This is some text with a footnote/i)).toBeTruthy();
629
+ expect(react_2.screen.getByText(/and here's a longer one./i)).toBeTruthy();
630
+ expect(react_2.screen.getByText(/You can also reference the same footnote multiple times./i)).toBeTruthy();
631
+ expect(react_2.screen.getByRole('heading', { name: /Footnotes/i })).toBeTruthy();
632
+ expect(react_2.screen.getByText(/This is the full footnote text. You can click the arrow to go back up./i)).toBeTruthy();
633
+ expect(react_2.screen.getByText(/Here's one with multiple paragraphs and/i)).toBeTruthy();
634
+ expect(react_2.screen.getByText(/formatting/i)).toBeTruthy();
635
+ expect(react_2.screen.getByText(/Indent paragraphs to include them in the footnote./i)).toBeTruthy();
636
+ expect(react_2.screen.getByText(/Add as many paragraphs as you like. You can include/i)).toBeTruthy();
637
+ expect(react_2.screen.getByText(/italic text/i)).toBeTruthy();
638
+ expect(react_2.screen.getByText(/bold text/i)).toBeTruthy();
639
+ expect(react_2.screen.getByText(/, and even/i)).toBeTruthy();
640
+ expect(react_2.screen.getByText(/code/i)).toBeTruthy();
641
+ expect(react_2.screen.getByText(/You can even include blockquotes in footnotes!/i)).toBeTruthy();
642
+ expect(react_2.screen.getAllByRole('link', { name: '1' })).toHaveLength(2);
643
+ expect(react_2.screen.getAllByRole('link', { name: '2' })).toBeTruthy();
644
+ expect(react_2.screen.getByRole('link', { name: 'Back to reference 1' })).toBeTruthy();
645
+ expect(react_2.screen.getByRole('link', { name: 'Back to reference 1-2' })).toBeTruthy();
646
+ expect(react_2.screen.getByRole('link', { name: /Back to reference 2/i })).toBeTruthy();
647
+ });
594
648
  it('should render beforeMainContent with main content', () => {
595
649
  const mainContent = 'Main message content';
596
650
  const beforeMainContentText = 'Before main content';
@@ -739,4 +793,21 @@ describe('Message', () => {
739
793
  const form = container.querySelector('form');
740
794
  expect(form).toHaveClass('test');
741
795
  });
796
+ it('should be able to disable markdown parsing', () => {
797
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, isMarkdownDisabled: true }));
798
+ // this is looking for markdown syntax that is ordinarily stripped
799
+ expect(react_2.screen.getByText(/~~~yaml/i)).toBeTruthy();
800
+ });
801
+ it('should be able to pass props to react-markdown, such as disabling tags', () => {
802
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, reactMarkdownProps: { disallowedElements: ['code'] } }));
803
+ expect(react_2.screen.getByText('Here is some YAML code:')).toBeTruthy();
804
+ // code block isn't rendering
805
+ expect(react_2.screen.queryByRole('button', { name: 'Copy code' })).toBeFalsy();
806
+ });
807
+ it('should render deep thinking section correctly', () => {
808
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", deepThinking: DEEP_THINKING }));
809
+ expect(react_2.screen.getByRole('button', { name: /Show thinking/i })).toBeTruthy();
810
+ expect(react_2.screen.getByText('Thought for 3 seconds')).toBeTruthy();
811
+ expect(react_2.screen.getByText("Here's why I said this.")).toBeTruthy();
812
+ });
742
813
  });
@@ -0,0 +1,3 @@
1
+ import { ExtraProps } from 'react-markdown';
2
+ declare const SuperscriptMessage: ({ children }: JSX.IntrinsicElements["sup"] & ExtraProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default SuperscriptMessage;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const SuperscriptMessage = ({ children }) => ((0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__message-superscript", children: (0, jsx_runtime_1.jsx)("sup", { children: children }) }));
5
+ exports.default = SuperscriptMessage;
@@ -1,5 +1,5 @@
1
1
  import type { FunctionComponent } from 'react';
2
- import { CardProps, LabelGroupProps, OUIAProps } from '@patternfly/react-core';
2
+ import { ActionGroupProps, ButtonProps, CardBodyProps, CardHeaderProps, CardProps, FormProps, LabelGroupProps, OUIAProps, TextAreaProps } from '@patternfly/react-core';
3
3
  import QuickResponse from '../QuickResponse/QuickResponse';
4
4
  export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProps {
5
5
  /** Additional classes for the pagination navigation container. */
@@ -34,6 +34,20 @@ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProp
34
34
  focusOnLoad?: boolean;
35
35
  /** Timestamp passed in by Message for more context in aria announcements */
36
36
  timestamp?: string;
37
+ /** Additional props passed to submit button */
38
+ submitButtonProps?: ButtonProps;
39
+ /** Additional props passed to card header */
40
+ cardHeaderProps?: CardHeaderProps;
41
+ /** Additional props passed to card body */
42
+ cardBodyProps?: CardBodyProps;
43
+ /** Additional props passed to title heading */
44
+ headingLevelProps?: React.HTMLAttributes<HTMLHeadingElement>;
45
+ /** Additional props passed to form */
46
+ formProps?: FormProps;
47
+ /** Additional props passed to text area */
48
+ textAreaProps?: TextAreaProps;
49
+ /** Additional props passed to action group */
50
+ actionGroupProps?: ActionGroupProps;
37
51
  }
38
52
  declare const UserFeedback: FunctionComponent<UserFeedbackProps>;
39
53
  export default UserFeedback;
@@ -21,7 +21,7 @@ const react_core_1 = require("@patternfly/react-core");
21
21
  const QuickResponse_1 = __importDefault(require("../QuickResponse/QuickResponse"));
22
22
  const CloseButton_1 = __importDefault(require("./CloseButton"));
23
23
  const UserFeedback = (_a) => {
24
- var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact"]);
24
+ var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact, children, cardHeaderProps, cardBodyProps, headingLevelProps, formProps, textAreaProps, actionGroupProps, submitButtonProps } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact", "children", "cardHeaderProps", "cardBodyProps", "headingLevelProps", "formProps", "textAreaProps", "actionGroupProps", "submitButtonProps"]);
25
25
  const [selectedResponse, setSelectedResponse] = (0, react_1.useState)();
26
26
  const [value, setValue] = (0, react_1.useState)('');
27
27
  const divRef = (0, react_1.useRef)(null);
@@ -33,11 +33,11 @@ const UserFeedback = (_a) => {
33
33
  }, []);
34
34
  return (
35
35
  /* card does not have ref forwarding; hence wrapper div */
36
- (0, jsx_runtime_1.jsx)("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardHeader, { actions: {
36
+ (0, jsx_runtime_1.jsx)("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardHeader, Object.assign({ actions: {
37
37
  actions: (0, jsx_runtime_1.jsx)(CloseButton_1.default, { onClose: onClose, ariaLabel: closeButtonAriaLabel })
38
- }, children: (0, jsx_runtime_1.jsx)(HeadingLevel, { className: "pf-chatbot__feedback-card-title", children: title }) }), (0, jsx_runtime_1.jsx)(react_core_1.CardBody, { children: (0, jsx_runtime_1.jsxs)(react_core_1.Form, { className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}`, children: [quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, onSelect: (id) => setSelectedResponse(id), isCompact: isCompact })), hasTextArea && ((0, jsx_runtime_1.jsx)(react_core_1.TextArea, { value: value, onChange: (_event, value) => {
38
+ } }, cardHeaderProps, { children: (0, jsx_runtime_1.jsx)(HeadingLevel, Object.assign({ className: "pf-chatbot__feedback-card-title" }, headingLevelProps, { children: title })) })), (0, jsx_runtime_1.jsx)(react_core_1.CardBody, Object.assign({}, cardBodyProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.Form, Object.assign({ className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}` }, formProps, { children: [quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, onSelect: (id) => setSelectedResponse(id), isCompact: isCompact })), hasTextArea && ((0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ value: value, onChange: (_event, value) => {
39
39
  setValue(value);
40
40
  onTextAreaChange && onTextAreaChange(_event, value);
41
- }, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" })), (0, jsx_runtime_1.jsx)(react_core_1.ActionGroup, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, { onClick: () => onSubmit(selectedResponse, value), children: submitWord }) })] }) })] })) }));
41
+ }, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" }, textAreaProps))), children, (0, jsx_runtime_1.jsx)(react_core_1.ActionGroup, Object.assign({}, actionGroupProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ onClick: () => onSubmit(selectedResponse, value) }, submitButtonProps, { children: submitWord })) }))] })) }))] })) }));
42
42
  };
43
43
  exports.default = UserFeedback;