@patternfly/chatbot 6.4.0-prerelease.2 → 6.4.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 (225) 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/FileDetails/FileDetails.d.ts +22 -3
  22. package/dist/cjs/FileDetails/FileDetails.js +27 -912
  23. package/dist/cjs/FileDetails/FileDetails.test.js +16 -0
  24. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +8 -2
  25. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.js +14 -2
  26. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.test.js +19 -1
  27. package/dist/cjs/FilePreview/FilePreview.d.ts +26 -0
  28. package/dist/cjs/FilePreview/FilePreview.js +26 -0
  29. package/dist/cjs/FilePreview/FilePreview.test.d.ts +1 -0
  30. package/dist/cjs/FilePreview/FilePreview.test.js +97 -0
  31. package/dist/cjs/FilePreview/index.d.ts +2 -0
  32. package/dist/cjs/FilePreview/index.js +23 -0
  33. package/dist/cjs/ImagePreview/ImagePreview.d.ts +53 -0
  34. package/dist/cjs/ImagePreview/ImagePreview.js +47 -0
  35. package/dist/cjs/ImagePreview/ImagePreview.test.d.ts +1 -0
  36. package/dist/cjs/ImagePreview/ImagePreview.test.js +225 -0
  37. package/dist/cjs/ImagePreview/index.d.ts +2 -0
  38. package/dist/cjs/ImagePreview/index.js +23 -0
  39. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
  40. package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +2 -1
  41. package/dist/cjs/Message/LinkMessage/LinkMessage.js +7 -3
  42. package/dist/cjs/Message/ListMessage/ListItemMessage.d.ts +1 -1
  43. package/dist/cjs/Message/ListMessage/ListItemMessage.js +16 -1
  44. package/dist/cjs/Message/Message.d.ts +15 -0
  45. package/dist/cjs/Message/Message.js +129 -32
  46. package/dist/cjs/Message/Message.test.js +71 -0
  47. package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
  48. package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.js +5 -0
  49. package/dist/cjs/Message/UserFeedback/UserFeedback.d.ts +15 -1
  50. package/dist/cjs/Message/UserFeedback/UserFeedback.js +4 -4
  51. package/dist/cjs/Message/UserFeedback/UserFeedback.test.js +44 -0
  52. package/dist/cjs/MessageBar/MessageBar.js +19 -4
  53. package/dist/cjs/MessageBox/JumpButton.d.ts +5 -0
  54. package/dist/cjs/MessageBox/JumpButton.js +1 -1
  55. package/dist/cjs/MessageBox/JumpButton.test.js +4 -4
  56. package/dist/cjs/MessageBox/MessageBox.d.ts +9 -0
  57. package/dist/cjs/MessageBox/MessageBox.js +2 -2
  58. package/dist/cjs/MessageBox/MessageBox.test.js +2 -2
  59. package/dist/cjs/SourcesCard/SourcesCard.d.ts +13 -1
  60. package/dist/cjs/SourcesCard/SourcesCard.js +6 -6
  61. package/dist/cjs/SourcesCard/SourcesCard.test.js +49 -0
  62. package/dist/cjs/ToolResponse/ToolResponse.d.ts +30 -0
  63. package/dist/cjs/ToolResponse/ToolResponse.js +18 -0
  64. package/dist/cjs/ToolResponse/ToolResponse.test.d.ts +1 -0
  65. package/dist/cjs/ToolResponse/ToolResponse.test.js +60 -0
  66. package/dist/cjs/ToolResponse/index.d.ts +2 -0
  67. package/dist/cjs/ToolResponse/index.js +23 -0
  68. package/dist/cjs/index.d.ts +8 -0
  69. package/dist/cjs/index.js +13 -1
  70. package/dist/css/main.css +339 -27
  71. package/dist/css/main.css.map +1 -1
  72. package/dist/dynamic/DeepThinking/package.json +1 -0
  73. package/dist/dynamic/FilePreview/package.json +1 -0
  74. package/dist/dynamic/ImagePreview/package.json +1 -0
  75. package/dist/dynamic/ToolResponse/package.json +1 -0
  76. package/dist/esm/Chatbot/Chatbot.js +1 -7
  77. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
  78. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
  79. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +22 -2
  80. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +17 -11
  81. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +41 -3
  82. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
  83. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
  84. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
  85. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.js +22 -0
  86. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
  87. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +20 -0
  88. package/dist/esm/ChatbotHeader/index.d.ts +1 -0
  89. package/dist/esm/ChatbotHeader/index.js +1 -0
  90. package/dist/esm/DeepThinking/DeepThinking.d.ts +18 -0
  91. package/dist/esm/DeepThinking/DeepThinking.js +14 -0
  92. package/dist/esm/DeepThinking/DeepThinking.test.d.ts +1 -0
  93. package/dist/esm/DeepThinking/DeepThinking.test.js +43 -0
  94. package/dist/esm/DeepThinking/index.d.ts +2 -0
  95. package/dist/esm/DeepThinking/index.js +2 -0
  96. package/dist/esm/FileDetails/FileDetails.d.ts +22 -3
  97. package/dist/esm/FileDetails/FileDetails.js +27 -912
  98. package/dist/esm/FileDetails/FileDetails.test.js +16 -0
  99. package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +8 -2
  100. package/dist/esm/FileDetailsLabel/FileDetailsLabel.js +14 -2
  101. package/dist/esm/FileDetailsLabel/FileDetailsLabel.test.js +19 -1
  102. package/dist/esm/FilePreview/FilePreview.d.ts +26 -0
  103. package/dist/esm/FilePreview/FilePreview.js +21 -0
  104. package/dist/esm/FilePreview/FilePreview.test.d.ts +1 -0
  105. package/dist/esm/FilePreview/FilePreview.test.js +92 -0
  106. package/dist/esm/FilePreview/index.d.ts +2 -0
  107. package/dist/esm/FilePreview/index.js +2 -0
  108. package/dist/esm/ImagePreview/ImagePreview.d.ts +53 -0
  109. package/dist/esm/ImagePreview/ImagePreview.js +42 -0
  110. package/dist/esm/ImagePreview/ImagePreview.test.d.ts +1 -0
  111. package/dist/esm/ImagePreview/ImagePreview.test.js +220 -0
  112. package/dist/esm/ImagePreview/index.d.ts +2 -0
  113. package/dist/esm/ImagePreview/index.js +2 -0
  114. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +5 -5
  115. package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +2 -1
  116. package/dist/esm/Message/LinkMessage/LinkMessage.js +7 -3
  117. package/dist/esm/Message/ListMessage/ListItemMessage.d.ts +1 -1
  118. package/dist/esm/Message/ListMessage/ListItemMessage.js +16 -1
  119. package/dist/esm/Message/Message.d.ts +15 -0
  120. package/dist/esm/Message/Message.js +129 -32
  121. package/dist/esm/Message/Message.test.js +71 -0
  122. package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
  123. package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.js +3 -0
  124. package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +15 -1
  125. package/dist/esm/Message/UserFeedback/UserFeedback.js +4 -4
  126. package/dist/esm/Message/UserFeedback/UserFeedback.test.js +45 -1
  127. package/dist/esm/MessageBar/MessageBar.js +19 -4
  128. package/dist/esm/MessageBox/JumpButton.d.ts +5 -0
  129. package/dist/esm/MessageBox/JumpButton.js +1 -1
  130. package/dist/esm/MessageBox/JumpButton.test.js +4 -4
  131. package/dist/esm/MessageBox/MessageBox.d.ts +9 -0
  132. package/dist/esm/MessageBox/MessageBox.js +2 -2
  133. package/dist/esm/MessageBox/MessageBox.test.js +2 -2
  134. package/dist/esm/SourcesCard/SourcesCard.d.ts +13 -1
  135. package/dist/esm/SourcesCard/SourcesCard.js +6 -6
  136. package/dist/esm/SourcesCard/SourcesCard.test.js +50 -1
  137. package/dist/esm/ToolResponse/ToolResponse.d.ts +30 -0
  138. package/dist/esm/ToolResponse/ToolResponse.js +14 -0
  139. package/dist/esm/ToolResponse/ToolResponse.test.d.ts +1 -0
  140. package/dist/esm/ToolResponse/ToolResponse.test.js +55 -0
  141. package/dist/esm/ToolResponse/index.d.ts +2 -0
  142. package/dist/esm/ToolResponse/index.js +2 -0
  143. package/dist/esm/index.d.ts +8 -0
  144. package/dist/esm/index.js +8 -0
  145. package/dist/tsconfig.tsbuildinfo +1 -1
  146. package/package.json +7 -6
  147. package/patternfly-docs/content/extensions/chatbot/examples/Messages/AttachmentEdit.tsx +1 -1
  148. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +101 -3
  149. package/patternfly-docs/content/extensions/chatbot/examples/Messages/FilePreview.tsx +33 -0
  150. package/patternfly-docs/content/extensions/chatbot/examples/Messages/ImagePreview.tsx +53 -0
  151. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +17 -0
  152. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +111 -85
  153. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithSources.tsx +70 -0
  154. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +135 -0
  155. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +38 -4
  156. package/patternfly-docs/content/extensions/chatbot/examples/Messages/PreviewAttachment.tsx +1 -1
  157. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +107 -2
  158. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +616 -3
  159. package/patternfly-docs/content/extensions/chatbot/examples/Messages/file-preview.svg +9 -0
  160. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotConversationEditing.tsx +202 -0
  161. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx +17 -3
  162. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +36 -5
  163. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +12 -2
  164. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +22 -3
  165. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +1 -1
  166. package/patternfly-docs/patternfly-docs.config.js +1 -1
  167. package/src/Chatbot/Chatbot.scss +9 -2
  168. package/src/Chatbot/Chatbot.tsx +18 -31
  169. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +5 -1
  170. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +16 -10
  171. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +132 -3
  172. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +80 -33
  173. package/src/ChatbotHeader/ChatbotHeaderMenu.test.tsx +1 -1
  174. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +2 -2
  175. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx +25 -0
  176. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx +64 -0
  177. package/src/ChatbotHeader/index.ts +1 -0
  178. package/src/ChatbotModal/ChatbotModal.scss +1 -1
  179. package/src/DeepThinking/DeepThinking.scss +24 -0
  180. package/src/DeepThinking/DeepThinking.test.tsx +61 -0
  181. package/src/DeepThinking/DeepThinking.tsx +68 -0
  182. package/src/DeepThinking/index.ts +3 -0
  183. package/src/FileDetails/FileDetails.scss +10 -0
  184. package/src/FileDetails/FileDetails.test.tsx +16 -0
  185. package/src/FileDetails/FileDetails.tsx +89 -32
  186. package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +20 -14
  187. package/src/FileDetailsLabel/FileDetailsLabel.test.tsx +21 -1
  188. package/src/FileDetailsLabel/FileDetailsLabel.tsx +16 -3
  189. package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +20 -14
  190. package/src/FilePreview/FilePreview.scss +22 -0
  191. package/src/FilePreview/FilePreview.test.tsx +112 -0
  192. package/src/FilePreview/FilePreview.tsx +58 -0
  193. package/src/FilePreview/index.ts +3 -0
  194. package/src/ImagePreview/ImagePreview.scss +61 -0
  195. package/src/ImagePreview/ImagePreview.test.tsx +253 -0
  196. package/src/ImagePreview/ImagePreview.tsx +200 -0
  197. package/src/ImagePreview/index.ts +3 -0
  198. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +2 -1
  199. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +6 -5
  200. package/src/Message/LinkMessage/LinkMessage.tsx +6 -2
  201. package/src/Message/ListMessage/ListItemMessage.tsx +5 -1
  202. package/src/Message/ListMessage/ListMessage.scss +17 -0
  203. package/src/Message/Message.scss +44 -0
  204. package/src/Message/Message.test.tsx +90 -0
  205. package/src/Message/Message.tsx +171 -46
  206. package/src/Message/SuperscriptMessage/SuperscriptMessage.scss +8 -0
  207. package/src/Message/SuperscriptMessage/SuperscriptMessage.tsx +13 -0
  208. package/src/Message/TextMessage/TextMessage.scss +46 -5
  209. package/src/Message/UserFeedback/UserFeedback.test.tsx +107 -0
  210. package/src/Message/UserFeedback/UserFeedback.tsx +41 -6
  211. package/src/MessageBar/MessageBar.tsx +23 -3
  212. package/src/MessageBox/JumpButton.test.tsx +4 -4
  213. package/src/MessageBox/JumpButton.tsx +20 -4
  214. package/src/MessageBox/MessageBox.scss +0 -12
  215. package/src/MessageBox/MessageBox.test.tsx +2 -2
  216. package/src/MessageBox/MessageBox.tsx +23 -2
  217. package/src/SourcesCard/SourcesCard.scss +17 -0
  218. package/src/SourcesCard/SourcesCard.test.tsx +93 -0
  219. package/src/SourcesCard/SourcesCard.tsx +116 -80
  220. package/src/ToolResponse/ToolResponse.scss +36 -0
  221. package/src/ToolResponse/ToolResponse.test.tsx +78 -0
  222. package/src/ToolResponse/ToolResponse.tsx +95 -0
  223. package/src/ToolResponse/index.ts +3 -0
  224. package/src/index.ts +12 -0
  225. package/src/main.scss +16 -0
@@ -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;
@@ -134,4 +134,48 @@ describe('UserFeedback', () => {
134
134
  (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, "data-testid": "card", isCompact: true }));
135
135
  expect(react_1.screen.getByTestId('card')).toHaveClass('pf-m-compact');
136
136
  });
137
+ it('should pass buttonProps to submit button', () => {
138
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, submitButtonProps: { variant: 'secondary', isDisabled: true } }));
139
+ const submitButton = react_1.screen.getByRole('button', { name: /Submit/i });
140
+ expect(submitButton).toHaveClass('pf-v6-c-button pf-m-secondary');
141
+ expect(submitButton).toBeDisabled();
142
+ });
143
+ it('should pass cardHeaderProps to card header', () => {
144
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardHeaderProps: { 'data-testid': 'card-header', className: 'custom-header' } }));
145
+ const cardHeader = react_1.screen.getByTestId('card-header');
146
+ expect(cardHeader).toHaveClass('custom-header');
147
+ });
148
+ it('should pass cardBodyProps to card body', () => {
149
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardBodyProps: { 'data-testid': 'card-body', className: 'custom-body' } }));
150
+ const cardBody = react_1.screen.getByTestId('card-body');
151
+ expect(cardBody).toHaveClass('custom-body');
152
+ });
153
+ it('should pass headingLevelProps to title heading', () => {
154
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, headingLevelProps: { className: 'custom-heading', id: 'feedback-title' } }));
155
+ const heading = react_1.screen.getByRole('heading', { level: 1, name: /Why did you choose this rating?/i });
156
+ expect(heading).toHaveClass('custom-heading');
157
+ expect(heading).toHaveAttribute('id', 'feedback-title');
158
+ });
159
+ it('should pass formProps to form', () => {
160
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, formProps: { 'data-testid': 'feedback-form', className: 'custom-form' } }));
161
+ const form = react_1.screen.getByTestId('feedback-form');
162
+ expect(form).toHaveClass('custom-form');
163
+ });
164
+ it('should pass textAreaProps to text area when hasTextArea is true', () => {
165
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, textAreaProps: { 'data-testid': 'custom-textarea', rows: 5 } }));
166
+ const textArea = react_1.screen.getByTestId('custom-textarea');
167
+ expect(textArea).toHaveAttribute('rows', '5');
168
+ expect(textArea).toHaveAttribute('data-testid', 'custom-textarea');
169
+ });
170
+ it('should pass actionGroupProps to action group', () => {
171
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, actionGroupProps: { 'data-testid': 'action-group', className: 'custom-actions' } }));
172
+ const actionGroup = react_1.screen.getByTestId('action-group');
173
+ expect(actionGroup).toHaveClass('custom-actions');
174
+ });
175
+ it('should render children', () => {
176
+ (0, react_1.render)((0, jsx_runtime_1.jsxs)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "custom-content", children: "Custom feedback content" }), (0, jsx_runtime_1.jsx)("p", { children: "Additional paragraph" })] }));
177
+ expect(react_1.screen.getByTestId('custom-content')).toBeInTheDocument();
178
+ expect(react_1.screen.getByText('Custom feedback content')).toBeInTheDocument();
179
+ expect(react_1.screen.getByText('Additional paragraph')).toBeInTheDocument();
180
+ });
137
181
  });
@@ -32,6 +32,7 @@ const MessageBarBase = (_a) => {
32
32
  const [message, setMessage] = (0, react_1.useState)(value !== null && value !== void 0 ? value : '');
33
33
  const [isListeningMessage, setIsListeningMessage] = (0, react_1.useState)(false);
34
34
  const [hasSentMessage, setHasSentMessage] = (0, react_1.useState)(false);
35
+ const [isComposing, setIsComposing] = (0, react_1.useState)(false);
35
36
  const inputRef = (0, react_1.useRef)(null);
36
37
  const textareaRef = (_b = innerRef) !== null && _b !== void 0 ? _b : inputRef;
37
38
  const attachButtonRef = (0, react_1.useRef)(null);
@@ -157,18 +158,32 @@ const MessageBarBase = (_a) => {
157
158
  setMessage('');
158
159
  }, [onSendMessage]);
159
160
  const handleKeyDown = (0, react_1.useCallback)((event) => {
160
- if (event.key === 'Enter' && !event.shiftKey) {
161
+ // Japanese and other languages may use IME for character input.
162
+ // In these cases, enter is used to select the final input, so we need to check for composition end instead.
163
+ // See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/
164
+ // Chrome, Edge, and Firefox seem to work well with just the compose event.
165
+ // Safari is a little bit special. We need to handle 229 as well in this case.
166
+ const nativeEvent = event.nativeEvent;
167
+ const isCompositionKey = nativeEvent.which === 229;
168
+ const isCurrentlyComposing = isComposing || isCompositionKey;
169
+ if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) {
161
170
  event.preventDefault();
162
171
  if (!isSendButtonDisabled && !hasStopButton) {
163
172
  handleSend(message);
164
173
  }
165
174
  }
166
- if (event.key === 'Enter' && event.shiftKey) {
175
+ if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) {
167
176
  if (textareaRef.current) {
168
177
  handleNewLine(textareaRef.current);
169
178
  }
170
179
  }
171
- }, [isSendButtonDisabled, hasStopButton, handleSend, message]);
180
+ }, [isSendButtonDisabled, hasStopButton, handleSend, message, isComposing]);
181
+ const handleCompositionStart = (0, react_1.useCallback)(() => {
182
+ setIsComposing(true);
183
+ }, []);
184
+ const handleCompositionEnd = (0, react_1.useCallback)(() => {
185
+ setIsComposing(false);
186
+ }, []);
172
187
  const handleAttachMenuToggle = () => {
173
188
  (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.setIsAttachMenuOpen) && (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.setIsAttachMenuOpen(!(attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.isAttachMenuOpen)));
174
189
  attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuToggleClick();
@@ -184,7 +199,7 @@ const MessageBarBase = (_a) => {
184
199
  }
185
200
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [attachMenuProps && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))), !attachMenuProps && hasAttachButton && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))), hasMicrophoneButton && ((0, jsx_runtime_1.jsx)(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))), (alwayShowSendButton || message) && ((0, jsx_runtime_1.jsx)(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))] }));
186
201
  };
187
- const messageBarContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown }, props)) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
202
+ const messageBarContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd }, props)) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
188
203
  if (attachMenuProps) {
189
204
  return ((0, jsx_runtime_1.jsx)(AttachMenu_1.default, Object.assign({ toggle: (toggleRef) => ((0, jsx_runtime_1.jsx)("div", { ref: toggleRef, className: `pf-chatbot__message-bar ${className !== null && className !== void 0 ? className : ''}`, children: messageBarContents })), filteredItems: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.attachMenuItems }, (attachMenuProps && { isOpen: attachMenuProps.isAttachMenuOpen }), { onOpenChange: (isAttachMenuOpen) => {
190
205
  var _a;
@@ -1,4 +1,5 @@
1
1
  import type { FunctionComponent } from 'react';
2
+ import { TooltipProps, ButtonProps } from '@patternfly/react-core';
2
3
  export interface JumpButtonProps {
3
4
  /** Position of the Jump Button(top/bottom) */
4
5
  position: 'top' | 'bottom';
@@ -6,6 +7,10 @@ export interface JumpButtonProps {
6
7
  onClick: () => void;
7
8
  /** Flag to change the visibilty of the button */
8
9
  isHidden?: boolean;
10
+ /** Additional props passed to jump buttons */
11
+ jumpButtonProps?: ButtonProps;
12
+ /** Additional props passed to tooltip */
13
+ jumpButtonTooltipProps?: TooltipProps;
9
14
  }
10
15
  declare const JumpButton: FunctionComponent<JumpButtonProps>;
11
16
  export default JumpButton;
@@ -5,5 +5,5 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_core_1 = require("@patternfly/react-core");
6
6
  const arrow_up_icon_1 = require("@patternfly/react-icons/dist/esm/icons/arrow-up-icon");
7
7
  const arrow_down_icon_1 = require("@patternfly/react-icons/dist/esm/icons/arrow-down-icon");
8
- const JumpButton = ({ position, isHidden, onClick }) => isHidden ? null : ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { id: `pf-chatbot__tooltip--jump-${position}`, content: `Back to ${position}`, position: "top", children: (0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "plain", className: `pf-chatbot__jump pf-chatbot__jump--${position}`, "aria-label": `Jump ${position}`, onClick: onClick, children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: "lg", isInline: true, children: position === 'top' ? (0, jsx_runtime_1.jsx)(arrow_up_icon_1.ArrowUpIcon, {}) : (0, jsx_runtime_1.jsx)(arrow_down_icon_1.ArrowDownIcon, {}) }) }) }));
8
+ const JumpButton = ({ position, isHidden, onClick, jumpButtonProps, jumpButtonTooltipProps }) => isHidden ? null : ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ id: `pf-chatbot__tooltip--jump-${position}`, content: `Back to ${position}`, position: "top" }, jumpButtonTooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ variant: "plain", className: `pf-chatbot__jump pf-chatbot__jump--${position}`, "aria-label": `Back to ${position}`, onClick: onClick }, jumpButtonProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: "lg", isInline: true, children: position === 'top' ? (0, jsx_runtime_1.jsx)(arrow_up_icon_1.ArrowUpIcon, {}) : (0, jsx_runtime_1.jsx)(arrow_down_icon_1.ArrowDownIcon, {}) }) })) })));
9
9
  exports.default = JumpButton;
@@ -20,20 +20,20 @@ const user_event_1 = __importDefault(require("@testing-library/user-event"));
20
20
  describe('JumpButton', () => {
21
21
  it('should render top button correctly', () => {
22
22
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", onClick: jest.fn() }));
23
- expect(react_1.screen.getByRole('button', { name: /Jump top/i })).toBeTruthy();
23
+ expect(react_1.screen.getByRole('button', { name: /Back to top/i })).toBeTruthy();
24
24
  });
25
25
  it('should render bottom button correctly', () => {
26
26
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: jest.fn() }));
27
- expect(react_1.screen.getByRole('button', { name: /Jump bottom/i })).toBeTruthy();
27
+ expect(react_1.screen.getByRole('button', { name: /Back to bottom/i })).toBeTruthy();
28
28
  });
29
29
  it('should call onClick appropriately', () => __awaiter(void 0, void 0, void 0, function* () {
30
30
  const spy = jest.fn();
31
31
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: spy }));
32
- yield user_event_1.default.click(react_1.screen.getByRole('button', { name: /Jump bottom/i }));
32
+ yield user_event_1.default.click(react_1.screen.getByRole('button', { name: /Back to bottom/i }));
33
33
  expect(spy).toHaveBeenCalledTimes(1);
34
34
  }));
35
35
  it('should be hidden if isHidden prop is used', () => __awaiter(void 0, void 0, void 0, function* () {
36
36
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: jest.fn(), isHidden: true }));
37
- expect(react_1.screen.queryByRole('button', { name: /Jump bottom/i })).toBeFalsy();
37
+ expect(react_1.screen.queryByRole('button', { name: /Back to bottom/i })).toBeFalsy();
38
38
  }));
39
39
  });
@@ -1,4 +1,5 @@
1
1
  import { HTMLProps, ReactNode } from 'react';
2
+ import { ButtonProps, TooltipProps } from '@patternfly/react-core';
2
3
  export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
3
4
  /** Content that can be announced, such as a new message, for screen readers */
4
5
  announcement?: string;
@@ -18,6 +19,14 @@ export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
18
19
  onScrollToBottomClick?: () => void;
19
20
  /** Flag to enable automatic scrolling when new messages are added */
20
21
  enableSmartScroll?: boolean;
22
+ /** Props passed to top jump button */
23
+ jumpButtonTopProps?: ButtonProps;
24
+ /** Props passed to bottom jump button */
25
+ jumpButtonBottomProps?: ButtonProps;
26
+ /** Props passed to top jump button tooltip */
27
+ jumpButtonTopTooltipProps?: TooltipProps;
28
+ /** Props passed to top jump button tooltip */
29
+ jumpButtonBottomTooltipProps?: TooltipProps;
21
30
  }
22
31
  export interface MessageBoxHandle extends HTMLDivElement {
23
32
  /** Scrolls to the top of the message box */
@@ -22,7 +22,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
22
22
  const react_1 = require("react");
23
23
  const JumpButton_1 = __importDefault(require("./JumpButton"));
24
24
  exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
25
- var { announcement, ariaLabel = 'Scrollable message log', children, className, position = 'top', onScrollToTopClick, onScrollToBottomClick, enableSmartScroll = false } = _a, props = __rest(_a, ["announcement", "ariaLabel", "children", "className", "position", "onScrollToTopClick", "onScrollToBottomClick", "enableSmartScroll"]);
25
+ var { announcement, ariaLabel = 'Scrollable message log', children, className, position = 'top', onScrollToTopClick, onScrollToBottomClick, enableSmartScroll = false, jumpButtonTopProps, jumpButtonBottomProps, jumpButtonBottomTooltipProps, jumpButtonTopTooltipProps } = _a, props = __rest(_a, ["announcement", "ariaLabel", "children", "className", "position", "onScrollToTopClick", "onScrollToBottomClick", "enableSmartScroll", "jumpButtonTopProps", "jumpButtonBottomProps", "jumpButtonBottomTooltipProps", "jumpButtonTopTooltipProps"]);
26
26
  const [atTop, setAtTop] = (0, react_1.useState)(false);
27
27
  const [atBottom, setAtBottom] = (0, react_1.useState)(true);
28
28
  const [isOverflowing, setIsOverflowing] = (0, react_1.useState)(false);
@@ -206,6 +206,6 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
206
206
  onTouchMove,
207
207
  onTouchEnd
208
208
  };
209
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' ? 'pf-chatbot__messagebox--bottom' : ''} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__messagebox-announcement", "aria-live": "polite", children: announcement })] })), (0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }) })] }));
209
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop, jumpButtonProps: jumpButtonTopProps, jumpButtonTooltipProps: jumpButtonTopTooltipProps }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' ? 'pf-chatbot__messagebox--bottom' : ''} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__messagebox-announcement pf-chatbot-m-hidden", "aria-live": "polite", children: announcement })] })), (0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }), jumpButtonProps: jumpButtonBottomProps, jumpButtonTooltipProps: jumpButtonBottomTooltipProps })] }));
210
210
  });
211
211
  exports.default = exports.MessageBox;
@@ -56,7 +56,7 @@ describe('MessageBox', () => {
56
56
  region.dispatchEvent(new Event('scroll'));
57
57
  });
58
58
  yield (0, react_2.waitFor)(() => {
59
- user_event_1.default.click(react_2.screen.getByRole('button', { name: /Jump bottom/i }));
59
+ user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to bottom/i }));
60
60
  expect(spy).toHaveBeenCalled();
61
61
  });
62
62
  }));
@@ -75,7 +75,7 @@ describe('MessageBox', () => {
75
75
  region.dispatchEvent(new Event('scroll'));
76
76
  });
77
77
  yield (0, react_2.waitFor)(() => {
78
- user_event_1.default.click(react_2.screen.getByRole('button', { name: /Jump top/i }));
78
+ user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to top/i }));
79
79
  expect(spy).toHaveBeenCalled();
80
80
  });
81
81
  }));
@@ -1,5 +1,5 @@
1
1
  import type { FunctionComponent } from 'react';
2
- import { ButtonProps, CardProps } from '@patternfly/react-core';
2
+ import { ButtonProps, CardBodyProps, CardFooterProps, CardProps, CardTitleProps, TruncateProps } from '@patternfly/react-core';
3
3
  export interface SourcesCardProps extends CardProps {
4
4
  /** Additional classes for the pagination navigation container. */
5
5
  className?: string;
@@ -13,6 +13,8 @@ export interface SourcesCardProps extends CardProps {
13
13
  sources: {
14
14
  /** Title of sources card */
15
15
  title?: string;
16
+ /** Subtitle of sources card */
17
+ subtitle?: string;
16
18
  /** Link to source */
17
19
  link: string;
18
20
  /** Body of sources card */
@@ -25,6 +27,10 @@ export interface SourcesCardProps extends CardProps {
25
27
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
26
28
  /** Any additional props applied to the title of the Sources card */
27
29
  titleProps?: ButtonProps;
30
+ /** Custom footer applied to the Sources card */
31
+ footer?: React.ReactNode;
32
+ /** Additional props passed to Truncate component */
33
+ truncateProps?: TruncateProps;
28
34
  }[];
29
35
  /** Label for the English word "source" */
30
36
  sourceWord?: string;
@@ -44,6 +50,12 @@ export interface SourcesCardProps extends CardProps {
44
50
  showMoreWords?: string;
45
51
  /** Label for English words "show less" */
46
52
  showLessWords?: string;
53
+ /** Additional props passed to card title */
54
+ cardTitleProps?: CardTitleProps;
55
+ /** Additional props passed to card body */
56
+ cardBodyProps?: CardBodyProps;
57
+ /** Additional props passed to card footer */
58
+ cardFooterProps?: CardFooterProps;
47
59
  }
48
60
  declare const SourcesCard: FunctionComponent<SourcesCardProps>;
49
61
  export default SourcesCard;
@@ -18,7 +18,7 @@ const react_core_1 = require("@patternfly/react-core");
18
18
  const react_icons_1 = require("@patternfly/react-icons");
19
19
  const SourcesCard = (_a) => {
20
20
  var _b;
21
- var { className, isDisabled, paginationAriaLabel = 'Pagination', sources, sourceWord = 'source', sourceWordPlural = 'sources', toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage, showMoreWords = 'show more', showLessWords = 'show less', isCompact } = _a, props = __rest(_a, ["className", "isDisabled", "paginationAriaLabel", "sources", "sourceWord", "sourceWordPlural", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage", "showMoreWords", "showLessWords", "isCompact"]);
21
+ var { className, isDisabled, paginationAriaLabel = 'Pagination', sources, sourceWord = 'source', sourceWordPlural = 'sources', toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage, showMoreWords = 'show more', showLessWords = 'show less', isCompact, cardTitleProps, cardBodyProps, cardFooterProps } = _a, props = __rest(_a, ["className", "isDisabled", "paginationAriaLabel", "sources", "sourceWord", "sourceWordPlural", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage", "showMoreWords", "showLessWords", "isCompact", "cardTitleProps", "cardBodyProps", "cardFooterProps"]);
22
22
  const [page, setPage] = (0, react_1.useState)(1);
23
23
  const [isExpanded, setIsExpanded] = (0, react_1.useState)(false);
24
24
  const onToggle = (_event, isExpanded) => {
@@ -28,15 +28,15 @@ const SourcesCard = (_a) => {
28
28
  setPage(newPage);
29
29
  onSetPage && onSetPage(_evt, newPage);
30
30
  };
31
- const renderTitle = (title) => {
31
+ const renderTitle = (title, truncateProps) => {
32
32
  if (title) {
33
- return (0, jsx_runtime_1.jsx)(react_core_1.Truncate, { content: title });
33
+ return (0, jsx_runtime_1.jsx)(react_core_1.Truncate, Object.assign({ content: title }, truncateProps));
34
34
  }
35
35
  return `Source ${page}`;
36
36
  };
37
- return ((0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__source", children: [(0, jsx_runtime_1.jsx)("span", { children: (0, react_core_1.pluralize)(sources.length, sourceWord, sourceWordPlural) }), (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: "pf-chatbot__sources-card" }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardTitle, { className: "pf-chatbot__sources-card-title", children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: react_core_1.ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkSquareAltIcon, {}) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined, onClick: (_b = sources[page - 1].onClick) !== null && _b !== void 0 ? _b : undefined }, sources[page - 1].titleProps, { children: renderTitle(sources[page - 1].title) })) }), sources[page - 1].body && ((0, jsx_runtime_1.jsx)(react_core_1.CardBody, { className: `pf-chatbot__sources-card-body`, children: sources[page - 1].hasShowMore ? (
37
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__source", children: [(0, jsx_runtime_1.jsx)("span", { children: (0, react_core_1.pluralize)(sources.length, sourceWord, sourceWordPlural) }), (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: "pf-chatbot__sources-card" }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardTitle, Object.assign({ className: "pf-chatbot__sources-card-title" }, cardTitleProps, { children: (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__sources-card-title-container", children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: react_core_1.ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkSquareAltIcon, {}) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined, onClick: (_b = sources[page - 1].onClick) !== null && _b !== void 0 ? _b : undefined }, sources[page - 1].titleProps, { children: renderTitle(sources[page - 1].title, sources[page - 1].truncateProps) })), sources[page - 1].subtitle && ((0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__sources-card-subtitle", children: sources[page - 1].subtitle }))] }) })), sources[page - 1].body && ((0, jsx_runtime_1.jsx)(react_core_1.CardBody, Object.assign({ className: `pf-chatbot__sources-card-body ${sources[page - 1].footer ? 'pf-chatbot__compact-sources-card-body' : undefined}` }, cardBodyProps, { children: sources[page - 1].hasShowMore ? (
38
38
  // prevents extra VO announcements of button text - parent Message has aria-live
39
- (0, jsx_runtime_1.jsx)("div", { "aria-live": "off", children: (0, jsx_runtime_1.jsx)(react_core_1.ExpandableSection, { variant: react_core_1.ExpandableSectionVariant.truncate, toggleText: isExpanded ? showLessWords : showMoreWords, onToggle: onToggle, isExpanded: isExpanded, truncateMaxLines: 2, children: sources[page - 1].body }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__sources-card-body-text", children: sources[page - 1].body })) })), sources.length > 1 && ((0, jsx_runtime_1.jsx)(react_core_1.CardFooter, { className: "pf-chatbot__sources-card-footer-container", children: (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__sources-card-footer", children: (0, jsx_runtime_1.jsxs)("nav", { className: `pf-chatbot__sources-card-footer-buttons ${className}`, "aria-label": paginationAriaLabel, children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: react_core_1.ButtonVariant.plain, isDisabled: isDisabled || page === 1, "data-action": "previous", onClick: (event) => {
39
+ (0, jsx_runtime_1.jsx)("div", { "aria-live": "off", children: (0, jsx_runtime_1.jsx)(react_core_1.ExpandableSection, { variant: react_core_1.ExpandableSectionVariant.truncate, toggleText: isExpanded ? showLessWords : showMoreWords, onToggle: onToggle, isExpanded: isExpanded, truncateMaxLines: 2, children: sources[page - 1].body }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__sources-card-body-text", children: sources[page - 1].body })) }))), sources[page - 1].footer ? ((0, jsx_runtime_1.jsx)(react_core_1.CardFooter, Object.assign({ className: "pf-chatbot__sources-card-footer" }, cardFooterProps, { children: sources[page - 1].footer }))) : (sources.length > 1 && ((0, jsx_runtime_1.jsx)(react_core_1.CardFooter, Object.assign({ className: "pf-chatbot__sources-card-footer-container" }, cardFooterProps, { children: (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__sources-card-footer", children: (0, jsx_runtime_1.jsxs)("nav", { className: `pf-chatbot__sources-card-footer-buttons ${className}`, "aria-label": paginationAriaLabel, children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: react_core_1.ButtonVariant.plain, isDisabled: isDisabled || page === 1, "data-action": "previous", onClick: (event) => {
40
40
  const newPage = page >= 1 ? page - 1 : 1;
41
41
  onPreviousClick && onPreviousClick(event, newPage);
42
42
  handleNewPage(event, newPage);
@@ -44,6 +44,6 @@ const SourcesCard = (_a) => {
44
44
  const newPage = page + 1 <= sources.length ? page + 1 : sources.length;
45
45
  onNextClick && onNextClick(event, newPage);
46
46
  handleNewPage(event, newPage);
47
- }, children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { isInline: true, iconSize: "lg", children: (0, jsx_runtime_1.jsx)("svg", { className: "pf-v6-svg", viewBox: "0 0 180 500", fill: "currentColor", "aria-hidden": "true", role: "img", width: "1em", height: "1em", children: (0, jsx_runtime_1.jsx)("path", { d: "M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z" }) }) }) })] }) }) }))] }))] }));
47
+ }, children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { isInline: true, iconSize: "lg", children: (0, jsx_runtime_1.jsx)("svg", { className: "pf-v6-svg", viewBox: "0 0 180 500", fill: "currentColor", "aria-hidden": "true", role: "img", width: "1em", height: "1em", children: (0, jsx_runtime_1.jsx)("path", { d: "M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z" }) }) }) })] }) }) }))))] }))] }));
48
48
  };
49
49
  exports.default = SourcesCard;
@@ -184,4 +184,53 @@ describe('SourcesCard', () => {
184
184
  (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { sources: [{ title: 'How to make an apple pie', link: '', titleProps: { className: 'test' } }] }));
185
185
  expect(react_1.screen.getByRole('link', { name: /How to make an apple pie/i })).toHaveClass('test');
186
186
  });
187
+ it('should apply cardTitleProps appropriately', () => {
188
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { cardTitleProps: { 'data-testid': 'card-title', className: 'test' }, sources: [{ title: 'How to make an apple pie', link: '' }] }));
189
+ expect(react_1.screen.getByTestId('card-title')).toHaveClass('test');
190
+ });
191
+ it('should apply cardBodyProps appropriately', () => {
192
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { cardBodyProps: { 'data-testid': 'card-body', body: 'To make an apple pie, you must first...', className: 'test' }, sources: [{ title: 'How to make an apple pie', link: '', body: 'To make an apple pie, you must first...' }] }));
193
+ expect(react_1.screen.getByTestId('card-body')).toHaveClass('test');
194
+ });
195
+ it('should apply cardFooterProps appropriately', () => {
196
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { cardFooterProps: { 'data-testid': 'card-footer', className: 'test' }, sources: [
197
+ { title: 'How to make an apple pie', link: '' },
198
+ { title: 'How to make cookies', link: '' }
199
+ ] }));
200
+ expect(react_1.screen.getByTestId('card-footer')).toHaveClass('test');
201
+ });
202
+ it('should apply truncateProps appropriately', () => {
203
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { sources: [
204
+ {
205
+ title: 'How to make an apple pie',
206
+ link: '',
207
+ truncateProps: { 'data-testid': 'card-truncate', className: 'test' }
208
+ }
209
+ ] }));
210
+ expect(react_1.screen.getByTestId('card-truncate')).toHaveClass('test');
211
+ });
212
+ it('should apply custom footer appropriately when there is one source', () => {
213
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { sources: [{ title: 'How to make an apple pie', link: '', footer: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "I am a custom footer" }) }] }));
214
+ expect(react_1.screen.getByText('I am a custom footer'));
215
+ expect(react_1.screen.queryByText('1/1')).toBeFalsy();
216
+ });
217
+ it('should apply custom footer appropriately when are multiple sources', () => {
218
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { sources: [
219
+ { title: 'How to make an apple pie', link: '', footer: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "I am a custom footer" }) },
220
+ { title: 'How to bake bread', link: '' }
221
+ ] }));
222
+ expect(react_1.screen.getByText('I am a custom footer'));
223
+ // does not show navigation bar
224
+ expect(react_1.screen.queryByText('1/2')).toBeFalsy();
225
+ });
226
+ it('should apply footer props to custom footer appropriately', () => {
227
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { cardFooterProps: { 'data-testid': 'card-footer', className: 'test' }, sources: [{ title: 'How to make an apple pie', link: '', footer: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "I am a custom footer" }) }] }));
228
+ expect(react_1.screen.getByText('I am a custom footer'));
229
+ expect(react_1.screen.getByTestId('card-footer')).toHaveClass('test');
230
+ });
231
+ it('should apply subtitle appropriately', () => {
232
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(SourcesCard_1.default, { sources: [{ title: 'How to make an apple pie', link: '', subtitle: 'You must first create the universe' }] }));
233
+ expect(react_1.screen.getByText('How to make an apple pie'));
234
+ expect(react_1.screen.getByText('You must first create the universe'));
235
+ });
187
236
  });
@@ -0,0 +1,30 @@
1
+ import { CardBodyProps, CardProps, CardTitleProps, DividerProps, ExpandableSectionProps } from '@patternfly/react-core';
2
+ import { type FunctionComponent } from 'react';
3
+ export interface ToolResponseProps {
4
+ /** Toggle content shown for expandable section */
5
+ toggleContent: React.ReactNode;
6
+ /** Additional props passed to expandable section */
7
+ expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
8
+ /** Subheading rendered inside expandable section */
9
+ subheading?: string;
10
+ /** Body text rendered inside expandable section */
11
+ body?: React.ReactNode | string;
12
+ /** Content passed into tool response card body */
13
+ cardBody: React.ReactNode;
14
+ /** Content passed into tool response card title */
15
+ cardTitle: React.ReactNode;
16
+ /** Additional props passed to main card */
17
+ cardProps?: CardProps;
18
+ /** Additional props passed to main card body */
19
+ cardBodyProps?: CardBodyProps;
20
+ /** Additional props passed to tool response card */
21
+ toolResponseCardProps?: CardProps;
22
+ /** Additional props passed to tool response card body */
23
+ toolResponseCardBodyProps?: CardBodyProps;
24
+ /** Additional props passed to tool response card divider */
25
+ toolResponseCardDividerProps?: DividerProps;
26
+ /** Additional props passed to tool response card title */
27
+ toolResponseCardTitleProps?: CardTitleProps;
28
+ }
29
+ export declare const ToolResponse: FunctionComponent<ToolResponseProps>;
30
+ export default ToolResponse;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolResponse = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ // ============================================================================
6
+ // Tool Response Card
7
+ // ============================================================================
8
+ const react_core_1 = require("@patternfly/react-core");
9
+ const react_1 = require("react");
10
+ const ToolResponse = ({ body, cardProps, expandableSectionProps, subheading, cardBody, cardTitle, cardBodyProps, toggleContent, toolResponseCardBodyProps, toolResponseCardDividerProps, toolResponseCardProps, toolResponseCardTitleProps }) => {
11
+ const [isExpanded, setIsExpanded] = (0, react_1.useState)(true);
12
+ const onToggle = (_event, isExpanded) => {
13
+ setIsExpanded(isExpanded);
14
+ };
15
+ return ((0, jsx_runtime_1.jsx)(react_core_1.Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-response" }, cardProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.CardBody, Object.assign({}, cardBodyProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.ExpandableSection, Object.assign({ toggleContent: toggleContent, onToggle: onToggle, isExpanded: isExpanded, isIndented: true, className: "pf-chatbot__tool-response-expandable-section" }, expandableSectionProps, { children: (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__tool-response-section", children: [subheading && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__tool-response-subheading", children: (0, jsx_runtime_1.jsx)("span", { children: subheading }) })), body && (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__tool-response-body", children: body }), (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-response-card" }, toolResponseCardProps, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardTitle, Object.assign({}, toolResponseCardTitleProps, { children: cardTitle })), (0, jsx_runtime_1.jsx)(react_core_1.Divider, Object.assign({}, toolResponseCardDividerProps)), (0, jsx_runtime_1.jsx)(react_core_1.CardBody, Object.assign({}, toolResponseCardBodyProps, { children: cardBody }))] }))] }) })) })) })));
16
+ };
17
+ exports.ToolResponse = ToolResponse;
18
+ exports.default = exports.ToolResponse;
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';