@patternfly/chatbot 6.3.1 → 6.4.0-prerelease.10

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 (135) hide show
  1. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
  2. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
  4. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +27 -4
  5. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +8 -14
  6. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +53 -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/FileDropZone/FileDropZone.d.ts +1 -2
  16. package/dist/cjs/Message/Message.d.ts +9 -2
  17. package/dist/cjs/Message/Message.js +40 -34
  18. package/dist/cjs/Message/Message.test.js +37 -0
  19. package/dist/cjs/Message/MessageInput.d.ts +3 -1
  20. package/dist/cjs/Message/MessageInput.js +2 -2
  21. package/dist/cjs/MessageBar/AttachButton.d.ts +2 -2
  22. package/dist/cjs/MessageBar/MessageBar.d.ts +2 -2
  23. package/dist/cjs/MessageBar/MessageBar.js +19 -4
  24. package/dist/cjs/MessageBox/JumpButton.d.ts +5 -0
  25. package/dist/cjs/MessageBox/JumpButton.js +1 -1
  26. package/dist/cjs/MessageBox/JumpButton.test.js +4 -4
  27. package/dist/cjs/MessageBox/MessageBox.d.ts +9 -0
  28. package/dist/cjs/MessageBox/MessageBox.js +2 -2
  29. package/dist/cjs/MessageBox/MessageBox.test.js +2 -2
  30. package/dist/cjs/MessageDivider/MessageDivider.d.ts +9 -0
  31. package/dist/cjs/MessageDivider/MessageDivider.js +23 -0
  32. package/dist/cjs/MessageDivider/MessageDivider.test.d.ts +1 -0
  33. package/dist/cjs/MessageDivider/MessageDivider.test.js +29 -0
  34. package/dist/cjs/MessageDivider/index.d.ts +2 -0
  35. package/dist/cjs/MessageDivider/index.js +23 -0
  36. package/dist/cjs/ResponseActions/ResponseActions.d.ts +1 -0
  37. package/dist/cjs/ResponseActions/ResponseActions.js +4 -4
  38. package/dist/cjs/ResponseActions/ResponseActions.test.js +6 -1
  39. package/dist/cjs/index.d.ts +2 -0
  40. package/dist/cjs/index.js +4 -1
  41. package/dist/css/main.css +103 -81
  42. package/dist/css/main.css.map +1 -1
  43. package/dist/dynamic/MessageDivider/package.json +1 -0
  44. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
  45. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
  46. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
  47. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +27 -4
  48. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +10 -16
  49. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +54 -3
  50. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
  51. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
  52. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
  53. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.js +22 -0
  54. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
  55. package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +20 -0
  56. package/dist/esm/ChatbotHeader/index.d.ts +1 -0
  57. package/dist/esm/ChatbotHeader/index.js +1 -0
  58. package/dist/esm/FileDropZone/FileDropZone.d.ts +1 -2
  59. package/dist/esm/Message/Message.d.ts +9 -2
  60. package/dist/esm/Message/Message.js +40 -34
  61. package/dist/esm/Message/Message.test.js +37 -0
  62. package/dist/esm/Message/MessageInput.d.ts +3 -1
  63. package/dist/esm/Message/MessageInput.js +2 -2
  64. package/dist/esm/MessageBar/AttachButton.d.ts +2 -2
  65. package/dist/esm/MessageBar/MessageBar.d.ts +2 -2
  66. package/dist/esm/MessageBar/MessageBar.js +19 -4
  67. package/dist/esm/MessageBox/JumpButton.d.ts +5 -0
  68. package/dist/esm/MessageBox/JumpButton.js +1 -1
  69. package/dist/esm/MessageBox/JumpButton.test.js +4 -4
  70. package/dist/esm/MessageBox/MessageBox.d.ts +9 -0
  71. package/dist/esm/MessageBox/MessageBox.js +2 -2
  72. package/dist/esm/MessageBox/MessageBox.test.js +2 -2
  73. package/dist/esm/MessageDivider/MessageDivider.d.ts +9 -0
  74. package/dist/esm/MessageDivider/MessageDivider.js +21 -0
  75. package/dist/esm/MessageDivider/MessageDivider.test.d.ts +1 -0
  76. package/dist/esm/MessageDivider/MessageDivider.test.js +24 -0
  77. package/dist/esm/MessageDivider/index.d.ts +2 -0
  78. package/dist/esm/MessageDivider/index.js +2 -0
  79. package/dist/esm/ResponseActions/ResponseActions.d.ts +1 -0
  80. package/dist/esm/ResponseActions/ResponseActions.js +5 -5
  81. package/dist/esm/ResponseActions/ResponseActions.test.js +6 -1
  82. package/dist/esm/index.d.ts +2 -0
  83. package/dist/esm/index.js +2 -0
  84. package/dist/tsconfig.tsbuildinfo +1 -1
  85. package/package.json +9 -4
  86. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDividers.tsx +24 -0
  87. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +15 -1
  88. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +39 -7
  89. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotConversationEditing.tsx +202 -0
  90. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx +17 -3
  91. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +45 -5
  92. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +206 -0
  93. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +30 -4
  94. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +33 -1
  95. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotDisplayMode.tsx +486 -0
  96. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +565 -0
  97. package/src/Chatbot/Chatbot.scss +1 -1
  98. package/src/ChatbotContent/ChatbotContent.scss +1 -1
  99. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +6 -6
  100. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +5 -2
  101. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +70 -32
  102. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +176 -3
  103. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +110 -60
  104. package/src/ChatbotFooter/ChatbotFooter.scss +1 -1
  105. package/src/ChatbotHeader/ChatbotHeader.scss +3 -3
  106. package/src/ChatbotHeader/ChatbotHeaderMenu.test.tsx +1 -1
  107. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +2 -2
  108. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx +25 -0
  109. package/src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx +64 -0
  110. package/src/ChatbotHeader/index.ts +1 -0
  111. package/src/ChatbotModal/ChatbotModal.scss +1 -1
  112. package/src/ChatbotToggle/ChatbotToggle.scss +2 -2
  113. package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +6 -9
  114. package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +6 -9
  115. package/src/FileDropZone/FileDropZone.tsx +2 -2
  116. package/src/Message/Message.scss +9 -7
  117. package/src/Message/Message.test.tsx +54 -0
  118. package/src/Message/Message.tsx +70 -50
  119. package/src/Message/MessageInput.tsx +5 -1
  120. package/src/MessageBar/AttachButton.tsx +2 -2
  121. package/src/MessageBar/MessageBar.tsx +25 -5
  122. package/src/MessageBar/SendButton.scss +3 -3
  123. package/src/MessageBox/JumpButton.scss +1 -1
  124. package/src/MessageBox/JumpButton.test.tsx +4 -4
  125. package/src/MessageBox/JumpButton.tsx +20 -4
  126. package/src/MessageBox/MessageBox.test.tsx +2 -2
  127. package/src/MessageBox/MessageBox.tsx +23 -2
  128. package/src/MessageDivider/MessageDivider.scss +45 -0
  129. package/src/MessageDivider/MessageDivider.test.tsx +24 -0
  130. package/src/MessageDivider/MessageDivider.tsx +35 -0
  131. package/src/MessageDivider/index.ts +3 -0
  132. package/src/ResponseActions/ResponseActions.test.tsx +6 -1
  133. package/src/ResponseActions/ResponseActions.tsx +24 -3
  134. package/src/index.ts +3 -0
  135. package/src/main.scss +1 -52
@@ -26,6 +26,7 @@ const ALL_ACTIONS = [
26
26
  { label: /Good response/i },
27
27
  { label: /Bad response/i },
28
28
  { label: /Copy/i },
29
+ { label: /Edit/i },
29
30
  { label: /Share/i },
30
31
  { label: /Listen/i }
31
32
  ];
@@ -346,6 +347,8 @@ describe('Message', () => {
346
347
  // eslint-disable-next-line no-console
347
348
  copy: { onClick: () => console.log('Copy') },
348
349
  // eslint-disable-next-line no-console
350
+ edit: { onClick: () => console.log('Edit') },
351
+ // eslint-disable-next-line no-console
349
352
  share: { onClick: () => console.log('Share') },
350
353
  // eslint-disable-next-line no-console
351
354
  download: { onClick: () => console.log('Download') },
@@ -365,6 +368,8 @@ describe('Message', () => {
365
368
  // eslint-disable-next-line no-console
366
369
  copy: { onClick: () => console.log('Copy') },
367
370
  // eslint-disable-next-line no-console
371
+ edit: { onClick: () => console.log('Edit') },
372
+ // eslint-disable-next-line no-console
368
373
  share: { onClick: () => console.log('Share') },
369
374
  // eslint-disable-next-line no-console
370
375
  download: { onClick: () => console.log('Download') },
@@ -376,6 +381,27 @@ describe('Message', () => {
376
381
  expect(react_2.screen.queryByRole('button', { name: label })).toBeFalsy();
377
382
  });
378
383
  }));
384
+ it('should not show actions if isEditable is true', () => __awaiter(void 0, void 0, void 0, function* () {
385
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", isEditable: true, actions: {
386
+ // eslint-disable-next-line no-console
387
+ positive: { onClick: () => console.log('Good response') },
388
+ // eslint-disable-next-line no-console
389
+ negative: { onClick: () => console.log('Bad response') },
390
+ // eslint-disable-next-line no-console
391
+ copy: { onClick: () => console.log('Copy') },
392
+ // eslint-disable-next-line no-console
393
+ edit: { onClick: () => console.log('Edit') },
394
+ // eslint-disable-next-line no-console
395
+ share: { onClick: () => console.log('Share') },
396
+ // eslint-disable-next-line no-console
397
+ download: { onClick: () => console.log('Download') },
398
+ // eslint-disable-next-line no-console
399
+ listen: { onClick: () => console.log('Listen') }
400
+ } }));
401
+ ALL_ACTIONS.forEach(({ label }) => {
402
+ expect(react_2.screen.queryByRole('button', { name: label })).toBeFalsy();
403
+ });
404
+ }));
379
405
  it('should render unordered lists correctly', () => {
380
406
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: UNORDERED_LIST }));
381
407
  expect(react_2.screen.getByText('Here is an unordered list:')).toBeTruthy();
@@ -713,4 +739,15 @@ describe('Message', () => {
713
739
  const form = container.querySelector('form');
714
740
  expect(form).toHaveClass('test');
715
741
  });
742
+ it('should be able to disable markdown parsing', () => {
743
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, isMarkdownDisabled: true }));
744
+ // this is looking for markdown syntax that is ordinarily stripped
745
+ expect(react_2.screen.getByText(/~~~yaml/i)).toBeTruthy();
746
+ });
747
+ it('should be able to pass props to react-markdown, such as disabling tags', () => {
748
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, reactMarkdownProps: { disallowedElements: ['code'] } }));
749
+ expect(react_2.screen.getByText('Here is some YAML code:')).toBeTruthy();
750
+ // code block isn't rendering
751
+ expect(react_2.screen.queryByRole('button', { name: 'Copy code' })).toBeFalsy();
752
+ });
716
753
  });
@@ -1,4 +1,4 @@
1
- import type { FunctionComponent } from 'react';
1
+ import type { FunctionComponent, Ref } from 'react';
2
2
  import { FormProps } from '@patternfly/react-core';
3
3
  export interface MessageInputProps extends FormProps {
4
4
  /** Placeholder for edit input */
@@ -11,6 +11,8 @@ export interface MessageInputProps extends FormProps {
11
11
  onEditUpdate?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, value: string) => void;
12
12
  /** Callback functionf or when edit cancel update button is clicked */
13
13
  onEditCancel?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
14
+ /** Ref applied to editable message input */
15
+ inputRef?: Ref<HTMLTextAreaElement>;
14
16
  /** Message text */
15
17
  content?: string;
16
18
  }
@@ -15,11 +15,11 @@ const jsx_runtime_1 = require("react/jsx-runtime");
15
15
  const react_1 = require("react");
16
16
  const react_core_1 = require("@patternfly/react-core");
17
17
  const MessageInput = (_a) => {
18
- var { editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, content } = _a, props = __rest(_a, ["editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "content"]);
18
+ var { editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, content } = _a, props = __rest(_a, ["editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "content"]);
19
19
  const [messageText, setMessageText] = (0, react_1.useState)(content !== null && content !== void 0 ? content : '');
20
20
  const onChange = (_event, value) => {
21
21
  setMessageText(value);
22
22
  };
23
- return ((0, jsx_runtime_1.jsxs)(react_core_1.Form, Object.assign({}, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.TextArea, { placeholder: editPlaceholder, value: messageText, onChange: onChange, "aria-label": editPlaceholder, autoResize: true }), (0, jsx_runtime_1.jsxs)(react_core_1.ActionGroup, { className: "pf-chatbot__message-edit-buttons", children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "primary", onClick: (event) => onEditUpdate && onEditUpdate(event, messageText), children: updateWord }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "secondary", onClick: onEditCancel, children: cancelWord })] })] })));
23
+ return ((0, jsx_runtime_1.jsxs)(react_core_1.Form, Object.assign({}, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.TextArea, { placeholder: editPlaceholder, value: messageText, onChange: onChange, "aria-label": editPlaceholder, autoResize: true, ref: inputRef }), (0, jsx_runtime_1.jsxs)(react_core_1.ActionGroup, { className: "pf-chatbot__message-edit-buttons", children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "primary", onClick: (event) => onEditUpdate && onEditUpdate(event, messageText), children: updateWord }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "secondary", onClick: onEditCancel, children: cancelWord })] })] })));
24
24
  };
25
25
  exports.default = MessageInput;
@@ -1,5 +1,5 @@
1
- import { ButtonProps, DropEvent, TooltipProps } from '@patternfly/react-core';
2
- import { Accept, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
1
+ import { ButtonProps, TooltipProps } from '@patternfly/react-core';
2
+ import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
3
3
  export interface AttachButtonProps extends ButtonProps {
4
4
  /** Callback for when button is clicked */
5
5
  onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
@@ -1,6 +1,6 @@
1
1
  import type { FunctionComponent } from 'react';
2
- import { Accept, DropzoneOptions, FileError, FileRejection } from 'react-dropzone/.';
3
- import { ButtonProps, DropEvent, TextAreaProps, TooltipProps } from '@patternfly/react-core';
2
+ import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
3
+ import { ButtonProps, TextAreaProps, TooltipProps } from '@patternfly/react-core';
4
4
  import { ChatbotDisplayMode } from '../Chatbot';
5
5
  export interface MessageBarWithAttachMenuProps {
6
6
  /** Flag to enable whether attach menu is open */
@@ -32,6 +32,7 @@ const MessageBarBase = (_a) => {
32
32
  const [message, setMessage] = (0, react_1.useState)(value !== null && value !== void 0 ? value : '');
33
33
  const [isListeningMessage, setIsListeningMessage] = (0, react_1.useState)(false);
34
34
  const [hasSentMessage, setHasSentMessage] = (0, react_1.useState)(false);
35
+ const [isComposing, setIsComposing] = (0, react_1.useState)(false);
35
36
  const inputRef = (0, react_1.useRef)(null);
36
37
  const textareaRef = (_b = innerRef) !== null && _b !== void 0 ? _b : inputRef;
37
38
  const attachButtonRef = (0, react_1.useRef)(null);
@@ -157,18 +158,32 @@ const MessageBarBase = (_a) => {
157
158
  setMessage('');
158
159
  }, [onSendMessage]);
159
160
  const handleKeyDown = (0, react_1.useCallback)((event) => {
160
- if (event.key === 'Enter' && !event.shiftKey) {
161
+ // Japanese and other languages may use IME for character input.
162
+ // In these cases, enter is used to select the final input, so we need to check for composition end instead.
163
+ // See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/
164
+ // Chrome, Edge, and Firefox seem to work well with just the compose event.
165
+ // Safari is a little bit special. We need to handle 229 as well in this case.
166
+ const nativeEvent = event.nativeEvent;
167
+ const isCompositionKey = nativeEvent.which === 229;
168
+ const isCurrentlyComposing = isComposing || isCompositionKey;
169
+ if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) {
161
170
  event.preventDefault();
162
171
  if (!isSendButtonDisabled && !hasStopButton) {
163
172
  handleSend(message);
164
173
  }
165
174
  }
166
- if (event.key === 'Enter' && event.shiftKey) {
175
+ if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) {
167
176
  if (textareaRef.current) {
168
177
  handleNewLine(textareaRef.current);
169
178
  }
170
179
  }
171
- }, [isSendButtonDisabled, hasStopButton, handleSend, message]);
180
+ }, [isSendButtonDisabled, hasStopButton, handleSend, message, isComposing]);
181
+ const handleCompositionStart = (0, react_1.useCallback)(() => {
182
+ setIsComposing(true);
183
+ }, []);
184
+ const handleCompositionEnd = (0, react_1.useCallback)(() => {
185
+ setIsComposing(false);
186
+ }, []);
172
187
  const handleAttachMenuToggle = () => {
173
188
  (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.setIsAttachMenuOpen) && (attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.setIsAttachMenuOpen(!(attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.isAttachMenuOpen)));
174
189
  attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.onAttachMenuToggleClick();
@@ -184,7 +199,7 @@ const MessageBarBase = (_a) => {
184
199
  }
185
200
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [attachMenuProps && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))), !attachMenuProps && hasAttachButton && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))), hasMicrophoneButton && ((0, jsx_runtime_1.jsx)(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))), (alwayShowSendButton || message) && ((0, jsx_runtime_1.jsx)(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))] }));
186
201
  };
187
- const messageBarContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown }, props)) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
202
+ const messageBarContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd }, props)) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
188
203
  if (attachMenuProps) {
189
204
  return ((0, jsx_runtime_1.jsx)(AttachMenu_1.default, Object.assign({ toggle: (toggleRef) => ((0, jsx_runtime_1.jsx)("div", { ref: toggleRef, className: `pf-chatbot__message-bar ${className !== null && className !== void 0 ? className : ''}`, children: messageBarContents })), filteredItems: attachMenuProps === null || attachMenuProps === void 0 ? void 0 : attachMenuProps.attachMenuItems }, (attachMenuProps && { isOpen: attachMenuProps.isAttachMenuOpen }), { onOpenChange: (isAttachMenuOpen) => {
190
205
  var _a;
@@ -1,4 +1,5 @@
1
1
  import type { FunctionComponent } from 'react';
2
+ import { TooltipProps, ButtonProps } from '@patternfly/react-core';
2
3
  export interface JumpButtonProps {
3
4
  /** Position of the Jump Button(top/bottom) */
4
5
  position: 'top' | 'bottom';
@@ -6,6 +7,10 @@ export interface JumpButtonProps {
6
7
  onClick: () => void;
7
8
  /** Flag to change the visibilty of the button */
8
9
  isHidden?: boolean;
10
+ /** Additional props passed to jump buttons */
11
+ jumpButtonProps?: ButtonProps;
12
+ /** Additional props passed to tooltip */
13
+ jumpButtonTooltipProps?: TooltipProps;
9
14
  }
10
15
  declare const JumpButton: FunctionComponent<JumpButtonProps>;
11
16
  export default JumpButton;
@@ -5,5 +5,5 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_core_1 = require("@patternfly/react-core");
6
6
  const arrow_up_icon_1 = require("@patternfly/react-icons/dist/esm/icons/arrow-up-icon");
7
7
  const arrow_down_icon_1 = require("@patternfly/react-icons/dist/esm/icons/arrow-down-icon");
8
- const JumpButton = ({ position, isHidden, onClick }) => isHidden ? null : ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { id: `pf-chatbot__tooltip--jump-${position}`, content: `Back to ${position}`, position: "top", children: (0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "plain", className: `pf-chatbot__jump pf-chatbot__jump--${position}`, "aria-label": `Jump ${position}`, onClick: onClick, children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: "lg", isInline: true, children: position === 'top' ? (0, jsx_runtime_1.jsx)(arrow_up_icon_1.ArrowUpIcon, {}) : (0, jsx_runtime_1.jsx)(arrow_down_icon_1.ArrowDownIcon, {}) }) }) }));
8
+ const JumpButton = ({ position, isHidden, onClick, jumpButtonProps, jumpButtonTooltipProps }) => isHidden ? null : ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ id: `pf-chatbot__tooltip--jump-${position}`, content: `Back to ${position}`, position: "top" }, jumpButtonTooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ variant: "plain", className: `pf-chatbot__jump pf-chatbot__jump--${position}`, "aria-label": `Back to ${position}`, onClick: onClick }, jumpButtonProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: "lg", isInline: true, children: position === 'top' ? (0, jsx_runtime_1.jsx)(arrow_up_icon_1.ArrowUpIcon, {}) : (0, jsx_runtime_1.jsx)(arrow_down_icon_1.ArrowDownIcon, {}) }) })) })));
9
9
  exports.default = JumpButton;
@@ -20,20 +20,20 @@ const user_event_1 = __importDefault(require("@testing-library/user-event"));
20
20
  describe('JumpButton', () => {
21
21
  it('should render top button correctly', () => {
22
22
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", onClick: jest.fn() }));
23
- expect(react_1.screen.getByRole('button', { name: /Jump top/i })).toBeTruthy();
23
+ expect(react_1.screen.getByRole('button', { name: /Back to top/i })).toBeTruthy();
24
24
  });
25
25
  it('should render bottom button correctly', () => {
26
26
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: jest.fn() }));
27
- expect(react_1.screen.getByRole('button', { name: /Jump bottom/i })).toBeTruthy();
27
+ expect(react_1.screen.getByRole('button', { name: /Back to bottom/i })).toBeTruthy();
28
28
  });
29
29
  it('should call onClick appropriately', () => __awaiter(void 0, void 0, void 0, function* () {
30
30
  const spy = jest.fn();
31
31
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: spy }));
32
- yield user_event_1.default.click(react_1.screen.getByRole('button', { name: /Jump bottom/i }));
32
+ yield user_event_1.default.click(react_1.screen.getByRole('button', { name: /Back to bottom/i }));
33
33
  expect(spy).toHaveBeenCalledTimes(1);
34
34
  }));
35
35
  it('should be hidden if isHidden prop is used', () => __awaiter(void 0, void 0, void 0, function* () {
36
36
  (0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: jest.fn(), isHidden: true }));
37
- expect(react_1.screen.queryByRole('button', { name: /Jump bottom/i })).toBeFalsy();
37
+ expect(react_1.screen.queryByRole('button', { name: /Back to bottom/i })).toBeFalsy();
38
38
  }));
39
39
  });
@@ -1,4 +1,5 @@
1
1
  import { HTMLProps, ReactNode } from 'react';
2
+ import { ButtonProps, TooltipProps } from '@patternfly/react-core';
2
3
  export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
3
4
  /** Content that can be announced, such as a new message, for screen readers */
4
5
  announcement?: string;
@@ -18,6 +19,14 @@ export interface MessageBoxProps extends HTMLProps<HTMLDivElement> {
18
19
  onScrollToBottomClick?: () => void;
19
20
  /** Flag to enable automatic scrolling when new messages are added */
20
21
  enableSmartScroll?: boolean;
22
+ /** Props passed to top jump button */
23
+ jumpButtonTopProps?: ButtonProps;
24
+ /** Props passed to bottom jump button */
25
+ jumpButtonBottomProps?: ButtonProps;
26
+ /** Props passed to top jump button tooltip */
27
+ jumpButtonTopTooltipProps?: TooltipProps;
28
+ /** Props passed to top jump button tooltip */
29
+ jumpButtonBottomTooltipProps?: TooltipProps;
21
30
  }
22
31
  export interface MessageBoxHandle extends HTMLDivElement {
23
32
  /** Scrolls to the top of the message box */
@@ -22,7 +22,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
22
22
  const react_1 = require("react");
23
23
  const JumpButton_1 = __importDefault(require("./JumpButton"));
24
24
  exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
25
- var { announcement, ariaLabel = 'Scrollable message log', children, className, position = 'top', onScrollToTopClick, onScrollToBottomClick, enableSmartScroll = false } = _a, props = __rest(_a, ["announcement", "ariaLabel", "children", "className", "position", "onScrollToTopClick", "onScrollToBottomClick", "enableSmartScroll"]);
25
+ var { announcement, ariaLabel = 'Scrollable message log', children, className, position = 'top', onScrollToTopClick, onScrollToBottomClick, enableSmartScroll = false, jumpButtonTopProps, jumpButtonBottomProps, jumpButtonBottomTooltipProps, jumpButtonTopTooltipProps } = _a, props = __rest(_a, ["announcement", "ariaLabel", "children", "className", "position", "onScrollToTopClick", "onScrollToBottomClick", "enableSmartScroll", "jumpButtonTopProps", "jumpButtonBottomProps", "jumpButtonBottomTooltipProps", "jumpButtonTopTooltipProps"]);
26
26
  const [atTop, setAtTop] = (0, react_1.useState)(false);
27
27
  const [atBottom, setAtBottom] = (0, react_1.useState)(true);
28
28
  const [isOverflowing, setIsOverflowing] = (0, react_1.useState)(false);
@@ -206,6 +206,6 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
206
206
  onTouchMove,
207
207
  onTouchEnd
208
208
  };
209
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' && 'pf-chatbot__messagebox--bottom'} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__messagebox-announcement", "aria-live": "polite", children: announcement })] })), (0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }) })] }));
209
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop, jumpButtonProps: jumpButtonTopProps, jumpButtonTooltipProps: jumpButtonTopTooltipProps }), (0, jsx_runtime_1.jsxs)("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' ? 'pf-chatbot__messagebox--bottom' : ''} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__messagebox-announcement", "aria-live": "polite", children: announcement })] })), (0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }), jumpButtonProps: jumpButtonBottomProps, jumpButtonTooltipProps: jumpButtonBottomTooltipProps })] }));
210
210
  });
211
211
  exports.default = exports.MessageBox;
@@ -56,7 +56,7 @@ describe('MessageBox', () => {
56
56
  region.dispatchEvent(new Event('scroll'));
57
57
  });
58
58
  yield (0, react_2.waitFor)(() => {
59
- user_event_1.default.click(react_2.screen.getByRole('button', { name: /Jump bottom/i }));
59
+ user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to bottom/i }));
60
60
  expect(spy).toHaveBeenCalled();
61
61
  });
62
62
  }));
@@ -75,7 +75,7 @@ describe('MessageBox', () => {
75
75
  region.dispatchEvent(new Event('scroll'));
76
76
  });
77
77
  yield (0, react_2.waitFor)(() => {
78
- user_event_1.default.click(react_2.screen.getByRole('button', { name: /Jump top/i }));
78
+ user_event_1.default.click(react_2.screen.getByRole('button', { name: /Back to top/i }));
79
79
  expect(spy).toHaveBeenCalled();
80
80
  });
81
81
  }));
@@ -0,0 +1,9 @@
1
+ import type { FunctionComponent } from 'react';
2
+ export interface MessageDividerProps {
3
+ /** Variant of the divider */
4
+ variant?: 'inset' | 'fullWidth';
5
+ /** Content of the message divider */
6
+ content?: string;
7
+ }
8
+ declare const MessageDivider: FunctionComponent<MessageDividerProps>;
9
+ export default MessageDivider;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ const jsx_runtime_1 = require("react/jsx-runtime");
15
+ const react_core_1 = require("@patternfly/react-core");
16
+ const MessageDivider = (_a) => {
17
+ var { variant = 'inset', content = new Date().toLocaleDateString() } = _a, props = __rest(_a, ["variant", "content"]);
18
+ if (variant === 'inset') {
19
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: "pf-chatbot__message-divider pf-m-divider pf-m-wrap" }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Divider, {}), (0, jsx_runtime_1.jsx)(react_core_1.Label, { variant: "outline", children: content })] })));
20
+ }
21
+ return ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: "pf-chatbot__message-divider pf-m-wrap" }, props, { children: (0, jsx_runtime_1.jsx)(react_core_1.Label, { children: content }) })));
22
+ };
23
+ exports.default = MessageDivider;
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("@testing-library/react");
8
+ require("@testing-library/jest-dom");
9
+ const MessageDivider_1 = __importDefault(require("./MessageDivider"));
10
+ describe('MessageDivider', () => {
11
+ beforeEach(() => {
12
+ jest.clearAllMocks();
13
+ });
14
+ it('should render default correctly with variant = date and content = new Date().toLocaleDateString()', () => {
15
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageDivider_1.default, { "data-testid": "message-divider" }));
16
+ expect(react_1.screen.getByText(new Date().toLocaleDateString())).toBeInTheDocument();
17
+ expect(react_1.screen.getByTestId('message-divider')).toHaveClass('pf-m-divider');
18
+ });
19
+ it('should render inset variant correctly', () => {
20
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageDivider_1.default, { variant: "inset", content: "test", "data-testid": "message-divider" }));
21
+ expect(react_1.screen.getByText('test')).toBeInTheDocument();
22
+ expect(react_1.screen.getByTestId('message-divider')).toHaveClass('pf-m-divider');
23
+ });
24
+ it('should render fullWidth variant correctly', () => {
25
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageDivider_1.default, { variant: "fullWidth", content: "test", "data-testid": "message-divider" }));
26
+ expect(react_1.screen.getByText('test')).toBeInTheDocument();
27
+ expect(react_1.screen.getByTestId('message-divider')).not.toHaveClass('pf-m-divider');
28
+ });
29
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from './MessageDivider';
2
+ export * from './MessageDivider';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.default = void 0;
21
+ var MessageDivider_1 = require("./MessageDivider");
22
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(MessageDivider_1).default; } });
23
+ __exportStar(require("./MessageDivider"), exports);
@@ -38,6 +38,7 @@ export interface ResponseActionProps {
38
38
  share?: ActionProps;
39
39
  download?: ActionProps;
40
40
  listen?: ActionProps;
41
+ edit?: ActionProps;
41
42
  };
42
43
  }
43
44
  export declare const ResponseActions: FunctionComponent<ResponseActionProps>;
@@ -21,12 +21,12 @@ const react_2 = require("react");
21
21
  const react_icons_1 = require("@patternfly/react-icons");
22
22
  const ResponseActionButton_1 = __importDefault(require("./ResponseActionButton"));
23
23
  const ResponseActions = ({ actions }) => {
24
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
24
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3;
25
25
  const [activeButton, setActiveButton] = (0, react_2.useState)();
26
26
  const [clickStatePersisted, setClickStatePersisted] = (0, react_2.useState)(false);
27
27
  (0, react_2.useEffect)(() => {
28
28
  // Define the order of precedence for checking initial `isClicked`
29
- const actionPrecedence = ['positive', 'negative', 'copy', 'share', 'download', 'listen'];
29
+ const actionPrecedence = ['positive', 'negative', 'copy', 'edit', 'share', 'download', 'listen'];
30
30
  let initialActive;
31
31
  // Check predefined actions first based on precedence
32
32
  for (const actionName of actionPrecedence) {
@@ -47,7 +47,7 @@ const ResponseActions = ({ actions }) => {
47
47
  }
48
48
  setActiveButton(initialActive);
49
49
  }, [actions]);
50
- const { positive, negative, copy, share, download, listen } = actions, additionalActions = __rest(actions, ["positive", "negative", "copy", "share", "download", "listen"]);
50
+ const { positive, negative, copy, edit, share, download, listen } = actions, additionalActions = __rest(actions, ["positive", "negative", "copy", "edit", "share", "download", "listen"]);
51
51
  const responseActions = (0, react_2.useRef)(null);
52
52
  (0, react_2.useEffect)(() => {
53
53
  const handleClickOutside = (e) => {
@@ -65,7 +65,7 @@ const ResponseActions = ({ actions }) => {
65
65
  setActiveButton(id);
66
66
  onClick && onClick(e);
67
67
  };
68
- return ((0, jsx_runtime_1.jsxs)("div", { ref: responseActions, className: "pf-chatbot__response-actions", children: [positive && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, positive, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedThumbsUpIcon, {}), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] }))), negative && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, negative, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedThumbsDownIcon, {}), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] }))), copy && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, copy, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedCopyIcon, {}), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] }))), share && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, share, { ariaLabel: (_o = share.ariaLabel) !== null && _o !== void 0 ? _o : 'Share', clickedAriaLabel: (_p = share.ariaLabel) !== null && _p !== void 0 ? _p : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_q = share.tooltipContent) !== null && _q !== void 0 ? _q : 'Share', clickedTooltipContent: (_r = share.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Shared', tooltipProps: share.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkAltIcon, {}), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] }))), download && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, download, { ariaLabel: (_s = download.ariaLabel) !== null && _s !== void 0 ? _s : 'Download', clickedAriaLabel: (_t = download.ariaLabel) !== null && _t !== void 0 ? _t : 'Downloaded', onClick: (e) => handleClick(e, 'download', download.onClick), className: download.className, isDisabled: download.isDisabled, tooltipContent: (_u = download.tooltipContent) !== null && _u !== void 0 ? _u : 'Download', clickedTooltipContent: (_v = download.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Downloaded', tooltipProps: download.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.DownloadIcon, {}), isClicked: activeButton === 'download', ref: download.ref, "aria-expanded": download['aria-expanded'], "aria-controls": download['aria-controls'] }))), listen && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, listen, { ariaLabel: (_w = listen.ariaLabel) !== null && _w !== void 0 ? _w : 'Listen', clickedAriaLabel: (_x = listen.ariaLabel) !== null && _x !== void 0 ? _x : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_y = listen.tooltipContent) !== null && _y !== void 0 ? _y : 'Listen', clickedTooltipContent: (_z = listen.clickedTooltipContent) !== null && _z !== void 0 ? _z : 'Listening', tooltipProps: listen.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.VolumeUpIcon, {}), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] }))), Object.keys(additionalActions).map((action) => {
68
+ return ((0, jsx_runtime_1.jsxs)("div", { ref: responseActions, className: "pf-chatbot__response-actions", children: [positive && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, positive, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedThumbsUpIcon, {}), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] }))), negative && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, negative, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedThumbsDownIcon, {}), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] }))), copy && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, copy, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedCopyIcon, {}), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] }))), edit && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, edit, { ariaLabel: (_o = edit.ariaLabel) !== null && _o !== void 0 ? _o : 'Edit', clickedAriaLabel: (_p = edit.ariaLabel) !== null && _p !== void 0 ? _p : 'Editing', onClick: (e) => handleClick(e, 'edit', edit.onClick), className: edit.className, isDisabled: edit.isDisabled, tooltipContent: (_q = edit.tooltipContent) !== null && _q !== void 0 ? _q : 'Edit ', clickedTooltipContent: (_r = edit.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Editing', tooltipProps: edit.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.PencilAltIcon, {}), isClicked: activeButton === 'edit', ref: edit.ref, "aria-expanded": edit['aria-expanded'], "aria-controls": edit['aria-controls'] }))), share && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, share, { ariaLabel: (_s = share.ariaLabel) !== null && _s !== void 0 ? _s : 'Share', clickedAriaLabel: (_t = share.ariaLabel) !== null && _t !== void 0 ? _t : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_u = share.tooltipContent) !== null && _u !== void 0 ? _u : 'Share', clickedTooltipContent: (_v = share.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Shared', tooltipProps: share.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.ExternalLinkAltIcon, {}), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] }))), download && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, download, { ariaLabel: (_w = download.ariaLabel) !== null && _w !== void 0 ? _w : 'Download', clickedAriaLabel: (_x = download.ariaLabel) !== null && _x !== void 0 ? _x : 'Downloaded', onClick: (e) => handleClick(e, 'download', download.onClick), className: download.className, isDisabled: download.isDisabled, tooltipContent: (_y = download.tooltipContent) !== null && _y !== void 0 ? _y : 'Download', clickedTooltipContent: (_z = download.clickedTooltipContent) !== null && _z !== void 0 ? _z : 'Downloaded', tooltipProps: download.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.DownloadIcon, {}), isClicked: activeButton === 'download', ref: download.ref, "aria-expanded": download['aria-expanded'], "aria-controls": download['aria-controls'] }))), listen && ((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, Object.assign({}, listen, { ariaLabel: (_0 = listen.ariaLabel) !== null && _0 !== void 0 ? _0 : 'Listen', clickedAriaLabel: (_1 = listen.ariaLabel) !== null && _1 !== void 0 ? _1 : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_2 = listen.tooltipContent) !== null && _2 !== void 0 ? _2 : 'Listen', clickedTooltipContent: (_3 = listen.clickedTooltipContent) !== null && _3 !== void 0 ? _3 : 'Listening', tooltipProps: listen.tooltipProps, icon: (0, jsx_runtime_1.jsx)(react_icons_1.VolumeUpIcon, {}), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] }))), Object.keys(additionalActions).map((action) => {
69
69
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
70
70
  return ((0, react_1.createElement)(ResponseActionButton_1.default, Object.assign({}, additionalActions[action], { key: action, ariaLabel: (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.ariaLabel, clickedAriaLabel: (_b = additionalActions[action]) === null || _b === void 0 ? void 0 : _b.clickedAriaLabel, onClick: (e) => { var _a; return handleClick(e, action, (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.onClick); }, className: (_c = additionalActions[action]) === null || _c === void 0 ? void 0 : _c.className, isDisabled: (_d = additionalActions[action]) === null || _d === void 0 ? void 0 : _d.isDisabled, tooltipContent: (_e = additionalActions[action]) === null || _e === void 0 ? void 0 : _e.tooltipContent, tooltipProps: (_f = additionalActions[action]) === null || _f === void 0 ? void 0 : _f.tooltipProps, clickedTooltipContent: (_g = additionalActions[action]) === null || _g === void 0 ? void 0 : _g.clickedTooltipContent, icon: (_h = additionalActions[action]) === null || _h === void 0 ? void 0 : _h.icon, isClicked: activeButton === action, ref: (_j = additionalActions[action]) === null || _j === void 0 ? void 0 : _j.ref, "aria-expanded": (_k = additionalActions[action]) === null || _k === void 0 ? void 0 : _k['aria-expanded'], "aria-controls": (_l = additionalActions[action]) === null || _l === void 0 ? void 0 : _l['aria-controls'] })));
71
71
  })] }));
@@ -23,6 +23,7 @@ const ALL_ACTIONS = [
23
23
  { type: 'positive', label: 'Good response', clickedLabel: 'Response recorded' },
24
24
  { type: 'negative', label: 'Bad response', clickedLabel: 'Response recorded' },
25
25
  { type: 'copy', label: 'Copy', clickedLabel: 'Copied' },
26
+ { type: 'edit', label: 'Edit', clickedLabel: 'Editing' },
26
27
  { type: 'share', label: 'Share', clickedLabel: 'Shared' },
27
28
  { type: 'listen', label: 'Listen', clickedLabel: 'Listening' }
28
29
  ];
@@ -56,6 +57,7 @@ const ALL_ACTIONS_DATA_TEST = [
56
57
  { type: 'positive', label: 'Good response', dataTestId: 'positive' },
57
58
  { type: 'negative', label: 'Bad response', dataTestId: 'negative' },
58
59
  { type: 'copy', label: 'Copy', dataTestId: 'copy' },
60
+ { type: 'edit', label: 'Edit', dataTestId: 'edit' },
59
61
  { type: 'share', label: 'Share', dataTestId: 'share' },
60
62
  { type: 'download', label: 'Download', dataTestId: 'download' },
61
63
  { type: 'listen', label: 'Listen', dataTestId: 'listen' }
@@ -69,6 +71,7 @@ describe('ResponseActions', () => {
69
71
  positive: { onClick: jest.fn() },
70
72
  negative: { onClick: jest.fn() },
71
73
  copy: { onClick: jest.fn() },
74
+ edit: { onClick: jest.fn() },
72
75
  share: { onClick: jest.fn() },
73
76
  download: { onClick: jest.fn() },
74
77
  listen: { onClick: jest.fn() }
@@ -76,10 +79,11 @@ describe('ResponseActions', () => {
76
79
  const goodBtn = react_1.screen.getByRole('button', { name: 'Good response' });
77
80
  const badBtn = react_1.screen.getByRole('button', { name: 'Bad response' });
78
81
  const copyBtn = react_1.screen.getByRole('button', { name: 'Copy' });
82
+ const editBtn = react_1.screen.getByRole('button', { name: 'Edit' });
79
83
  const shareBtn = react_1.screen.getByRole('button', { name: 'Share' });
80
84
  const downloadBtn = react_1.screen.getByRole('button', { name: 'Download' });
81
85
  const listenBtn = react_1.screen.getByRole('button', { name: 'Listen' });
82
- const buttons = [goodBtn, badBtn, copyBtn, shareBtn, downloadBtn, listenBtn];
86
+ const buttons = [goodBtn, badBtn, copyBtn, editBtn, shareBtn, downloadBtn, listenBtn];
83
87
  buttons.forEach((button) => {
84
88
  expect(button).toBeTruthy();
85
89
  });
@@ -211,6 +215,7 @@ describe('ResponseActions', () => {
211
215
  { type: 'positive', ariaLabel: 'Thumbs up' },
212
216
  { type: 'negative', ariaLabel: 'Thumbs down' },
213
217
  { type: 'copy', ariaLabel: 'Copy the message' },
218
+ { type: 'edit', ariaLabel: 'Edit this message' },
214
219
  { type: 'share', ariaLabel: 'Share it with friends' },
215
220
  { type: 'download', ariaLabel: 'Download your cool message' },
216
221
  { type: 'listen', ariaLabel: 'Listen up' }
@@ -40,6 +40,8 @@ export { default as MessageBar } from './MessageBar';
40
40
  export * from './MessageBar';
41
41
  export { default as MessageBox } from './MessageBox';
42
42
  export * from './MessageBox';
43
+ export { default as MessageDivider } from './MessageDivider';
44
+ export * from './MessageDivider';
43
45
  export { default as PreviewAttachment } from './PreviewAttachment';
44
46
  export * from './PreviewAttachment';
45
47
  export { default as ResponseActions } from './ResponseActions';
package/dist/cjs/index.js CHANGED
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.tracking = exports.TermsOfUse = exports.SourcesCard = exports.SourceDetailsMenuItem = exports.Settings = exports.ResponseActions = exports.PreviewAttachment = exports.MessageBox = exports.MessageBar = exports.Message = exports.LoadingMessage = exports.FileDropZone = exports.FileDetailsLabel = exports.FileDetails = exports.Compare = exports.CodeModal = exports.ChatbotWelcomePrompt = exports.ChatbotToggle = exports.ChatbotPopover = exports.ChatbotModal = exports.ChatbotHeader = exports.ChatbotFooter = exports.ChatbotConversationHistoryNav = exports.ChatbotContent = exports.ChatbotAlert = exports.Chatbot = exports.AttachMenu = exports.AttachmentEdit = void 0;
21
+ exports.tracking = exports.TermsOfUse = exports.SourcesCard = exports.SourceDetailsMenuItem = exports.Settings = exports.ResponseActions = exports.PreviewAttachment = exports.MessageDivider = exports.MessageBox = exports.MessageBar = exports.Message = exports.LoadingMessage = exports.FileDropZone = exports.FileDetailsLabel = exports.FileDetails = exports.Compare = exports.CodeModal = exports.ChatbotWelcomePrompt = exports.ChatbotToggle = exports.ChatbotPopover = exports.ChatbotModal = exports.ChatbotHeader = exports.ChatbotFooter = exports.ChatbotConversationHistoryNav = exports.ChatbotContent = exports.ChatbotAlert = exports.Chatbot = exports.AttachMenu = exports.AttachmentEdit = void 0;
22
22
  var AttachmentEdit_1 = require("./AttachmentEdit");
23
23
  Object.defineProperty(exports, "AttachmentEdit", { enumerable: true, get: function () { return __importDefault(AttachmentEdit_1).default; } });
24
24
  __exportStar(require("./AttachmentEdit"), exports);
@@ -82,6 +82,9 @@ __exportStar(require("./MessageBar"), exports);
82
82
  var MessageBox_1 = require("./MessageBox");
83
83
  Object.defineProperty(exports, "MessageBox", { enumerable: true, get: function () { return __importDefault(MessageBox_1).default; } });
84
84
  __exportStar(require("./MessageBox"), exports);
85
+ var MessageDivider_1 = require("./MessageDivider");
86
+ Object.defineProperty(exports, "MessageDivider", { enumerable: true, get: function () { return __importDefault(MessageDivider_1).default; } });
87
+ __exportStar(require("./MessageDivider"), exports);
85
88
  var PreviewAttachment_1 = require("./PreviewAttachment");
86
89
  Object.defineProperty(exports, "PreviewAttachment", { enumerable: true, get: function () { return __importDefault(PreviewAttachment_1).default; } });
87
90
  __exportStar(require("./PreviewAttachment"), exports);