@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
@@ -2,12 +2,12 @@
2
2
  // Chatbot Header - Chatbot Conversation History Nav
3
3
  // ============================================================================
4
4
  import type { KeyboardEvent, FunctionComponent } from 'react';
5
-
6
5
  import { useRef, Fragment } from 'react';
7
6
 
8
7
  // Import PatternFly components
9
8
  import {
10
9
  Button,
10
+ ButtonProps,
11
11
  Drawer,
12
12
  DrawerPanelContent,
13
13
  DrawerContent,
@@ -18,13 +18,7 @@ import {
18
18
  DrawerCloseButton,
19
19
  DrawerContentBody,
20
20
  SearchInput,
21
- Menu,
22
- MenuList,
23
- MenuGroup,
24
- MenuItem,
25
- MenuContent,
26
- MenuItemProps,
27
- MenuProps,
21
+ Title,
28
22
  DrawerPanelContentProps,
29
23
  DrawerContentProps,
30
24
  DrawerContentBodyProps,
@@ -33,12 +27,22 @@ import {
33
27
  DrawerCloseButtonProps,
34
28
  DrawerPanelBodyProps,
35
29
  SkeletonProps,
36
- Title,
37
30
  Icon,
38
- ButtonProps
31
+ MenuProps,
32
+ TitleProps,
33
+ MenuListProps,
34
+ SearchInputProps,
35
+ MenuList,
36
+ MenuGroup,
37
+ MenuItem,
38
+ Menu,
39
+ MenuContent,
40
+ MenuItemProps,
41
+ MenuGroupProps,
42
+ MenuContentProps
39
43
  } from '@patternfly/react-core';
40
44
 
41
- import { OutlinedClockIcon, OutlinedCommentAltIcon } from '@patternfly/react-icons';
45
+ import { OutlinedClockIcon, OutlinedCommentAltIcon, PenToSquareIcon } from '@patternfly/react-icons';
42
46
  import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
43
47
  import ConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
44
48
  import LoadingState from './LoadingState';
@@ -61,8 +65,10 @@ export interface Conversation {
61
65
  label?: string;
62
66
  /** Callback for when user selects item. */
63
67
  onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
64
- /** Additional props passed to conversation menu item */
68
+ /** Additional props passed to menu item */
65
69
  additionalProps?: MenuItemProps;
70
+ /** Custom dropdown ID to ensure uniqueness across demo instances */
71
+ dropdownId?: string;
66
72
  }
67
73
  export interface ChatbotConversationHistoryNavProps extends DrawerProps {
68
74
  /** Function called to toggle drawer */
@@ -79,6 +85,10 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
79
85
  conversations: Conversation[] | { [key: string]: Conversation[] };
80
86
  /** Additional button props for new chat button. */
81
87
  newChatButtonProps?: ButtonProps;
88
+ /** Additional props applied to conversation menu group. If conversations is an object, you should pass an object of MenuGroupProps for each group. */
89
+ menuGroupProps?: MenuGroupProps | { [key: string]: MenuGroupProps };
90
+ /** Additional props applied to conversation list. If conversations is an object, you should pass an object of MenuListProps for each group. */
91
+ menuListProps?: Omit<MenuListProps, 'children'> | { [key: string]: Omit<MenuListProps, 'children'> };
82
92
  /** Text shown in blue button */
83
93
  newChatButtonText?: string;
84
94
  /** Callback function for when blue button is clicked. Omit to hide blue "new chat button" */
@@ -89,6 +99,8 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
89
99
  searchInputPlaceholder?: string;
90
100
  /** Aria label for search input */
91
101
  searchInputAriaLabel?: string;
102
+ /** Additional props passed to search input */
103
+ searchInputProps?: SearchInputProps;
92
104
  /** A callback for when the input value changes. Omit to hide input field */
93
105
  handleTextInputChange?: (value: string) => void;
94
106
  /** Display mode of chatbot */
@@ -127,6 +139,14 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
127
139
  isCompact?: boolean;
128
140
  /** Display title */
129
141
  title?: string;
142
+ /** Icon displayed in title */
143
+ navTitleIcon?: React.ReactNode;
144
+ /** Title header level */
145
+ navTitleProps?: Partial<TitleProps>;
146
+ /** Visually hidden text that gets announced by assistive technologies. Should be used to convey the result count when the search input value changes. */
147
+ searchInputScreenReaderText?: string;
148
+ /** Additional props passed to MenuContent */
149
+ menuContentProps?: Omit<MenuContentProps, 'ref'>;
130
150
  }
131
151
 
132
152
  export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversationHistoryNavProps> = ({
@@ -136,17 +156,18 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
136
156
  activeItemId,
137
157
  onSelectActiveItem,
138
158
  conversations,
159
+ menuListProps,
139
160
  newChatButtonText = 'New chat',
140
161
  drawerContent,
141
162
  onNewChat,
142
163
  newChatButtonProps,
143
164
  searchInputPlaceholder = 'Search previous conversations...',
144
- searchInputAriaLabel = 'Filter menu items',
165
+ searchInputAriaLabel = 'Search previous conversations',
166
+ searchInputProps,
145
167
  handleTextInputChange,
146
168
  displayMode,
147
169
  reverseButtonOrder = false,
148
170
  drawerActionsTestId = 'chatbot-nav-drawer-actions',
149
- menuProps,
150
171
  drawerPanelContentProps,
151
172
  drawerContentProps,
152
173
  drawerContentBodyProps,
@@ -161,6 +182,12 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
161
182
  noResultsState,
162
183
  isCompact,
163
184
  title = 'Chat history',
185
+ navTitleProps,
186
+ navTitleIcon = <OutlinedClockIcon />,
187
+ searchInputScreenReaderText,
188
+ menuProps,
189
+ menuGroupProps,
190
+ menuContentProps,
164
191
  ...props
165
192
  }: ChatbotConversationHistoryNavProps) => {
166
193
  const drawerRef = useRef<HTMLDivElement>(null);
@@ -169,11 +196,13 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
169
196
  drawerRef.current && drawerRef.current.focus();
170
197
  };
171
198
 
199
+ const isConversation = (item: any): item is Conversation =>
200
+ item && typeof item === 'object' && 'id' in item && 'text' in item;
201
+
172
202
  const getNavItem = (conversation: Conversation) => (
173
203
  <MenuItem
174
204
  className={`pf-chatbot__menu-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__menu-item--active' : ''}`}
175
205
  itemId={conversation.id}
176
- key={conversation.id}
177
206
  {...(conversation.noIcon ? {} : { icon: conversation.icon ?? <OutlinedCommentAltIcon /> })}
178
207
  /* eslint-disable indent */
179
208
  {...(conversation.menuItems
@@ -189,30 +218,37 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
189
218
  }
190
219
  : {})}
191
220
  {...conversation.additionalProps}
192
- /* eslint-enable indent */
193
221
  >
194
222
  {conversation.text}
195
223
  </MenuItem>
196
224
  );
197
225
 
198
- const buildMenu = () => {
226
+ const buildConversations = () => {
199
227
  if (Array.isArray(conversations)) {
200
- // Render for array of MenuItemObject
201
228
  return (
202
- <MenuList>
203
- {conversations.map((conversation) => (
204
- <Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
205
- ))}
229
+ <MenuList {...menuListProps}>
230
+ {conversations.map((conversation) => {
231
+ if (isConversation(conversation)) {
232
+ return <Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>;
233
+ } else {
234
+ return conversation;
235
+ }
236
+ })}
206
237
  </MenuList>
207
238
  );
208
239
  } else {
209
- // Render for object with NavItemObject arrays as values
210
240
  return (
211
241
  <>
212
242
  {Object.keys(conversations).map((navGroup) => (
213
- <MenuGroup className="pf-chatbot__menu-item-header" label={navGroup} key={navGroup}>
214
- <MenuList>
215
- {conversations[navGroup].map((conversation) => (
243
+ <MenuGroup
244
+ className="pf-chatbot__menu-item-header"
245
+ label={navGroup}
246
+ key={navGroup}
247
+ labelHeadingLevel="h3"
248
+ {...menuGroupProps?.[navGroup]}
249
+ >
250
+ <MenuList {...menuListProps?.[navGroup]}>
251
+ {conversations[navGroup].map((conversation: Conversation) => (
216
252
  <Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
217
253
  ))}
218
254
  </MenuList>
@@ -240,7 +276,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
240
276
  }
241
277
  return (
242
278
  <Menu isPlain onSelect={onSelectActiveItem} activeItemId={activeItemId} {...menuProps}>
243
- <MenuContent>{buildMenu()}</MenuContent>
279
+ <MenuContent {...menuContentProps}>{buildConversations()}</MenuContent>
244
280
  </Menu>
245
281
  );
246
282
  };
@@ -262,26 +298,37 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
262
298
  >
263
299
  <DrawerCloseButton onClick={onDrawerToggle} {...drawerCloseButtonProps} />
264
300
  {onNewChat && (
265
- <Button size={isCompact ? 'sm' : undefined} onClick={onNewChat} {...newChatButtonProps}>
301
+ <Button
302
+ size={isCompact ? 'sm' : undefined}
303
+ onClick={onNewChat}
304
+ icon={<PenToSquareIcon />}
305
+ {...newChatButtonProps}
306
+ >
266
307
  {newChatButtonText}
267
308
  </Button>
268
309
  )}
269
310
  </DrawerActions>
270
311
  </DrawerHead>
271
- <div className="pf-chatbot__title-container">
272
- <Title headingLevel="h3">
312
+ <div className="pf-chatbot__heading-container">
313
+ <div className="pf-chatbot__title-container">
273
314
  <Icon size="lg" className="pf-chatbot__title-icon">
274
- <OutlinedClockIcon />
315
+ {navTitleIcon}
275
316
  </Icon>
276
- {title}
277
- </Title>
317
+ <Title className="pf-chatbot__title" headingLevel="h2" {...navTitleProps}>
318
+ {title}
319
+ </Title>
320
+ </div>
278
321
  {!isLoading && handleTextInputChange && (
279
322
  <div className="pf-chatbot__input">
280
323
  <SearchInput
281
324
  aria-label={searchInputAriaLabel}
282
325
  onChange={(_event, value) => handleTextInputChange(value)}
283
326
  placeholder={searchInputPlaceholder}
327
+ {...searchInputProps}
284
328
  />
329
+ {searchInputScreenReaderText && (
330
+ <div className="pf-chatbot__filter-announcement pf-chatbot-m-hidden">{searchInputScreenReaderText}</div>
331
+ )}
285
332
  </div>
286
333
  )}
287
334
  </div>
@@ -12,7 +12,7 @@ describe('ChatbotHeaderMenu', () => {
12
12
  it('should call onMenuToggle when ChatbotHeaderMenu button is clicked', () => {
13
13
  const onMenuToggle = jest.fn();
14
14
  render(<ChatbotHeaderMenu className="custom-header-menu" onMenuToggle={onMenuToggle} />);
15
- fireEvent.click(screen.getByRole('button', { name: 'Toggle menu' }));
15
+ fireEvent.click(screen.getByRole('button', { name: 'Chat history menu' }));
16
16
 
17
17
  expect(onMenuToggle).toHaveBeenCalled();
18
18
  });
@@ -25,9 +25,9 @@ const ChatbotHeaderMenuBase: FunctionComponent<ChatbotHeaderMenuProps> = ({
25
25
  className,
26
26
  onMenuToggle,
27
27
  tooltipProps,
28
- menuAriaLabel = 'Toggle menu',
28
+ menuAriaLabel = 'Chat history menu',
29
29
  innerRef,
30
- tooltipContent = 'Menu',
30
+ tooltipContent = 'Chat history menu',
31
31
  isCompact,
32
32
  ...props
33
33
  }: ChatbotHeaderMenuProps) => (
@@ -0,0 +1,25 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { ChatbotHeaderNewChatButton } from './ChatbotHeaderNewChatButton';
3
+ import '@testing-library/jest-dom';
4
+
5
+ describe('ChatbotHeaderNewChatButton', () => {
6
+ it('should render ChatbotHeaderNewChatButton', () => {
7
+ const { container } = render(
8
+ <ChatbotHeaderNewChatButton className="custom-header-new-chat-button" onClick={jest.fn()} />
9
+ );
10
+
11
+ expect(container.querySelector('.custom-header-new-chat-button')).toBeTruthy();
12
+ });
13
+
14
+ it('should call onClick handler when new chat button is pressed', () => {
15
+ const onClick = jest.fn();
16
+ render(<ChatbotHeaderNewChatButton className="custom-header-new-chat-button" onClick={onClick} />);
17
+ fireEvent.click(screen.getByRole('button', { name: 'New chat' }));
18
+ expect(onClick).toHaveBeenCalled();
19
+ });
20
+
21
+ it('should render button with isCompact', () => {
22
+ render(<ChatbotHeaderNewChatButton data-testid="new-chat-button" onClick={jest.fn()} isCompact />);
23
+ expect(screen.getByTestId('new-chat-button')).toHaveClass('pf-m-compact');
24
+ });
25
+ });
@@ -0,0 +1,64 @@
1
+ import type { Ref, FunctionComponent } from 'react';
2
+ import { forwardRef } from 'react';
3
+
4
+ import { Button, ButtonProps, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
5
+ import { PenToSquareIcon } from '@patternfly/react-icons/dist/esm/icons/pen-to-square-icon';
6
+
7
+ export interface ChatbotHeaderNewChatButtonProps extends ButtonProps {
8
+ /** Callback function for when button is clicked */
9
+ onClick: () => void;
10
+ /** Custom classname for the header component */
11
+ className?: string;
12
+ /** Props spread to the PF Tooltip component wrapping the display mode dropdown */
13
+ tooltipProps?: TooltipProps;
14
+ /** Aria label for menu */
15
+ menuAriaLabel?: string;
16
+ /** Ref applied to menu */
17
+ innerRef?: React.Ref<HTMLButtonElement>;
18
+ /** Content used in tooltip */
19
+ tooltipContent?: string;
20
+ /** Sets button to compact styling. */
21
+ isCompact?: boolean;
22
+ }
23
+
24
+ const ChatbotHeaderNewChatButtonBase: FunctionComponent<ChatbotHeaderNewChatButtonProps> = ({
25
+ className,
26
+ onClick,
27
+ tooltipProps,
28
+ menuAriaLabel = 'New chat',
29
+ innerRef,
30
+ tooltipContent = 'New chat',
31
+ isCompact,
32
+ ...props
33
+ }: ChatbotHeaderNewChatButtonProps) => (
34
+ <div className={`pf-chatbot__menu${className ? ` ${className}` : ''}`}>
35
+ <Tooltip
36
+ content={tooltipContent}
37
+ position="bottom"
38
+ // prevents VO announcements of both aria label and tooltip
39
+ aria="none"
40
+ {...tooltipProps}
41
+ >
42
+ <Button
43
+ className={`pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`}
44
+ variant="plain"
45
+ onClick={onClick}
46
+ aria-label={menuAriaLabel}
47
+ ref={innerRef}
48
+ icon={
49
+ <Icon size={isCompact ? 'lg' : 'xl'} isInline>
50
+ <PenToSquareIcon />
51
+ </Icon>
52
+ }
53
+ size={isCompact ? 'sm' : undefined}
54
+ {...props}
55
+ />
56
+ </Tooltip>
57
+ </div>
58
+ );
59
+
60
+ export const ChatbotHeaderNewChatButton = forwardRef(
61
+ (props: ChatbotHeaderNewChatButtonProps, ref: Ref<HTMLButtonElement>) => (
62
+ <ChatbotHeaderNewChatButtonBase innerRef={ref} {...props} />
63
+ )
64
+ );
@@ -8,3 +8,4 @@ export * from './ChatbotHeaderTitle';
8
8
  export * from './ChatbotHeaderOptionsDropdown';
9
9
  export * from './ChatbotHeaderSelectorDropdown';
10
10
  export * from './ChatbotHeaderCloseButton';
11
+ export * from './ChatbotHeaderNewChatButton';
@@ -20,7 +20,7 @@
20
20
  padding-block-end: var(--pf-t--global--spacer--xl);
21
21
  }
22
22
  .pf-v6-c-modal-box__header {
23
- padding-block-end: var(--pf-t--global--spacer--lg);
23
+ padding-block-end: var(--pf-t--global--spacer--sm);
24
24
  }
25
25
  }
26
26
 
@@ -0,0 +1,24 @@
1
+ .pf-chatbot__deep-thinking {
2
+ --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--control--read-only);
3
+ overflow: unset;
4
+ }
5
+
6
+ .pf-chatbot__deep-thinking-expandable-section {
7
+ --pf-v6-c-expandable-section--Gap: var(--pf-t--global--spacer--xs);
8
+ }
9
+
10
+ .pf-chatbot__deep-thinking-section {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--pf-t--global--spacer--xs);
14
+ }
15
+
16
+ .pf-chatbot__deep-thinking-subheading {
17
+ font-size: var(--pf-t--global--font--size--body--sm);
18
+ font-weight: var(--pf-t--global--font--weight--body--default);
19
+ color: var(--pf-t--global--text--color--subtle);
20
+ }
21
+
22
+ .pf-chatbot__deep-thinking-body {
23
+ color: var(--pf-t--global--text--color--subtle);
24
+ }
@@ -0,0 +1,61 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import '@testing-library/jest-dom';
3
+ import DeepThinking from './DeepThinking';
4
+
5
+ describe('DeepThinking', () => {
6
+ const defaultProps = {
7
+ toggleContent: 'Show thinking'
8
+ };
9
+
10
+ it('should render with required props only', () => {
11
+ render(<DeepThinking {...defaultProps} />);
12
+ expect(screen.getByText('Show thinking')).toBeTruthy();
13
+ });
14
+
15
+ it('should render subheading when provided', () => {
16
+ const subheading = 'Thought for 3 seconds';
17
+ render(<DeepThinking {...defaultProps} subheading={subheading} />);
18
+ expect(screen.getByText(subheading)).toBeTruthy();
19
+ });
20
+
21
+ it('should render body content when provided', () => {
22
+ const body = "Here's why I think that";
23
+ render(<DeepThinking {...defaultProps} body={body} />);
24
+ expect(screen.getByText(body)).toBeTruthy();
25
+ });
26
+
27
+ it('should render with complex content including React elements', () => {
28
+ const body = (
29
+ <div>
30
+ <p>Complex body content</p>
31
+ <ul>
32
+ <li>Item 1</li>
33
+ <li>Item 2</li>
34
+ </ul>
35
+ </div>
36
+ );
37
+
38
+ render(<DeepThinking {...defaultProps} body={body} />);
39
+ expect(screen.getByText('Complex body content')).toBeTruthy();
40
+ expect(screen.getByText('Item 1')).toBeTruthy();
41
+ expect(screen.getByText('Item 2')).toBeTruthy();
42
+ });
43
+
44
+ it('should apply custom className from cardProps', () => {
45
+ const { container } = render(
46
+ <DeepThinking {...defaultProps} cardProps={{ className: 'custom-tool-response-class' }} />
47
+ );
48
+ expect(container.querySelector('.custom-tool-response-class')).toBeTruthy();
49
+ });
50
+
51
+ it('should pass through expandableSectionProps', () => {
52
+ render(<DeepThinking {...defaultProps} expandableSectionProps={{ className: 'custom-expandable-class' }} />);
53
+ expect(document.querySelector('.custom-expandable-class')).toBeTruthy();
54
+ });
55
+
56
+ it('should not render subheading span when subheading is not provided', () => {
57
+ const { container } = render(<DeepThinking {...defaultProps} />);
58
+ const subheadingContainer = container.querySelector('.pf-chatbot__tool-response-subheading');
59
+ expect(subheadingContainer).toBeFalsy();
60
+ });
61
+ });
@@ -0,0 +1,68 @@
1
+ // ============================================================================
2
+ // Deep Thinking
3
+ // ============================================================================
4
+ import {
5
+ Card,
6
+ CardBody,
7
+ CardBodyProps,
8
+ CardProps,
9
+ ExpandableSection,
10
+ ExpandableSectionProps
11
+ } from '@patternfly/react-core';
12
+ import { useState, type FunctionComponent } from 'react';
13
+
14
+ export interface DeepThinkingProps {
15
+ /** Toggle content shown for expandable section */
16
+ toggleContent: React.ReactNode;
17
+ /** Additional props passed to expandable section */
18
+ expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
19
+ /** Subheading rendered inside expandable section */
20
+ subheading?: string;
21
+ /** Body text rendered inside expandable section */
22
+ body?: React.ReactNode | string;
23
+ /** Additional props passed to main card */
24
+ cardProps?: CardProps;
25
+ /** Additional props passed to main card body */
26
+ cardBodyProps?: CardBodyProps;
27
+ }
28
+
29
+ export const DeepThinking: FunctionComponent<DeepThinkingProps> = ({
30
+ body,
31
+ cardProps,
32
+ expandableSectionProps,
33
+ subheading,
34
+ toggleContent,
35
+ cardBodyProps
36
+ }: DeepThinkingProps) => {
37
+ const [isExpanded, setIsExpanded] = useState(true);
38
+
39
+ const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
40
+ setIsExpanded(isExpanded);
41
+ };
42
+
43
+ return (
44
+ <Card isCompact className="pf-chatbot__deep-thinking" {...cardProps}>
45
+ <CardBody {...cardBodyProps}>
46
+ <ExpandableSection
47
+ toggleContent={toggleContent}
48
+ onToggle={onToggle}
49
+ isExpanded={isExpanded}
50
+ isIndented
51
+ className="pf-chatbot__deep-thinking-expandable-section"
52
+ {...expandableSectionProps}
53
+ >
54
+ <div className="pf-chatbot__deep-thinking-section">
55
+ {subheading && (
56
+ <div className="pf-chatbot__deep-thinking-subheading">
57
+ <span>{subheading}</span>
58
+ </div>
59
+ )}
60
+ {body && <div className="pf-chatbot__deep-thinking-body">{body}</div>}
61
+ </div>
62
+ </ExpandableSection>
63
+ </CardBody>
64
+ </Card>
65
+ );
66
+ };
67
+
68
+ export default DeepThinking;
@@ -0,0 +1,3 @@
1
+ export { default } from './DeepThinking';
2
+
3
+ export * from './DeepThinking';
@@ -11,10 +11,20 @@
11
11
  height: 24px;
12
12
  }
13
13
 
14
+ .pf-chatbot__image-icon {
15
+ color: var(--pf-t--global--icon--color--status--info--default);
16
+ width: 24px;
17
+ height: 24px;
18
+ }
19
+
14
20
  .pf-chatbot__code-fileName {
15
21
  font-size: var(--pf-t--global--font--size--body--default);
16
22
  }
17
23
 
24
+ .pf-chatbot__code-file-size {
25
+ color: var(--pf-t--global--text--color--subtle);
26
+ }
27
+
18
28
  // This is used in demos only
19
29
  .pf-chatbot__file-details-example {
20
30
  background: var(--pf-t--global--background--color--secondary--default);
@@ -11,6 +11,7 @@ describe('FileDetails', () => {
11
11
  it('should render file details correctly if an extension we support is passed in', () => {
12
12
  render(<FileDetails fileName="test.txt" languageTestId="language" />);
13
13
  expect(screen.getByText('test')).toBeTruthy();
14
+ expect(screen.queryByText('test.txt')).toBeFalsy();
14
15
  expect(screen.getByText('TEXT')).toBeTruthy();
15
16
  expect(screen.getByTestId('language')).toBeTruthy();
16
17
  });
@@ -19,4 +20,19 @@ describe('FileDetails', () => {
19
20
  expect(screen.getByText('test')).toBeTruthy();
20
21
  expect(screen.queryByTestId('language')).toBeFalsy();
21
22
  });
23
+ it('should support image formats by rendering extension differently', () => {
24
+ render(<FileDetails fileName="test.svg" languageTestId="language" />);
25
+ expect(screen.getByText('test')).toBeTruthy();
26
+ expect(screen.queryByText('test.svg')).toBeFalsy();
27
+ expect(screen.queryByTestId('language')).toBeFalsy();
28
+ });
29
+ it('should handle truncation differently', () => {
30
+ render(<FileDetails fileName="test.svg" languageTestId="language" hasTruncation={false} />);
31
+ expect(screen.getByText('test.svg')).toBeTruthy();
32
+ expect(screen.queryByTestId('language')).toBeFalsy();
33
+ });
34
+ it('should include file size if prop passed in', () => {
35
+ render(<FileDetails fileName="test.joke" languageTestId="language" fileSize="100MB" />);
36
+ expect(screen.getByText('100MB')).toBeTruthy();
37
+ });
22
38
  });