@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
@@ -8,15 +8,21 @@ import { useState, useRef, useEffect } from 'react';
8
8
  // Import PatternFly components
9
9
  import {
10
10
  ActionGroup,
11
+ ActionGroupProps,
11
12
  Button,
13
+ ButtonProps,
12
14
  Card,
13
15
  CardBody,
16
+ CardBodyProps,
14
17
  CardHeader,
18
+ CardHeaderProps,
15
19
  CardProps,
16
20
  Form,
21
+ FormProps,
17
22
  LabelGroupProps,
18
23
  OUIAProps,
19
- TextArea
24
+ TextArea,
25
+ TextAreaProps
20
26
  } from '@patternfly/react-core';
21
27
  import QuickResponse from '../QuickResponse/QuickResponse';
22
28
  import CloseButton from './CloseButton';
@@ -54,6 +60,20 @@ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProp
54
60
  focusOnLoad?: boolean;
55
61
  /** Timestamp passed in by Message for more context in aria announcements */
56
62
  timestamp?: string;
63
+ /** Additional props passed to submit button */
64
+ submitButtonProps?: ButtonProps;
65
+ /** Additional props passed to card header */
66
+ cardHeaderProps?: CardHeaderProps;
67
+ /** Additional props passed to card body */
68
+ cardBodyProps?: CardBodyProps;
69
+ /** Additional props passed to title heading */
70
+ headingLevelProps?: React.HTMLAttributes<HTMLHeadingElement>;
71
+ /** Additional props passed to form */
72
+ formProps?: FormProps;
73
+ /** Additional props passed to text area */
74
+ textAreaProps?: TextAreaProps;
75
+ /** Additional props passed to action group */
76
+ actionGroupProps?: ActionGroupProps;
57
77
  }
58
78
 
59
79
  const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
@@ -74,6 +94,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
74
94
  headingLevel: HeadingLevel = 'h1',
75
95
  focusOnLoad = true,
76
96
  isCompact,
97
+ children,
98
+ cardHeaderProps,
99
+ cardBodyProps,
100
+ headingLevelProps,
101
+ formProps,
102
+ textAreaProps,
103
+ actionGroupProps,
104
+ submitButtonProps,
77
105
  ...props
78
106
  }: UserFeedbackProps) => {
79
107
  const [selectedResponse, setSelectedResponse] = useState<string>();
@@ -94,11 +122,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
94
122
  actions={{
95
123
  actions: <CloseButton onClose={onClose} ariaLabel={closeButtonAriaLabel} />
96
124
  }}
125
+ {...cardHeaderProps}
97
126
  >
98
- <HeadingLevel className="pf-chatbot__feedback-card-title">{title}</HeadingLevel>
127
+ <HeadingLevel className="pf-chatbot__feedback-card-title" {...headingLevelProps}>
128
+ {title}
129
+ </HeadingLevel>
99
130
  </CardHeader>
100
- <CardBody>
101
- <Form className={`pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}`}>
131
+ <CardBody {...cardBodyProps}>
132
+ <Form className={`pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}`} {...formProps}>
102
133
  {quickResponses && (
103
134
  <QuickResponse
104
135
  quickResponses={quickResponses}
@@ -117,10 +148,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
117
148
  placeholder={textAreaPlaceholder}
118
149
  aria-label={textAreaAriaLabel}
119
150
  resizeOrientation="vertical"
151
+ {...textAreaProps}
120
152
  />
121
153
  )}
122
- <ActionGroup>
123
- <Button onClick={() => onSubmit(selectedResponse, value)}>{submitWord}</Button>
154
+ {children}
155
+ <ActionGroup {...actionGroupProps}>
156
+ <Button onClick={() => onSubmit(selectedResponse, value)} {...submitButtonProps}>
157
+ {submitWord}
158
+ </Button>
124
159
  </ActionGroup>
125
160
  </Form>
126
161
  </CardBody>
@@ -141,6 +141,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
141
141
  const [message, setMessage] = useState<string | number>(value ?? '');
142
142
  const [isListeningMessage, setIsListeningMessage] = useState<boolean>(false);
143
143
  const [hasSentMessage, setHasSentMessage] = useState(false);
144
+ const [isComposing, setIsComposing] = useState(false);
144
145
  const inputRef = useRef<HTMLTextAreaElement>(null);
145
146
  const textareaRef = (innerRef as React.RefObject<HTMLTextAreaElement>) ?? inputRef;
146
147
  const attachButtonRef = useRef<HTMLButtonElement>(null);
@@ -285,21 +286,38 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
285
286
 
286
287
  const handleKeyDown = useCallback(
287
288
  (event: ReactKeyboardEvent) => {
288
- if (event.key === 'Enter' && !event.shiftKey) {
289
+ // Japanese and other languages may use IME for character input.
290
+ // In these cases, enter is used to select the final input, so we need to check for composition end instead.
291
+ // See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/
292
+ // Chrome, Edge, and Firefox seem to work well with just the compose event.
293
+ // Safari is a little bit special. We need to handle 229 as well in this case.
294
+ const nativeEvent = event.nativeEvent as KeyboardEvent;
295
+ const isCompositionKey = nativeEvent.which === 229;
296
+ const isCurrentlyComposing = isComposing || isCompositionKey;
297
+
298
+ if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) {
289
299
  event.preventDefault();
290
300
  if (!isSendButtonDisabled && !hasStopButton) {
291
301
  handleSend(message);
292
302
  }
293
303
  }
294
- if (event.key === 'Enter' && event.shiftKey) {
304
+ if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) {
295
305
  if (textareaRef.current) {
296
306
  handleNewLine(textareaRef.current);
297
307
  }
298
308
  }
299
309
  },
300
- [isSendButtonDisabled, hasStopButton, handleSend, message]
310
+ [isSendButtonDisabled, hasStopButton, handleSend, message, isComposing]
301
311
  );
302
312
 
313
+ const handleCompositionStart = useCallback(() => {
314
+ setIsComposing(true);
315
+ }, []);
316
+
317
+ const handleCompositionEnd = useCallback(() => {
318
+ setIsComposing(false);
319
+ }, []);
320
+
303
321
  const handleAttachMenuToggle = () => {
304
322
  attachMenuProps?.setIsAttachMenuOpen && attachMenuProps?.setIsAttachMenuOpen(!attachMenuProps?.isAttachMenuOpen);
305
323
  attachMenuProps?.onAttachMenuToggleClick();
@@ -402,6 +420,8 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
402
420
  placeholder={isListeningMessage ? listeningText : placeholder}
403
421
  ref={textareaRef}
404
422
  onKeyDown={handleKeyDown}
423
+ onCompositionStart={handleCompositionStart}
424
+ onCompositionEnd={handleCompositionEnd}
405
425
  {...props}
406
426
  />
407
427
  </div>
@@ -6,20 +6,20 @@ import userEvent from '@testing-library/user-event';
6
6
  describe('JumpButton', () => {
7
7
  it('should render top button correctly', () => {
8
8
  render(<JumpButton position="top" onClick={jest.fn()} />);
9
- expect(screen.getByRole('button', { name: /Jump top/i })).toBeTruthy();
9
+ expect(screen.getByRole('button', { name: /Back to top/i })).toBeTruthy();
10
10
  });
11
11
  it('should render bottom button correctly', () => {
12
12
  render(<JumpButton position="bottom" onClick={jest.fn()} />);
13
- expect(screen.getByRole('button', { name: /Jump bottom/i })).toBeTruthy();
13
+ expect(screen.getByRole('button', { name: /Back to bottom/i })).toBeTruthy();
14
14
  });
15
15
  it('should call onClick appropriately', async () => {
16
16
  const spy = jest.fn();
17
17
  render(<JumpButton position="bottom" onClick={spy} />);
18
- await userEvent.click(screen.getByRole('button', { name: /Jump bottom/i }));
18
+ await userEvent.click(screen.getByRole('button', { name: /Back to bottom/i }));
19
19
  expect(spy).toHaveBeenCalledTimes(1);
20
20
  });
21
21
  it('should be hidden if isHidden prop is used', async () => {
22
22
  render(<JumpButton position="bottom" onClick={jest.fn()} isHidden />);
23
- expect(screen.queryByRole('button', { name: /Jump bottom/i })).toBeFalsy();
23
+ expect(screen.queryByRole('button', { name: /Back to bottom/i })).toBeFalsy();
24
24
  });
25
25
  });
@@ -4,7 +4,7 @@
4
4
  import type { FunctionComponent } from 'react';
5
5
 
6
6
  // Import PatternFly components
7
- import { Button, Tooltip, Icon } from '@patternfly/react-core';
7
+ import { Button, Tooltip, Icon, TooltipProps, ButtonProps } from '@patternfly/react-core';
8
8
 
9
9
  import { ArrowUpIcon } from '@patternfly/react-icons/dist/esm/icons/arrow-up-icon';
10
10
  import { ArrowDownIcon } from '@patternfly/react-icons/dist/esm/icons/arrow-down-icon';
@@ -16,16 +16,32 @@ export interface JumpButtonProps {
16
16
  onClick: () => void;
17
17
  /** Flag to change the visibilty of the button */
18
18
  isHidden?: boolean;
19
+ /** Additional props passed to jump buttons */
20
+ jumpButtonProps?: ButtonProps;
21
+ /** Additional props passed to tooltip */
22
+ jumpButtonTooltipProps?: TooltipProps;
19
23
  }
20
24
 
21
- const JumpButton: FunctionComponent<JumpButtonProps> = ({ position, isHidden, onClick }: JumpButtonProps) =>
25
+ const JumpButton: FunctionComponent<JumpButtonProps> = ({
26
+ position,
27
+ isHidden,
28
+ onClick,
29
+ jumpButtonProps,
30
+ jumpButtonTooltipProps
31
+ }: JumpButtonProps) =>
22
32
  isHidden ? null : (
23
- <Tooltip id={`pf-chatbot__tooltip--jump-${position}`} content={`Back to ${position}`} position="top">
33
+ <Tooltip
34
+ id={`pf-chatbot__tooltip--jump-${position}`}
35
+ content={`Back to ${position}`}
36
+ position="top"
37
+ {...jumpButtonTooltipProps}
38
+ >
24
39
  <Button
25
40
  variant="plain"
26
41
  className={`pf-chatbot__jump pf-chatbot__jump--${position}`}
27
- aria-label={`Jump ${position}`}
42
+ aria-label={`Back to ${position}`}
28
43
  onClick={onClick}
44
+ {...jumpButtonProps}
29
45
  >
30
46
  <Icon iconSize="lg" isInline>
31
47
  {position === 'top' ? <ArrowUpIcon /> : <ArrowDownIcon />}
@@ -23,18 +23,6 @@
23
23
  margin-top: auto !important;
24
24
  }
25
25
 
26
- // hide from view but not assistive technologies
27
- // https://css-tricks.com/inclusively-hidden/
28
- .pf-chatbot__messagebox-announcement {
29
- clip: rect(0 0 0 0);
30
- clip-path: inset(50%);
31
- height: 1px;
32
- overflow: hidden;
33
- position: absolute;
34
- white-space: nowrap;
35
- width: 1px;
36
- }
37
-
38
26
  @media screen and (min-width: 64rem) {
39
27
  .pf-chatbot--embedded,
40
28
  .pf-chatbot--drawer,
@@ -61,7 +61,7 @@ describe('MessageBox', () => {
61
61
  });
62
62
 
63
63
  await waitFor(() => {
64
- userEvent.click(screen.getByRole('button', { name: /Jump bottom/i }));
64
+ userEvent.click(screen.getByRole('button', { name: /Back to bottom/i }));
65
65
  expect(spy).toHaveBeenCalled();
66
66
  });
67
67
  });
@@ -85,7 +85,7 @@ describe('MessageBox', () => {
85
85
  region.dispatchEvent(new Event('scroll'));
86
86
  });
87
87
  await waitFor(() => {
88
- userEvent.click(screen.getByRole('button', { name: /Jump top/i }));
88
+ userEvent.click(screen.getByRole('button', { name: /Back to top/i }));
89
89
  expect(spy).toHaveBeenCalled();
90
90
  });
91
91
  });
@@ -18,6 +18,7 @@ import {
18
18
  WheelEventHandler
19
19
  } from 'react';
20
20
  import JumpButton from './JumpButton';
21
+ import { ButtonProps, TooltipProps } from '@patternfly/react-core';
21
22
 
22
23
  export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
23
24
  /** Content that can be announced, such as a new message, for screen readers */
@@ -38,6 +39,14 @@ export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
38
39
  onScrollToBottomClick?: () => void;
39
40
  /** Flag to enable automatic scrolling when new messages are added */
40
41
  enableSmartScroll?: boolean;
42
+ /** Props passed to top jump button */
43
+ jumpButtonTopProps?: ButtonProps;
44
+ /** Props passed to bottom jump button */
45
+ jumpButtonBottomProps?: ButtonProps;
46
+ /** Props passed to top jump button tooltip */
47
+ jumpButtonTopTooltipProps?: TooltipProps;
48
+ /** Props passed to top jump button tooltip */
49
+ jumpButtonBottomTooltipProps?: TooltipProps;
41
50
  }
42
51
 
43
52
  export interface MessageBoxHandle extends HTMLDivElement {
@@ -60,6 +69,10 @@ export const MessageBox = forwardRef(
60
69
  onScrollToTopClick,
61
70
  onScrollToBottomClick,
62
71
  enableSmartScroll = false,
72
+ jumpButtonTopProps,
73
+ jumpButtonBottomProps,
74
+ jumpButtonBottomTooltipProps,
75
+ jumpButtonTopTooltipProps,
63
76
  ...props
64
77
  }: MessageBoxProps,
65
78
  ref: ForwardedRef<MessageBoxHandle | null>
@@ -305,7 +318,13 @@ export const MessageBox = forwardRef(
305
318
 
306
319
  return (
307
320
  <>
308
- <JumpButton position="top" isHidden={isOverflowing && atTop} onClick={scrollToTop} />
321
+ <JumpButton
322
+ position="top"
323
+ isHidden={isOverflowing && atTop}
324
+ onClick={scrollToTop}
325
+ jumpButtonProps={jumpButtonTopProps}
326
+ jumpButtonTooltipProps={jumpButtonTopTooltipProps}
327
+ />
309
328
  <div
310
329
  role="region"
311
330
  tabIndex={0}
@@ -316,7 +335,7 @@ export const MessageBox = forwardRef(
316
335
  {...(enableSmartScroll ? { ...smartScrollHandlers } : {})}
317
336
  >
318
337
  {children}
319
- <div className="pf-chatbot__messagebox-announcement" aria-live="polite">
338
+ <div className="pf-chatbot__messagebox-announcement pf-chatbot-m-hidden" aria-live="polite">
320
339
  {announcement}
321
340
  </div>
322
341
  </div>
@@ -324,6 +343,8 @@ export const MessageBox = forwardRef(
324
343
  position="bottom"
325
344
  isHidden={isOverflowing && atBottom}
326
345
  onClick={() => scrollToBottom({ resumeSmartScroll: true })}
346
+ jumpButtonProps={jumpButtonBottomProps}
347
+ jumpButtonTooltipProps={jumpButtonBottomTooltipProps}
327
348
  />
328
349
  </>
329
350
  );
@@ -16,6 +16,17 @@
16
16
  box-shadow: var(--pf-t--global--box-shadow--sm);
17
17
  }
18
18
 
19
+ .pf-chatbot__compact-sources-card-body {
20
+ --pf-v6-c-card--child--PaddingBlockEnd: var(--pf-t--global--spacer--xs);
21
+ }
22
+
23
+ .pf-chatbot__sources-card-subtitle,
24
+ .pf-chatbot__sources-card-subtle {
25
+ color: var(--pf-t--global--text--color--subtle);
26
+ font-size: var(--pf-t--global--font--size--body--sm);
27
+ font-weight: var(--pf-t--global--font--weight--body--default);
28
+ }
29
+
19
30
  .pf-chatbot__sources-card-body-text {
20
31
  display: block;
21
32
  display: -webkit-box;
@@ -27,6 +38,12 @@
27
38
  text-overflow: ellipsis;
28
39
  }
29
40
 
41
+ .pf-chatbot__sources-card-title-container {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--pf-t--global--spacer--xs);
45
+ }
46
+
30
47
  .pf-chatbot__sources-card-footer-container {
31
48
  border-top: var(--pf-t--global--border--width--regular) solid var(--pf-t--global--border--color--default);
32
49
  padding: var(--pf-t--global--spacer--sm) var(--pf-t--global--spacer--md) var(--pf-t--global--spacer--sm)
@@ -256,4 +256,97 @@ describe('SourcesCard', () => {
256
256
  );
257
257
  expect(screen.getByRole('link', { name: /How to make an apple pie/i })).toHaveClass('test');
258
258
  });
259
+
260
+ it('should apply cardTitleProps appropriately', () => {
261
+ render(
262
+ <SourcesCard
263
+ cardTitleProps={{ 'data-testid': 'card-title', className: 'test' } as any}
264
+ sources={[{ title: 'How to make an apple pie', link: '' }]}
265
+ />
266
+ );
267
+ expect(screen.getByTestId('card-title')).toHaveClass('test');
268
+ });
269
+
270
+ it('should apply cardBodyProps appropriately', () => {
271
+ render(
272
+ <SourcesCard
273
+ cardBodyProps={
274
+ { 'data-testid': 'card-body', body: 'To make an apple pie, you must first...', className: 'test' } as any
275
+ }
276
+ sources={[{ title: 'How to make an apple pie', link: '', body: 'To make an apple pie, you must first...' }]}
277
+ />
278
+ );
279
+ expect(screen.getByTestId('card-body')).toHaveClass('test');
280
+ });
281
+
282
+ it('should apply cardFooterProps appropriately', () => {
283
+ render(
284
+ <SourcesCard
285
+ cardFooterProps={{ 'data-testid': 'card-footer', className: 'test' } as any}
286
+ sources={[
287
+ { title: 'How to make an apple pie', link: '' },
288
+ { title: 'How to make cookies', link: '' }
289
+ ]}
290
+ />
291
+ );
292
+ expect(screen.getByTestId('card-footer')).toHaveClass('test');
293
+ });
294
+
295
+ it('should apply truncateProps appropriately', () => {
296
+ render(
297
+ <SourcesCard
298
+ sources={[
299
+ {
300
+ title: 'How to make an apple pie',
301
+ link: '',
302
+ truncateProps: { 'data-testid': 'card-truncate', className: 'test' } as any
303
+ }
304
+ ]}
305
+ />
306
+ );
307
+ expect(screen.getByTestId('card-truncate')).toHaveClass('test');
308
+ });
309
+
310
+ it('should apply custom footer appropriately when there is one source', () => {
311
+ render(
312
+ <SourcesCard sources={[{ title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> }]} />
313
+ );
314
+ expect(screen.getByText('I am a custom footer'));
315
+ expect(screen.queryByText('1/1')).toBeFalsy();
316
+ });
317
+
318
+ it('should apply custom footer appropriately when are multiple sources', () => {
319
+ render(
320
+ <SourcesCard
321
+ sources={[
322
+ { title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> },
323
+ { title: 'How to bake bread', link: '' }
324
+ ]}
325
+ />
326
+ );
327
+ expect(screen.getByText('I am a custom footer'));
328
+ // does not show navigation bar
329
+ expect(screen.queryByText('1/2')).toBeFalsy();
330
+ });
331
+
332
+ it('should apply footer props to custom footer appropriately', () => {
333
+ render(
334
+ <SourcesCard
335
+ cardFooterProps={{ 'data-testid': 'card-footer', className: 'test' } as any}
336
+ sources={[{ title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> }]}
337
+ />
338
+ );
339
+ expect(screen.getByText('I am a custom footer'));
340
+ expect(screen.getByTestId('card-footer')).toHaveClass('test');
341
+ });
342
+
343
+ it('should apply subtitle appropriately', () => {
344
+ render(
345
+ <SourcesCard
346
+ sources={[{ title: 'How to make an apple pie', link: '', subtitle: 'You must first create the universe' }]}
347
+ />
348
+ );
349
+ expect(screen.getByText('How to make an apple pie'));
350
+ expect(screen.getByText('You must first create the universe'));
351
+ });
259
352
  });