@patternfly/chatbot 6.3.0-prerelease.16 → 6.3.0-prerelease.17

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.
@@ -49,6 +49,7 @@ const rehype_sanitize_1 = __importDefault(require("rehype-sanitize"));
49
49
  const LinkMessage_1 = __importDefault(require("./LinkMessage/LinkMessage"));
50
50
  const ErrorMessage_1 = __importDefault(require("./ErrorMessage/ErrorMessage"));
51
51
  const MessageInput_1 = __importDefault(require("./MessageInput"));
52
+ const rehypeMoveImagesOutOfParagraphs_1 = require("./Plugins/rehypeMoveImagesOutOfParagraphs");
52
53
  const MessageBase = (_a) => {
53
54
  var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, editFormProps, isCompact } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "editFormProps", "isCompact"]);
54
55
  const [messageText, setMessageText] = (0, react_1.useState)(content);
@@ -56,7 +57,7 @@ const MessageBase = (_a) => {
56
57
  setMessageText(content);
57
58
  }, [content]);
58
59
  const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
59
- let rehypePlugins = [rehype_unwrap_images_1.default];
60
+ let rehypePlugins = [rehype_unwrap_images_1.default, rehypeMoveImagesOutOfParagraphs_1.rehypeMoveImagesOutOfParagraphs];
60
61
  if (openLinkInNewTab) {
61
62
  rehypePlugins = rehypePlugins.concat([[rehype_external_links_1.default, { target: '_blank' }, rehype_sanitize_1.default]]);
62
63
  }
@@ -141,6 +141,7 @@ const EMPTY_TABLE = `
141
141
 
142
142
  `;
143
143
  const IMAGE = `![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
144
+ const INLINE_IMAGE = `inline text ![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
144
145
  const ERROR = {
145
146
  title: 'Could not load chat',
146
147
  children: 'Wait a few minutes and check your network settings. If the issue persists: ',
@@ -600,6 +601,11 @@ describe('Message', () => {
600
601
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: IMAGE }));
601
602
  expect(react_2.screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
602
603
  });
604
+ it('inline image parent should have class pf-chatbot__message-and-actions', () => {
605
+ (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: INLINE_IMAGE }));
606
+ expect(react_2.screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
607
+ expect(react_2.screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i }).parentElement).toHaveClass('pf-chatbot__message-and-actions');
608
+ });
603
609
  it('should handle external links correctly', () => {
604
610
  (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: `[PatternFly](https://www.patternfly.org/)` }));
605
611
  // we are mocking rehype libraries, so we can't test target _blank addition on links directly with RTL
@@ -0,0 +1,2 @@
1
+ import { Node } from 'unist';
2
+ export declare const rehypeMoveImagesOutOfParagraphs: () => (tree: Node) => void;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rehypeMoveImagesOutOfParagraphs = void 0;
4
+ const unist_util_visit_1 = require("unist-util-visit");
5
+ // Rehype plugin to remove images from within p tags and put them as separate block-level elements.
6
+ // This allows us to avoid having a blue background on images - this is something Kayla requested.
7
+ const rehypeMoveImagesOutOfParagraphs = () => (tree) => {
8
+ const nodesToRemove = [];
9
+ (0, unist_util_visit_1.visit)(tree, 'element', (node, index, parent) => {
10
+ if (node.tagName === 'p' && node.children) {
11
+ const imagesInParagraph = [];
12
+ node.children.forEach((child, childIndex) => {
13
+ if (child.type === 'element' && child.tagName === 'img') {
14
+ imagesInParagraph.push({ node: child, index: childIndex });
15
+ }
16
+ });
17
+ if (imagesInParagraph.length > 0 && parent && index !== null) {
18
+ imagesInParagraph.forEach(({ node: imgNode, index: imgIndex }) => {
19
+ nodesToRemove.push({ parent: node, index: imgIndex, node: imgNode });
20
+ });
21
+ // To avoid issues with index shifting during removal, we process in reverse
22
+ for (let i = nodesToRemove.length - 1; i >= 0; i--) {
23
+ const { parent: pTag, index: imgIndexToRemove } = nodesToRemove[i];
24
+ if (pTag.children) {
25
+ pTag.children.splice(imgIndexToRemove, 1);
26
+ }
27
+ }
28
+ // Insert the removed images after the paragraph
29
+ const paragraphIndexInParent = parent.children.indexOf(node);
30
+ if (paragraphIndexInParent !== -1) {
31
+ imagesInParagraph.forEach(({ node: imgNode }) => {
32
+ parent.children.splice(paragraphIndexInParent + 1, 0, imgNode);
33
+ });
34
+ }
35
+ // Remove paragraph if it's now empty after image removal
36
+ if (node.children.length === 0) {
37
+ const paragraphIndexInParent = parent.children.indexOf(node);
38
+ if (paragraphIndexInParent !== -1) {
39
+ parent.children.splice(paragraphIndexInParent, 1);
40
+ }
41
+ }
42
+ nodesToRemove.length = 0;
43
+ }
44
+ }
45
+ });
46
+ };
47
+ exports.rehypeMoveImagesOutOfParagraphs = rehypeMoveImagesOutOfParagraphs;
@@ -43,6 +43,7 @@ import rehypeSanitize from 'rehype-sanitize';
43
43
  import LinkMessage from './LinkMessage/LinkMessage';
44
44
  import ErrorMessage from './ErrorMessage/ErrorMessage';
45
45
  import MessageInput from './MessageInput';
46
+ import { rehypeMoveImagesOutOfParagraphs } from './Plugins/rehypeMoveImagesOutOfParagraphs';
46
47
  export const MessageBase = (_a) => {
47
48
  var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, editFormProps, isCompact } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "editFormProps", "isCompact"]);
48
49
  const [messageText, setMessageText] = useState(content);
@@ -50,7 +51,7 @@ export const MessageBase = (_a) => {
50
51
  setMessageText(content);
51
52
  }, [content]);
52
53
  const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
53
- let rehypePlugins = [rehypeUnwrapImages];
54
+ let rehypePlugins = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs];
54
55
  if (openLinkInNewTab) {
55
56
  rehypePlugins = rehypePlugins.concat([[rehypeExternalLinks, { target: '_blank' }, rehypeSanitize]]);
56
57
  }
@@ -136,6 +136,7 @@ const EMPTY_TABLE = `
136
136
 
137
137
  `;
138
138
  const IMAGE = `![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
139
+ const INLINE_IMAGE = `inline text ![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
139
140
  const ERROR = {
140
141
  title: 'Could not load chat',
141
142
  children: 'Wait a few minutes and check your network settings. If the issue persists: ',
@@ -595,6 +596,11 @@ describe('Message', () => {
595
596
  render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: IMAGE }));
596
597
  expect(screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
597
598
  });
599
+ it('inline image parent should have class pf-chatbot__message-and-actions', () => {
600
+ render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: INLINE_IMAGE }));
601
+ expect(screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
602
+ expect(screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i }).parentElement).toHaveClass('pf-chatbot__message-and-actions');
603
+ });
598
604
  it('should handle external links correctly', () => {
599
605
  render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: `[PatternFly](https://www.patternfly.org/)` }));
600
606
  // we are mocking rehype libraries, so we can't test target _blank addition on links directly with RTL
@@ -0,0 +1,2 @@
1
+ import { Node } from 'unist';
2
+ export declare const rehypeMoveImagesOutOfParagraphs: () => (tree: Node) => void;
@@ -0,0 +1,43 @@
1
+ import { visit } from 'unist-util-visit';
2
+ // Rehype plugin to remove images from within p tags and put them as separate block-level elements.
3
+ // This allows us to avoid having a blue background on images - this is something Kayla requested.
4
+ export const rehypeMoveImagesOutOfParagraphs = () => (tree) => {
5
+ const nodesToRemove = [];
6
+ visit(tree, 'element', (node, index, parent) => {
7
+ if (node.tagName === 'p' && node.children) {
8
+ const imagesInParagraph = [];
9
+ node.children.forEach((child, childIndex) => {
10
+ if (child.type === 'element' && child.tagName === 'img') {
11
+ imagesInParagraph.push({ node: child, index: childIndex });
12
+ }
13
+ });
14
+ if (imagesInParagraph.length > 0 && parent && index !== null) {
15
+ imagesInParagraph.forEach(({ node: imgNode, index: imgIndex }) => {
16
+ nodesToRemove.push({ parent: node, index: imgIndex, node: imgNode });
17
+ });
18
+ // To avoid issues with index shifting during removal, we process in reverse
19
+ for (let i = nodesToRemove.length - 1; i >= 0; i--) {
20
+ const { parent: pTag, index: imgIndexToRemove } = nodesToRemove[i];
21
+ if (pTag.children) {
22
+ pTag.children.splice(imgIndexToRemove, 1);
23
+ }
24
+ }
25
+ // Insert the removed images after the paragraph
26
+ const paragraphIndexInParent = parent.children.indexOf(node);
27
+ if (paragraphIndexInParent !== -1) {
28
+ imagesInParagraph.forEach(({ node: imgNode }) => {
29
+ parent.children.splice(paragraphIndexInParent + 1, 0, imgNode);
30
+ });
31
+ }
32
+ // Remove paragraph if it's now empty after image removal
33
+ if (node.children.length === 0) {
34
+ const paragraphIndexInParent = parent.children.indexOf(node);
35
+ if (paragraphIndexInParent !== -1) {
36
+ parent.children.splice(paragraphIndexInParent, 1);
37
+ }
38
+ }
39
+ nodesToRemove.length = 0;
40
+ }
41
+ }
42
+ });
43
+ };
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.3.0-prerelease.16",
3
+ "version": "6.3.0-prerelease.17",
4
4
  "description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -45,7 +45,8 @@
45
45
  "rehype-unwrap-images": "^1.0.0",
46
46
  "rehype-external-links": "^3.0.0",
47
47
  "rehype-sanitize": "^6.0.0",
48
- "path-browserify": "^1.0.1"
48
+ "path-browserify": "^1.0.1",
49
+ "unist-util-visit": "^5.0.0"
49
50
  },
50
51
  "peerDependencies": {
51
52
  "react": "^17 || ^18 || ^19",
@@ -142,6 +142,8 @@ const EMPTY_TABLE = `
142
142
 
143
143
  const IMAGE = `![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
144
144
 
145
+ const INLINE_IMAGE = `inline text ![Multi-colored wavy lines on a black background](https://cdn.dribbble.com/userupload/10651749/file/original-8a07b8e39d9e8bf002358c66fce1223e.gif)`;
146
+
145
147
  const ERROR = {
146
148
  title: 'Could not load chat',
147
149
  children: 'Wait a few minutes and check your network settings. If the issue persists: ',
@@ -787,6 +789,13 @@ describe('Message', () => {
787
789
  render(<Message avatar="./img" role="user" name="User" content={IMAGE} />);
788
790
  expect(screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
789
791
  });
792
+ it('inline image parent should have class pf-chatbot__message-and-actions', () => {
793
+ render(<Message avatar="./img" role="user" name="User" content={INLINE_IMAGE} />);
794
+ expect(screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i })).toBeTruthy();
795
+ expect(
796
+ screen.getByRole('img', { name: /Multi-colored wavy lines on a black background/i }).parentElement
797
+ ).toHaveClass('pf-chatbot__message-and-actions');
798
+ });
790
799
  it('should handle external links correctly', () => {
791
800
  render(<Message avatar="./img" role="user" name="User" content={`[PatternFly](https://www.patternfly.org/)`} />);
792
801
  // we are mocking rehype libraries, so we can't test target _blank addition on links directly with RTL
@@ -46,6 +46,7 @@ import { PluggableList } from 'react-markdown/lib';
46
46
  import LinkMessage from './LinkMessage/LinkMessage';
47
47
  import ErrorMessage from './ErrorMessage/ErrorMessage';
48
48
  import MessageInput from './MessageInput';
49
+ import { rehypeMoveImagesOutOfParagraphs } from './Plugins/rehypeMoveImagesOutOfParagraphs';
49
50
 
50
51
  export interface MessageAttachment {
51
52
  /** Name of file attached to the message */
@@ -212,7 +213,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
212
213
  }, [content]);
213
214
 
214
215
  const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
215
- let rehypePlugins: PluggableList = [rehypeUnwrapImages];
216
+ let rehypePlugins: PluggableList = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs];
216
217
  if (openLinkInNewTab) {
217
218
  rehypePlugins = rehypePlugins.concat([[rehypeExternalLinks, { target: '_blank' }, rehypeSanitize]]);
218
219
  }
@@ -0,0 +1,53 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import { Element } from 'hast';
3
+ import { Node } from 'unist';
4
+
5
+ // Rehype plugin to remove images from within p tags and put them as separate block-level elements.
6
+ // This allows us to avoid having a blue background on images - this is something Kayla requested.
7
+ export const rehypeMoveImagesOutOfParagraphs = () => (tree: Node) => {
8
+ const nodesToRemove: { parent: Element; index: number; node: Element }[] = [];
9
+
10
+ visit(tree, 'element', (node: Element, index: number | null, parent: Element | null) => {
11
+ if (node.tagName === 'p' && node.children) {
12
+ const imagesInParagraph: { node: Element; index: number }[] = [];
13
+
14
+ node.children.forEach((child: Node, childIndex: number) => {
15
+ if (child.type === 'element' && (child as Element).tagName === 'img') {
16
+ imagesInParagraph.push({ node: child as Element, index: childIndex });
17
+ }
18
+ });
19
+
20
+ if (imagesInParagraph.length > 0 && parent && index !== null) {
21
+ imagesInParagraph.forEach(({ node: imgNode, index: imgIndex }) => {
22
+ nodesToRemove.push({ parent: node, index: imgIndex, node: imgNode });
23
+ });
24
+
25
+ // To avoid issues with index shifting during removal, we process in reverse
26
+ for (let i = nodesToRemove.length - 1; i >= 0; i--) {
27
+ const { parent: pTag, index: imgIndexToRemove } = nodesToRemove[i];
28
+ if (pTag.children) {
29
+ pTag.children.splice(imgIndexToRemove, 1);
30
+ }
31
+ }
32
+
33
+ // Insert the removed images after the paragraph
34
+ const paragraphIndexInParent = parent.children.indexOf(node);
35
+ if (paragraphIndexInParent !== -1) {
36
+ imagesInParagraph.forEach(({ node: imgNode }) => {
37
+ parent.children.splice(paragraphIndexInParent + 1, 0, imgNode);
38
+ });
39
+ }
40
+
41
+ // Remove paragraph if it's now empty after image removal
42
+ if (node.children.length === 0) {
43
+ const paragraphIndexInParent = parent.children.indexOf(node);
44
+ if (paragraphIndexInParent !== -1) {
45
+ parent.children.splice(paragraphIndexInParent, 1);
46
+ }
47
+ }
48
+
49
+ nodesToRemove.length = 0;
50
+ }
51
+ }
52
+ });
53
+ };