@patternfly/chatbot 6.5.0-prerelease.8 → 6.5.0

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 (315) hide show
  1. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +9 -1
  2. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +9 -2
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +38 -0
  4. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +29 -2
  5. package/dist/cjs/CodeModal/CodeModal.d.ts +2 -0
  6. package/dist/cjs/CodeModal/CodeModal.js +53 -12
  7. package/dist/cjs/DeepThinking/DeepThinking.d.ts +13 -0
  8. package/dist/cjs/DeepThinking/DeepThinking.js +31 -3
  9. package/dist/cjs/DeepThinking/DeepThinking.test.js +80 -0
  10. package/dist/cjs/MarkdownContent/MarkdownContent.d.ts +44 -0
  11. package/dist/cjs/MarkdownContent/MarkdownContent.js +181 -0
  12. package/dist/cjs/MarkdownContent/MarkdownContent.test.d.ts +1 -0
  13. package/dist/cjs/MarkdownContent/MarkdownContent.test.js +192 -0
  14. package/dist/cjs/MarkdownContent/index.d.ts +2 -0
  15. package/dist/cjs/MarkdownContent/index.js +23 -0
  16. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  17. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +15 -4
  18. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.test.d.ts +1 -0
  19. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.test.js +131 -0
  20. package/dist/cjs/Message/ErrorMessage/ErrorMessage.d.ts +15 -1
  21. package/dist/cjs/Message/ErrorMessage/ErrorMessage.js +5 -3
  22. package/dist/cjs/Message/ErrorMessage/ErrorMessage.test.d.ts +1 -0
  23. package/dist/cjs/Message/ErrorMessage/ErrorMessage.test.js +30 -0
  24. package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +5 -1
  25. package/dist/cjs/Message/LinkMessage/LinkMessage.js +4 -3
  26. package/dist/cjs/Message/ListMessage/OrderedListMessage.d.ts +9 -1
  27. package/dist/cjs/Message/ListMessage/OrderedListMessage.js +2 -1
  28. package/dist/cjs/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
  29. package/dist/cjs/Message/ListMessage/UnorderedListMessage.js +2 -1
  30. package/dist/cjs/Message/Message.d.ts +20 -3
  31. package/dist/cjs/Message/Message.js +7 -160
  32. package/dist/cjs/Message/Message.test.js +129 -2
  33. package/dist/cjs/Message/MessageAndActions/MessageAndActions.d.ts +14 -0
  34. package/dist/cjs/Message/MessageAndActions/MessageAndActions.js +22 -0
  35. package/dist/cjs/Message/MessageAndActions/MessageAndActions.test.d.ts +1 -0
  36. package/dist/cjs/Message/MessageAndActions/MessageAndActions.test.js +25 -0
  37. package/dist/cjs/Message/MessageAndActions/index.d.ts +1 -0
  38. package/dist/cjs/Message/MessageAndActions/index.js +17 -0
  39. package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.d.ts +13 -0
  40. package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.js +22 -0
  41. package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.test.d.ts +1 -0
  42. package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.test.js +25 -0
  43. package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.d.ts +13 -0
  44. package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.js +22 -0
  45. package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.test.d.ts +1 -0
  46. package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.test.js +25 -0
  47. package/dist/cjs/Message/MessageAttachments/index.d.ts +2 -0
  48. package/dist/cjs/Message/MessageAttachments/index.js +18 -0
  49. package/dist/cjs/Message/MessageInput.d.ts +1 -1
  50. package/dist/cjs/Message/MessageInput.js +3 -1
  51. package/dist/cjs/Message/MessageLoading.d.ts +13 -4
  52. package/dist/cjs/Message/MessageLoading.js +19 -5
  53. package/dist/cjs/Message/MessageLoading.test.d.ts +1 -0
  54. package/dist/cjs/Message/MessageLoading.test.js +25 -0
  55. package/dist/cjs/Message/QuickResponse/QuickResponse.js +3 -2
  56. package/dist/cjs/Message/QuickResponse/QuickResponse.test.d.ts +1 -0
  57. package/dist/cjs/Message/QuickResponse/QuickResponse.test.js +109 -0
  58. package/dist/cjs/Message/QuickResponse/index.d.ts +1 -0
  59. package/dist/cjs/Message/QuickResponse/index.js +17 -0
  60. package/dist/cjs/Message/QuickStarts/QuickStartTile.d.ts +1 -1
  61. package/dist/cjs/Message/QuickStarts/QuickStartTile.js +3 -2
  62. package/dist/cjs/Message/QuickStarts/index.d.ts +2 -0
  63. package/dist/cjs/Message/QuickStarts/index.js +18 -0
  64. package/dist/cjs/Message/TableMessage/TableMessage.d.ts +6 -1
  65. package/dist/cjs/Message/TableMessage/TableMessage.js +3 -2
  66. package/dist/cjs/Message/TextMessage/TextMessage.d.ts +8 -1
  67. package/dist/cjs/Message/TextMessage/TextMessage.js +3 -2
  68. package/dist/cjs/Message/UserFeedback/UserFeedback.d.ts +3 -1
  69. package/dist/cjs/Message/UserFeedback/UserFeedback.js +8 -6
  70. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.d.ts +1 -1
  71. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.js +3 -2
  72. package/dist/cjs/Message/UserFeedback/index.d.ts +2 -0
  73. package/dist/cjs/Message/UserFeedback/index.js +18 -0
  74. package/dist/cjs/Message/index.d.ts +8 -0
  75. package/dist/cjs/Message/index.js +8 -0
  76. package/dist/cjs/MessageBar/MessageBar.d.ts +4 -0
  77. package/dist/cjs/MessageBar/MessageBar.js +20 -5
  78. package/dist/cjs/MessageBar/MessageBar.test.js +8 -0
  79. package/dist/cjs/Onboarding/Onboarding.d.ts +36 -0
  80. package/dist/cjs/Onboarding/Onboarding.js +37 -0
  81. package/dist/cjs/Onboarding/Onboarding.test.d.ts +1 -0
  82. package/dist/cjs/Onboarding/Onboarding.test.js +80 -0
  83. package/dist/cjs/Onboarding/index.d.ts +2 -0
  84. package/dist/cjs/Onboarding/index.js +23 -0
  85. package/dist/cjs/ResponseActions/ResponseActions.d.ts +7 -0
  86. package/dist/cjs/ResponseActions/ResponseActions.js +28 -7
  87. package/dist/cjs/ResponseActions/ResponseActions.test.js +67 -12
  88. package/dist/cjs/ResponseActions/ResponseActionsGroups.d.ts +13 -0
  89. package/dist/cjs/ResponseActions/ResponseActionsGroups.js +22 -0
  90. package/dist/cjs/ResponseActions/ResponseActionsGroups.test.d.ts +1 -0
  91. package/dist/cjs/ResponseActions/ResponseActionsGroups.test.js +25 -0
  92. package/dist/cjs/ResponseActions/index.d.ts +1 -0
  93. package/dist/cjs/ResponseActions/index.js +1 -0
  94. package/dist/cjs/ToolCall/ToolCall.d.ts +11 -0
  95. package/dist/cjs/ToolCall/ToolCall.js +24 -3
  96. package/dist/cjs/ToolCall/ToolCall.test.js +57 -0
  97. package/dist/cjs/ToolResponse/ToolResponse.d.ts +17 -0
  98. package/dist/cjs/ToolResponse/ToolResponse.js +49 -3
  99. package/dist/cjs/ToolResponse/ToolResponse.test.js +100 -0
  100. package/dist/cjs/index.d.ts +4 -0
  101. package/dist/cjs/index.js +7 -1
  102. package/dist/css/main.css +268 -30
  103. package/dist/css/main.css.map +1 -1
  104. package/dist/dynamic/MarkdownContent/package.json +1 -0
  105. package/dist/dynamic/Onboarding/package.json +1 -0
  106. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +9 -1
  107. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +10 -3
  108. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +38 -0
  109. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +30 -3
  110. package/dist/esm/CodeModal/CodeModal.d.ts +2 -0
  111. package/dist/esm/CodeModal/CodeModal.js +54 -13
  112. package/dist/esm/DeepThinking/DeepThinking.d.ts +13 -0
  113. package/dist/esm/DeepThinking/DeepThinking.js +28 -3
  114. package/dist/esm/DeepThinking/DeepThinking.test.js +80 -0
  115. package/dist/esm/MarkdownContent/MarkdownContent.d.ts +44 -0
  116. package/dist/esm/MarkdownContent/MarkdownContent.js +174 -0
  117. package/dist/esm/MarkdownContent/MarkdownContent.test.d.ts +1 -0
  118. package/dist/esm/MarkdownContent/MarkdownContent.test.js +187 -0
  119. package/dist/esm/MarkdownContent/index.d.ts +2 -0
  120. package/dist/esm/MarkdownContent/index.js +2 -0
  121. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  122. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +15 -4
  123. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.test.d.ts +1 -0
  124. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.test.js +126 -0
  125. package/dist/esm/Message/ErrorMessage/ErrorMessage.d.ts +15 -1
  126. package/dist/esm/Message/ErrorMessage/ErrorMessage.js +3 -3
  127. package/dist/esm/Message/ErrorMessage/ErrorMessage.test.d.ts +1 -0
  128. package/dist/esm/Message/ErrorMessage/ErrorMessage.test.js +25 -0
  129. package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +5 -1
  130. package/dist/esm/Message/LinkMessage/LinkMessage.js +4 -3
  131. package/dist/esm/Message/ListMessage/OrderedListMessage.d.ts +9 -1
  132. package/dist/esm/Message/ListMessage/OrderedListMessage.js +2 -1
  133. package/dist/esm/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
  134. package/dist/esm/Message/ListMessage/UnorderedListMessage.js +2 -1
  135. package/dist/esm/Message/Message.d.ts +20 -3
  136. package/dist/esm/Message/Message.js +8 -161
  137. package/dist/esm/Message/Message.test.js +129 -2
  138. package/dist/esm/Message/MessageAndActions/MessageAndActions.d.ts +14 -0
  139. package/dist/esm/Message/MessageAndActions/MessageAndActions.js +18 -0
  140. package/dist/esm/Message/MessageAndActions/MessageAndActions.test.d.ts +1 -0
  141. package/dist/esm/Message/MessageAndActions/MessageAndActions.test.js +20 -0
  142. package/dist/esm/Message/MessageAndActions/index.d.ts +1 -0
  143. package/dist/esm/Message/MessageAndActions/index.js +1 -0
  144. package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.d.ts +13 -0
  145. package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.js +18 -0
  146. package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.test.d.ts +1 -0
  147. package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.test.js +20 -0
  148. package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.d.ts +13 -0
  149. package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.js +18 -0
  150. package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.test.d.ts +1 -0
  151. package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.test.js +20 -0
  152. package/dist/esm/Message/MessageAttachments/index.d.ts +2 -0
  153. package/dist/esm/Message/MessageAttachments/index.js +2 -0
  154. package/dist/esm/Message/MessageInput.d.ts +1 -1
  155. package/dist/esm/Message/MessageInput.js +1 -1
  156. package/dist/esm/Message/MessageLoading.d.ts +13 -4
  157. package/dist/esm/Message/MessageLoading.js +16 -4
  158. package/dist/esm/Message/MessageLoading.test.d.ts +1 -0
  159. package/dist/esm/Message/MessageLoading.test.js +20 -0
  160. package/dist/esm/Message/QuickResponse/QuickResponse.js +3 -2
  161. package/dist/esm/Message/QuickResponse/QuickResponse.test.d.ts +1 -0
  162. package/dist/esm/Message/QuickResponse/QuickResponse.test.js +104 -0
  163. package/dist/esm/Message/QuickResponse/index.d.ts +1 -0
  164. package/dist/esm/Message/QuickResponse/index.js +1 -0
  165. package/dist/esm/Message/QuickStarts/QuickStartTile.d.ts +1 -1
  166. package/dist/esm/Message/QuickStarts/QuickStartTile.js +1 -1
  167. package/dist/esm/Message/QuickStarts/index.d.ts +2 -0
  168. package/dist/esm/Message/QuickStarts/index.js +2 -0
  169. package/dist/esm/Message/TableMessage/TableMessage.d.ts +6 -1
  170. package/dist/esm/Message/TableMessage/TableMessage.js +3 -2
  171. package/dist/esm/Message/TextMessage/TextMessage.d.ts +8 -1
  172. package/dist/esm/Message/TextMessage/TextMessage.js +3 -2
  173. package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +3 -1
  174. package/dist/esm/Message/UserFeedback/UserFeedback.js +7 -7
  175. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.d.ts +1 -1
  176. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.js +1 -2
  177. package/dist/esm/Message/UserFeedback/index.d.ts +2 -0
  178. package/dist/esm/Message/UserFeedback/index.js +2 -0
  179. package/dist/esm/Message/index.d.ts +8 -0
  180. package/dist/esm/Message/index.js +8 -0
  181. package/dist/esm/MessageBar/MessageBar.d.ts +4 -0
  182. package/dist/esm/MessageBar/MessageBar.js +20 -5
  183. package/dist/esm/MessageBar/MessageBar.test.js +8 -0
  184. package/dist/esm/Onboarding/Onboarding.d.ts +36 -0
  185. package/dist/esm/Onboarding/Onboarding.js +30 -0
  186. package/dist/esm/Onboarding/Onboarding.test.d.ts +1 -0
  187. package/dist/esm/Onboarding/Onboarding.test.js +75 -0
  188. package/dist/esm/Onboarding/index.d.ts +2 -0
  189. package/dist/esm/Onboarding/index.js +2 -0
  190. package/dist/esm/ResponseActions/ResponseActions.d.ts +7 -0
  191. package/dist/esm/ResponseActions/ResponseActions.js +28 -7
  192. package/dist/esm/ResponseActions/ResponseActions.test.js +67 -12
  193. package/dist/esm/ResponseActions/ResponseActionsGroups.d.ts +13 -0
  194. package/dist/esm/ResponseActions/ResponseActionsGroups.js +18 -0
  195. package/dist/esm/ResponseActions/ResponseActionsGroups.test.d.ts +1 -0
  196. package/dist/esm/ResponseActions/ResponseActionsGroups.test.js +20 -0
  197. package/dist/esm/ResponseActions/index.d.ts +1 -0
  198. package/dist/esm/ResponseActions/index.js +1 -0
  199. package/dist/esm/ToolCall/ToolCall.d.ts +11 -0
  200. package/dist/esm/ToolCall/ToolCall.js +21 -3
  201. package/dist/esm/ToolCall/ToolCall.test.js +57 -0
  202. package/dist/esm/ToolResponse/ToolResponse.d.ts +17 -0
  203. package/dist/esm/ToolResponse/ToolResponse.js +46 -3
  204. package/dist/esm/ToolResponse/ToolResponse.test.js +100 -0
  205. package/dist/esm/index.d.ts +4 -0
  206. package/dist/esm/index.js +4 -0
  207. package/dist/tsconfig.tsbuildinfo +1 -1
  208. package/package.json +13 -3
  209. package/patternfly-docs/content/extensions/chatbot/chatbot.md +57 -0
  210. package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +12 -12
  211. package/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md +1 -1
  212. package/patternfly-docs/content/extensions/chatbot/examples/Customizing Messages/Customizing Messages.md +1 -1
  213. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +1 -0
  214. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomStructure.tsx +102 -0
  215. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +25 -11
  216. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +14 -1
  217. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownDeepThinking.tsx +26 -0
  218. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolCall.tsx +29 -0
  219. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolResponse.tsx +200 -0
  220. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMultipleActionGroups.tsx +61 -0
  221. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithPersistedActions.tsx +22 -0
  222. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickResponses.tsx +11 -0
  223. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolCall.tsx +14 -1
  224. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +222 -105
  225. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +123 -14
  226. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +1 -0
  227. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSearchActions.tsx +198 -0
  228. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarIndicatorThinking.tsx +15 -0
  229. package/patternfly-docs/content/extensions/chatbot/examples/UI/CompactOnboarding.tsx +141 -0
  230. package/patternfly-docs/content/extensions/chatbot/examples/UI/Onboarding.tsx +151 -0
  231. package/patternfly-docs/content/extensions/chatbot/examples/UI/RH-Hat-Image.svg +9 -0
  232. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +67 -29
  233. package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +18 -18
  234. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +33 -19
  235. package/patternfly-docs/patternfly-docs.config.js +1 -1
  236. package/patternfly-docs/patternfly-docs.source.js +1 -1
  237. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +43 -0
  238. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +95 -0
  239. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +51 -15
  240. package/src/ChatbotHeader/ChatbotHeader.scss +4 -0
  241. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +56 -14
  242. package/src/ChatbotModal/ChatbotModal.scss +3 -0
  243. package/src/CodeModal/CodeModal.tsx +71 -26
  244. package/src/DeepThinking/DeepThinking.scss +1 -1
  245. package/src/DeepThinking/DeepThinking.test.tsx +109 -0
  246. package/src/DeepThinking/DeepThinking.tsx +54 -5
  247. package/src/MarkdownContent/MarkdownContent.test.tsx +207 -0
  248. package/src/MarkdownContent/MarkdownContent.tsx +269 -0
  249. package/src/MarkdownContent/index.ts +2 -0
  250. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +13 -0
  251. package/src/Message/CodeBlockMessage/CodeBlockMessage.test.tsx +171 -0
  252. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +17 -4
  253. package/src/Message/ErrorMessage/ErrorMessage.test.tsx +38 -0
  254. package/src/Message/ErrorMessage/ErrorMessage.tsx +17 -2
  255. package/src/Message/LinkMessage/LinkMessage.scss +5 -0
  256. package/src/Message/LinkMessage/LinkMessage.tsx +24 -2
  257. package/src/Message/ListMessage/ListMessage.scss +8 -0
  258. package/src/Message/ListMessage/OrderedListMessage.tsx +16 -2
  259. package/src/Message/ListMessage/UnorderedListMessage.tsx +12 -2
  260. package/src/Message/Message.scss +11 -7
  261. package/src/Message/Message.test.tsx +202 -2
  262. package/src/Message/Message.tsx +129 -241
  263. package/src/Message/MessageAndActions/MessageAndActions.test.tsx +23 -0
  264. package/src/Message/MessageAndActions/MessageAndActions.tsx +22 -0
  265. package/src/Message/MessageAndActions/index.ts +1 -0
  266. package/src/Message/MessageAttachments/MessageAttachmentItem.test.tsx +23 -0
  267. package/src/Message/MessageAttachments/MessageAttachmentItem.tsx +25 -0
  268. package/src/Message/MessageAttachments/MessageAttachmentsContainer.test.tsx +23 -0
  269. package/src/Message/MessageAttachments/MessageAttachmentsContainer.tsx +25 -0
  270. package/src/Message/MessageAttachments/index.ts +2 -0
  271. package/src/Message/MessageInput.tsx +1 -1
  272. package/src/Message/MessageLoading.test.tsx +23 -0
  273. package/src/Message/MessageLoading.tsx +17 -2
  274. package/src/Message/QuickResponse/QuickResponse.scss +3 -1
  275. package/src/Message/QuickResponse/QuickResponse.test.tsx +131 -0
  276. package/src/Message/QuickResponse/QuickResponse.tsx +3 -2
  277. package/src/Message/QuickResponse/index.ts +1 -0
  278. package/src/Message/QuickStarts/QuickStartTile.tsx +1 -1
  279. package/src/Message/QuickStarts/index.ts +2 -0
  280. package/src/Message/TableMessage/TableMessage.scss +13 -1
  281. package/src/Message/TableMessage/TableMessage.tsx +18 -2
  282. package/src/Message/TextMessage/TextMessage.scss +12 -0
  283. package/src/Message/TextMessage/TextMessage.tsx +29 -2
  284. package/src/Message/UserFeedback/UserFeedback.scss +28 -1
  285. package/src/Message/UserFeedback/UserFeedback.tsx +23 -13
  286. package/src/Message/UserFeedback/UserFeedbackComplete.tsx +1 -4
  287. package/src/Message/UserFeedback/index.ts +2 -0
  288. package/src/Message/index.ts +8 -0
  289. package/src/MessageBar/AttachButton.scss +0 -1
  290. package/src/MessageBar/MessageBar.scss +48 -6
  291. package/src/MessageBar/MessageBar.test.tsx +12 -0
  292. package/src/MessageBar/MessageBar.tsx +38 -4
  293. package/src/MessageBar/MicrophoneButton.scss +0 -1
  294. package/src/MessageBar/SendButton.scss +0 -1
  295. package/src/MessageBar/StopButton.scss +0 -1
  296. package/src/Onboarding/Onboarding.scss +101 -0
  297. package/src/Onboarding/Onboarding.test.tsx +148 -0
  298. package/src/Onboarding/Onboarding.tsx +126 -0
  299. package/src/Onboarding/index.ts +3 -0
  300. package/src/ResponseActions/ResponseActions.scss +12 -1
  301. package/src/ResponseActions/ResponseActions.test.tsx +111 -12
  302. package/src/ResponseActions/ResponseActions.tsx +44 -10
  303. package/src/ResponseActions/ResponseActionsGroups.test.tsx +23 -0
  304. package/src/ResponseActions/ResponseActionsGroups.tsx +28 -0
  305. package/src/ResponseActions/index.ts +1 -0
  306. package/src/ToolCall/ToolCall.scss +1 -1
  307. package/src/ToolCall/ToolCall.test.tsx +91 -0
  308. package/src/ToolCall/ToolCall.tsx +49 -4
  309. package/src/ToolResponse/ToolResponse.scss +13 -3
  310. package/src/ToolResponse/ToolResponse.test.tsx +119 -0
  311. package/src/ToolResponse/ToolResponse.tsx +82 -7
  312. package/src/index.ts +6 -0
  313. package/src/main.scss +2 -0
  314. package/tsconfig.json +1 -1
  315. package/patternfly-docs/content/extensions/chatbot/about-chatbot.md +0 -44
@@ -6,8 +6,8 @@ import { DownloadIcon, InfoCircleIcon, RedoIcon } from '@patternfly/react-icons'
6
6
  import Message from '../Message';
7
7
 
8
8
  const ALL_ACTIONS = [
9
- { type: 'positive', label: 'Good response', clickedLabel: 'Response recorded' },
10
- { type: 'negative', label: 'Bad response', clickedLabel: 'Response recorded' },
9
+ { type: 'positive', label: 'Good response', clickedLabel: 'Good response recorded' },
10
+ { type: 'negative', label: 'Bad response', clickedLabel: 'Bad response recorded' },
11
11
  { type: 'copy', label: 'Copy', clickedLabel: 'Copied' },
12
12
  { type: 'edit', label: 'Edit', clickedLabel: 'Editing' },
13
13
  { type: 'share', label: 'Share', clickedLabel: 'Shared' },
@@ -81,7 +81,7 @@ describe('ResponseActions', () => {
81
81
  expect(button).toBeTruthy();
82
82
  });
83
83
  await userEvent.click(goodBtn);
84
- expect(screen.getByRole('button', { name: 'Response recorded' })).toHaveClass(
84
+ expect(screen.getByRole('button', { name: 'Good response recorded' })).toHaveClass(
85
85
  'pf-chatbot__button--response-action-clicked'
86
86
  );
87
87
  let unclickedButtons = buttons.filter((button) => button !== goodBtn);
@@ -89,7 +89,7 @@ describe('ResponseActions', () => {
89
89
  expect(button).not.toHaveClass('pf-chatbot__button--response-action-clicked');
90
90
  });
91
91
  await userEvent.click(badBtn);
92
- expect(screen.getByRole('button', { name: 'Response recorded' })).toHaveClass(
92
+ expect(screen.getByRole('button', { name: 'Bad response recorded' })).toHaveClass(
93
93
  'pf-chatbot__button--response-action-clicked'
94
94
  );
95
95
  unclickedButtons = buttons.filter((button) => button !== badBtn);
@@ -117,13 +117,13 @@ describe('ResponseActions', () => {
117
117
  expect(badBtn).toBeTruthy();
118
118
 
119
119
  await userEvent.click(goodBtn);
120
- expect(screen.getByRole('button', { name: 'Response recorded' })).toHaveClass(
120
+ expect(screen.getByRole('button', { name: 'Good response recorded' })).toHaveClass(
121
121
  'pf-chatbot__button--response-action-clicked'
122
122
  );
123
123
  expect(badBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
124
124
 
125
125
  await userEvent.click(badBtn);
126
- expect(screen.getByRole('button', { name: 'Response recorded' })).toHaveClass(
126
+ expect(screen.getByRole('button', { name: 'Bad response recorded' })).toHaveClass(
127
127
  'pf-chatbot__button--response-action-clicked'
128
128
  );
129
129
  expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
@@ -238,30 +238,30 @@ describe('ResponseActions', () => {
238
238
  });
239
239
 
240
240
  it('should be able to call onClick correctly', async () => {
241
- ALL_ACTIONS.forEach(async ({ type, label }) => {
241
+ for (const { type, label } of ALL_ACTIONS) {
242
242
  const spy = jest.fn();
243
243
  render(<ResponseActions actions={{ [type]: { onClick: spy } }} />);
244
244
  await userEvent.click(screen.getByRole('button', { name: label }));
245
245
  expect(spy).toHaveBeenCalledTimes(1);
246
- });
246
+ }
247
247
  });
248
248
 
249
249
  it('should swap clicked and non-clicked aria labels on click', async () => {
250
- ALL_ACTIONS.forEach(async ({ type, label, clickedLabel }) => {
250
+ for (const { type, label, clickedLabel } of ALL_ACTIONS) {
251
251
  render(<ResponseActions actions={{ [type]: { onClick: jest.fn() } }} />);
252
252
  expect(screen.getByRole('button', { name: label })).toBeTruthy();
253
253
  await userEvent.click(screen.getByRole('button', { name: label }));
254
254
  expect(screen.getByRole('button', { name: clickedLabel })).toBeTruthy();
255
- });
255
+ }
256
256
  });
257
257
 
258
258
  it('should swap clicked and non-clicked tooltips on click', async () => {
259
- ALL_ACTIONS.forEach(async ({ type, label, clickedLabel }) => {
259
+ for (const { type, label, clickedLabel } of ALL_ACTIONS) {
260
260
  render(<ResponseActions actions={{ [type]: { onClick: jest.fn() } }} />);
261
261
  expect(screen.getByRole('button', { name: label })).toBeTruthy();
262
262
  await userEvent.click(screen.getByRole('button', { name: label }));
263
263
  expect(screen.getByRole('tooltip', { name: clickedLabel })).toBeTruthy();
264
- });
264
+ }
265
265
  });
266
266
 
267
267
  it('should be able to change aria labels', () => {
@@ -322,4 +322,103 @@ describe('ResponseActions', () => {
322
322
  expect(screen.getByTestId(action[key])).toBeTruthy();
323
323
  });
324
324
  });
325
+
326
+ // we are testing for the reverse case already above
327
+ it('should not deselect when clicking outside when persistActionSelection is true', async () => {
328
+ render(
329
+ <Message
330
+ name="Bot"
331
+ role="bot"
332
+ avatar=""
333
+ content="Test content"
334
+ actions={{
335
+ positive: {},
336
+ negative: {}
337
+ }}
338
+ persistActionSelection
339
+ />
340
+ );
341
+ const goodBtn = screen.getByRole('button', { name: 'Good response' });
342
+
343
+ await userEvent.click(goodBtn);
344
+ expect(screen.getByRole('button', { name: 'Good response recorded' })).toHaveClass(
345
+ 'pf-chatbot__button--response-action-clicked'
346
+ );
347
+
348
+ await userEvent.click(screen.getByText('Test content'));
349
+
350
+ expect(screen.getByRole('button', { name: 'Good response recorded' })).toHaveClass(
351
+ 'pf-chatbot__button--response-action-clicked'
352
+ );
353
+ });
354
+
355
+ it('should switch selection to another button when persistActionSelection is true', async () => {
356
+ render(
357
+ <Message
358
+ name="Bot"
359
+ role="bot"
360
+ avatar=""
361
+ content="Test content"
362
+ actions={{
363
+ positive: {},
364
+ negative: {}
365
+ }}
366
+ persistActionSelection
367
+ />
368
+ );
369
+ const goodBtn = screen.getByRole('button', { name: 'Good response' });
370
+ const badBtn = screen.getByRole('button', { name: 'Bad response' });
371
+
372
+ await userEvent.click(goodBtn);
373
+ expect(goodBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
374
+
375
+ await userEvent.click(badBtn);
376
+ expect(badBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
377
+ expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
378
+ });
379
+
380
+ it('should toggle off when clicking the same button when persistActionSelection is true', async () => {
381
+ render(
382
+ <Message
383
+ name="Bot"
384
+ role="bot"
385
+ avatar=""
386
+ content="Test content"
387
+ actions={{
388
+ positive: {},
389
+ negative: {}
390
+ }}
391
+ persistActionSelection
392
+ />
393
+ );
394
+ const goodBtn = screen.getByRole('button', { name: 'Good response' });
395
+
396
+ await userEvent.click(goodBtn);
397
+ expect(goodBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
398
+
399
+ await userEvent.click(goodBtn);
400
+ expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
401
+ });
402
+
403
+ it('should work with custom actions when persistActionSelection is true', async () => {
404
+ const actions = {
405
+ positive: { 'data-testid': 'positive', onClick: jest.fn() },
406
+ negative: { 'data-testid': 'negative', onClick: jest.fn() },
407
+ custom: {
408
+ 'data-testid': 'custom',
409
+ onClick: jest.fn(),
410
+ ariaLabel: 'Custom',
411
+ tooltipContent: 'Custom action',
412
+ icon: <DownloadIcon />
413
+ }
414
+ };
415
+ render(<ResponseActions actions={actions} persistActionSelection />);
416
+
417
+ const customBtn = screen.getByTestId('custom');
418
+ await userEvent.click(customBtn);
419
+ expect(customBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
420
+
421
+ await userEvent.click(customBtn);
422
+ expect(customBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
423
+ });
325
424
  });
@@ -42,6 +42,12 @@ export interface ActionProps extends Omit<ButtonProps, 'ref'> {
42
42
  type ExtendedActionProps = ActionProps & {
43
43
  [key: string]: any;
44
44
  };
45
+
46
+ /**
47
+ * The various actions that can be attached to a bot message for users to interact with.
48
+ * Use this component when passing children to Message to customize its structure.
49
+ */
50
+
45
51
  export interface ResponseActionProps {
46
52
  /** Props for message actions, such as feedback (positive or negative), copy button, share, and listen */
47
53
  actions: Record<string, ExtendedActionProps | undefined> & {
@@ -53,11 +59,20 @@ export interface ResponseActionProps {
53
59
  listen?: ActionProps;
54
60
  edit?: ActionProps;
55
61
  };
62
+ /** When true, the selected action will persist even when clicking outside the component.
63
+ * When false (default), clicking outside or clicking another action will deselect the current selection. */
64
+ persistActionSelection?: boolean;
56
65
  }
57
66
 
58
- export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ actions }) => {
67
+ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({
68
+ actions,
69
+ persistActionSelection = false
70
+ }) => {
59
71
  const [activeButton, setActiveButton] = useState<string>();
60
72
  const [clickStatePersisted, setClickStatePersisted] = useState<boolean>(false);
73
+
74
+ const { positive, negative, copy, edit, share, download, listen, ...additionalActions } = actions;
75
+
61
76
  useEffect(() => {
62
77
  // Define the order of precedence for checking initial `isClicked`
63
78
  const actionPrecedence = ['positive', 'negative', 'copy', 'edit', 'share', 'download', 'listen'];
@@ -82,13 +97,21 @@ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ action
82
97
  // Click state is explicitly controlled by consumer.
83
98
  setClickStatePersisted(true);
84
99
  }
100
+ // If persistActionSelection is true, all selections are persisted
101
+ if (persistActionSelection) {
102
+ setClickStatePersisted(true);
103
+ }
85
104
  setActiveButton(initialActive);
86
- }, [actions]);
105
+ }, [actions, persistActionSelection]);
87
106
 
88
- const { positive, negative, copy, edit, share, download, listen, ...additionalActions } = actions;
89
107
  const responseActions = useRef<HTMLDivElement>(null);
90
108
 
91
109
  useEffect(() => {
110
+ // Only add click outside listener if not persisting selection
111
+ if (persistActionSelection) {
112
+ return;
113
+ }
114
+
92
115
  const handleClickOutside = (e) => {
93
116
  if (responseActions.current && !responseActions.current.contains(e.target) && !clickStatePersisted) {
94
117
  setActiveButton(undefined);
@@ -99,15 +122,26 @@ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ action
99
122
  return () => {
100
123
  window.removeEventListener('click', handleClickOutside);
101
124
  };
102
- }, [clickStatePersisted]);
125
+ }, [clickStatePersisted, persistActionSelection]);
103
126
 
104
127
  const handleClick = (
105
128
  e: MouseEvent | MouseEvent<Element, MouseEvent> | KeyboardEvent,
106
129
  id: string,
107
130
  onClick?: (event: MouseEvent | MouseEvent<Element, MouseEvent> | KeyboardEvent) => void
108
131
  ) => {
109
- setClickStatePersisted(false);
110
- setActiveButton(id);
132
+ if (persistActionSelection) {
133
+ if (activeButton === id) {
134
+ // Toggle off if clicking the same button
135
+ setActiveButton(undefined);
136
+ } else {
137
+ // Set new active button
138
+ setActiveButton(id);
139
+ }
140
+ setClickStatePersisted(true);
141
+ } else {
142
+ setClickStatePersisted(false);
143
+ setActiveButton(id);
144
+ }
111
145
  onClick && onClick(e);
112
146
  };
113
147
 
@@ -117,12 +151,12 @@ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ action
117
151
  <ResponseActionButton
118
152
  {...positive}
119
153
  ariaLabel={positive.ariaLabel ?? 'Good response'}
120
- clickedAriaLabel={positive.ariaLabel ?? 'Response recorded'}
154
+ clickedAriaLabel={positive.ariaLabel ?? 'Good response recorded'}
121
155
  onClick={(e) => handleClick(e, 'positive', positive.onClick)}
122
156
  className={positive.className}
123
157
  isDisabled={positive.isDisabled}
124
158
  tooltipContent={positive.tooltipContent ?? 'Good response'}
125
- clickedTooltipContent={positive.clickedTooltipContent ?? 'Response recorded'}
159
+ clickedTooltipContent={positive.clickedTooltipContent ?? 'Good response recorded'}
126
160
  tooltipProps={positive.tooltipProps}
127
161
  icon={<OutlinedThumbsUpIcon />}
128
162
  isClicked={activeButton === 'positive'}
@@ -135,12 +169,12 @@ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ action
135
169
  <ResponseActionButton
136
170
  {...negative}
137
171
  ariaLabel={negative.ariaLabel ?? 'Bad response'}
138
- clickedAriaLabel={negative.ariaLabel ?? 'Response recorded'}
172
+ clickedAriaLabel={negative.ariaLabel ?? 'Bad response recorded'}
139
173
  onClick={(e) => handleClick(e, 'negative', negative.onClick)}
140
174
  className={negative.className}
141
175
  isDisabled={negative.isDisabled}
142
176
  tooltipContent={negative.tooltipContent ?? 'Bad response'}
143
- clickedTooltipContent={negative.clickedTooltipContent ?? 'Response recorded'}
177
+ clickedTooltipContent={negative.clickedTooltipContent ?? 'Bad response recorded'}
144
178
  tooltipProps={negative.tooltipProps}
145
179
  icon={<OutlinedThumbsDownIcon />}
146
180
  isClicked={activeButton === 'negative'}
@@ -0,0 +1,23 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render, screen } from '@testing-library/react';
3
+ import ResponseActionsGroups from './ResponseActionsGroups';
4
+
5
+ test('Renders with children', () => {
6
+ render(<ResponseActionsGroups>Test content</ResponseActionsGroups>);
7
+ expect(screen.getByText('Test content')).toBeInTheDocument();
8
+ });
9
+
10
+ test('Renders with pf-chatbot__response-actions-groups class by default', () => {
11
+ render(<ResponseActionsGroups>Test content</ResponseActionsGroups>);
12
+ expect(screen.getByText('Test content')).toHaveClass('pf-chatbot__response-actions-groups', { exact: true });
13
+ });
14
+
15
+ test('Renders with custom className', () => {
16
+ render(<ResponseActionsGroups className="custom-class">Test content</ResponseActionsGroups>);
17
+ expect(screen.getByText('Test content')).toHaveClass('custom-class');
18
+ });
19
+
20
+ test('Spreads additional props', () => {
21
+ render(<ResponseActionsGroups id="test-id">Test content</ResponseActionsGroups>);
22
+ expect(screen.getByText('Test content')).toHaveAttribute('id', 'test-id');
23
+ });
@@ -0,0 +1,28 @@
1
+ // ============================================================================
2
+ // Response Actions Groups - Container for multiple action groups
3
+ // ============================================================================
4
+ import { FunctionComponent, HTMLProps, ReactNode } from 'react';
5
+ import { css } from '@patternfly/react-styles';
6
+
7
+ /**
8
+ * The container for grouping multiple related ResponseActions components, typically used for having different persistence states amongst groups.
9
+ * Use this component when passing children to Message to customize its structure.
10
+ */
11
+ export interface ResponseActionsGroupsProps extends HTMLProps<HTMLDivElement> {
12
+ /** Content to render inside the response actions groups container */
13
+ children: ReactNode;
14
+ /** Additional classes applied to the response actions groups container. */
15
+ className?: string;
16
+ }
17
+
18
+ export const ResponseActionsGroups: FunctionComponent<ResponseActionsGroupsProps> = ({
19
+ children,
20
+ className,
21
+ ...props
22
+ }) => (
23
+ <div className={css('pf-chatbot__response-actions-groups', className)} {...props}>
24
+ {children}
25
+ </div>
26
+ );
27
+
28
+ export default ResponseActionsGroups;
@@ -1,3 +1,4 @@
1
1
  export { default } from './ResponseActions';
2
2
 
3
3
  export * from './ResponseActions';
4
+ export * from './ResponseActionsGroups';
@@ -1,6 +1,6 @@
1
1
  .pf-chatbot__tool-call {
2
- --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--control--read-only);
3
2
  --pf-v6-c-card--BorderRadius: var(--pf-t--global--border--radius--small);
3
+ --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--default);
4
4
 
5
5
  overflow: unset;
6
6
  row-gap: var(--pf-t--global--spacer--sm);
@@ -181,4 +181,95 @@ describe('ToolCall', () => {
181
181
  render(<ToolCall {...defaultProps} cardFooterProps={{ id: 'card-footer-test-id' }} />);
182
182
  expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-footer-test-id')).toBeVisible();
183
183
  });
184
+
185
+ it('Renders collapsed by default when expandableContent is provided', () => {
186
+ render(<ToolCall {...defaultProps} expandableContent="Expandable Content" />);
187
+
188
+ expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'false');
189
+ expect(screen.queryByText('Expandable Content')).not.toBeVisible();
190
+ });
191
+
192
+ it('Renders expanded when isDefaultExpanded is true', () => {
193
+ render(<ToolCall {...defaultProps} isDefaultExpanded expandableContent="Expandable Content" />);
194
+
195
+ expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'true');
196
+ expect(screen.getByText('Expandable Content')).toBeVisible();
197
+ });
198
+
199
+ it('expandableSectionProps.isExpanded overrides isDefaultExpanded', () => {
200
+ render(
201
+ <ToolCall
202
+ {...defaultProps}
203
+ isDefaultExpanded={false}
204
+ expandableContent="Expandable Content"
205
+ expandableSectionProps={{ isExpanded: true }}
206
+ />
207
+ );
208
+
209
+ expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'true');
210
+ expect(screen.getByText('Expandable Content')).toBeVisible();
211
+ });
212
+
213
+ it('expandableSectionProps.onToggle overrides internal onToggle behavior', async () => {
214
+ const user = userEvent.setup();
215
+ const customOnToggle = jest.fn();
216
+
217
+ render(
218
+ <ToolCall
219
+ {...defaultProps}
220
+ isDefaultExpanded={false}
221
+ expandableContent="Expandable Content"
222
+ expandableSectionProps={{ onToggle: customOnToggle }}
223
+ />
224
+ );
225
+
226
+ const toggleButton = screen.getByRole('button', { name: defaultProps.titleText });
227
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
228
+
229
+ await user.click(toggleButton);
230
+
231
+ expect(customOnToggle).toHaveBeenCalledTimes(1);
232
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
233
+ expect(screen.queryByText('Expandable Content')).not.toBeVisible();
234
+ });
235
+
236
+ it('should render titleText as markdown when isTitleMarkdown is true', () => {
237
+ const titleText = '**Bold title**';
238
+ const { container } = render(<ToolCall titleText={titleText} isTitleMarkdown />);
239
+ expect(container.querySelector('strong')).toBeTruthy();
240
+ expect(screen.getByText('Bold title')).toBeTruthy();
241
+ });
242
+
243
+ it('should not render titleText as markdown when isTitleMarkdown is false', () => {
244
+ const titleText = '**Bold title**';
245
+ render(<ToolCall titleText={titleText} />);
246
+ expect(screen.getByText('**Bold title**')).toBeTruthy();
247
+ });
248
+
249
+ it('should render expandableContent as markdown when isExpandableContentMarkdown is true', async () => {
250
+ const user = userEvent.setup();
251
+ const expandableContent = '**Bold expandable content**';
252
+ const { container } = render(
253
+ <ToolCall {...defaultProps} expandableContent={expandableContent} isExpandableContentMarkdown />
254
+ );
255
+ await user.click(screen.getByRole('button', { name: defaultProps.titleText }));
256
+ expect(container.querySelector('strong')).toBeTruthy();
257
+ expect(screen.getByText('Bold expandable content')).toBeTruthy();
258
+ });
259
+
260
+ it('should not render expandableContent as markdown when isExpandableContentMarkdown is false', async () => {
261
+ const user = userEvent.setup();
262
+ const expandableContent = '**Bold expandable content**';
263
+ render(<ToolCall {...defaultProps} expandableContent={expandableContent} />);
264
+ await user.click(screen.getByRole('button', { name: defaultProps.titleText }));
265
+ expect(screen.getByText('**Bold expandable content**')).toBeTruthy();
266
+ });
267
+
268
+ it('should pass markdownContentProps to MarkdownContent component', () => {
269
+ const titleText = '**Bold title**';
270
+ const { container } = render(
271
+ <ToolCall titleText={titleText} isTitleMarkdown markdownContentProps={{ isPrimary: true }} />
272
+ );
273
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
274
+ });
184
275
  });
@@ -1,4 +1,4 @@
1
- import { type FunctionComponent } from 'react';
1
+ import { useState, type FunctionComponent } from 'react';
2
2
  import {
3
3
  ActionList,
4
4
  ActionListProps,
@@ -19,6 +19,8 @@ import {
19
19
  Spinner,
20
20
  SpinnerProps
21
21
  } from '@patternfly/react-core';
22
+ import MarkdownContent from '../MarkdownContent';
23
+ import type { MarkdownContentProps } from '../MarkdownContent';
22
24
 
23
25
  export interface ToolCallProps {
24
26
  /** Title text for the tool call. */
@@ -31,6 +33,8 @@ export interface ToolCallProps {
31
33
  spinnerProps?: SpinnerProps;
32
34
  /** Content to render within an expandable section. */
33
35
  expandableContent?: React.ReactNode;
36
+ /** Flag indicating whether the expandable content is expanded by default. */
37
+ isDefaultExpanded?: boolean;
34
38
  /** Text content for the "run" action button. */
35
39
  runButtonText?: string;
36
40
  /** Additional props for the "run" action button. */
@@ -59,6 +63,14 @@ export interface ToolCallProps {
59
63
  cardFooterProps?: CardFooterProps;
60
64
  /** Additional props for the expandable section when expandableContent is passed. */
61
65
  expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
66
+ /** Whether to enable markdown rendering for titleText. When true, titleText will be parsed as markdown. */
67
+ isTitleMarkdown?: boolean;
68
+ /** Whether to enable markdown rendering for expandableContent. When true and expandableContent is a string, it will be parsed as markdown. */
69
+ isExpandableContentMarkdown?: boolean;
70
+ /** Props passed to MarkdownContent component when markdown is enabled */
71
+ markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
72
+ /** Whether to retain styles in the MarkdownContent component. Defaults to false. */
73
+ shouldRetainStyles?: boolean;
62
74
  }
63
75
 
64
76
  export const ToolCall: FunctionComponent<ToolCallProps> = ({
@@ -66,6 +78,7 @@ export const ToolCall: FunctionComponent<ToolCallProps> = ({
66
78
  loadingText,
67
79
  isLoading,
68
80
  expandableContent,
81
+ isDefaultExpanded = false,
69
82
  runButtonText = 'Run tool',
70
83
  runButtonProps,
71
84
  runActionItemProps,
@@ -80,8 +93,25 @@ export const ToolCall: FunctionComponent<ToolCallProps> = ({
80
93
  cardBodyProps,
81
94
  cardFooterProps,
82
95
  expandableSectionProps,
83
- spinnerProps
96
+ spinnerProps,
97
+ isTitleMarkdown,
98
+ isExpandableContentMarkdown,
99
+ markdownContentProps,
100
+ shouldRetainStyles = false
84
101
  }: ToolCallProps) => {
102
+ const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
103
+
104
+ const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
105
+ setIsExpanded(isExpanded);
106
+ };
107
+
108
+ const renderTitle = () => {
109
+ if (isTitleMarkdown) {
110
+ return <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={titleText} {...markdownContentProps} />;
111
+ }
112
+ return titleText;
113
+ };
114
+
85
115
  const titleContent = (
86
116
  <span className={`pf-chatbot__tool-call-title-content`}>
87
117
  {isLoading ? (
@@ -90,10 +120,23 @@ export const ToolCall: FunctionComponent<ToolCallProps> = ({
90
120
  {<span className="pf-chatbot__tool-call-title-text">{loadingText}</span>}
91
121
  </>
92
122
  ) : (
93
- <span className="pf-chatbot__tool-call-title-text">{titleText}</span>
123
+ <span className="pf-chatbot__tool-call-title-text">{renderTitle()}</span>
94
124
  )}
95
125
  </span>
96
126
  );
127
+
128
+ const renderExpandableContent = () => {
129
+ if (isExpandableContentMarkdown && typeof expandableContent === 'string') {
130
+ return (
131
+ <MarkdownContent
132
+ shouldRetainStyles={shouldRetainStyles}
133
+ content={expandableContent}
134
+ {...markdownContentProps}
135
+ />
136
+ );
137
+ }
138
+ return expandableContent;
139
+ };
97
140
  const defaultActions = (
98
141
  <>
99
142
  <ActionListItem {...actionListItemProps} {...cancelActionItemProps}>
@@ -124,10 +167,12 @@ export const ToolCall: FunctionComponent<ToolCallProps> = ({
124
167
  <ExpandableSection
125
168
  className="pf-chatbot__tool-call-expandable-section"
126
169
  toggleContent={titleContent}
170
+ onToggle={onToggle}
171
+ isExpanded={isExpanded}
127
172
  isIndented
128
173
  {...expandableSectionProps}
129
174
  >
130
- {expandableContent}
175
+ {renderExpandableContent()}
131
176
  </ExpandableSection>
132
177
  ) : (
133
178
  titleContent
@@ -1,5 +1,5 @@
1
1
  .pf-chatbot__tool-response {
2
- --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--control--read-only);
2
+ --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--default);
3
3
  overflow: unset;
4
4
  }
5
5
 
@@ -25,12 +25,22 @@
25
25
  }
26
26
 
27
27
  .pf-chatbot__tool-response-card {
28
- --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--control--read-only);
28
+ --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--default);
29
29
  --pf-v6-c-card--first-child--PaddingBlockStart: var(--pf-t--global--spacer--sm);
30
30
  --pf-v6-c-card__title--not--last-child--PaddingBlockEnd: var(--pf-t--global--spacer--sm);
31
31
  --pf-v6-c-card--c-divider--child--PaddingBlockStart: var(--pf-t--global--spacer--sm);
32
32
 
33
33
  .pf-v6-c-divider {
34
- --pf-v6-c-divider--Color: var(--pf-t--global--border--color--control--read-only);
34
+ --pf-v6-c-divider--Color: var(--pf-t--global--border--color--default);
35
+ }
36
+ }
37
+
38
+ .pf-chatbot__tool-response-expandable-section .pf-v6-c-expandable-section__toggle .pf-m-markdown {
39
+ padding: inherit;
40
+ }
41
+
42
+ .pf-chatbot__tool-response {
43
+ .pf-chatbot__message-image {
44
+ max-width: 100%;
35
45
  }
36
46
  }