@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.
- package/dist/cjs/Message/Message.js +2 -1
- package/dist/cjs/Message/Message.test.js +6 -0
- package/dist/cjs/Message/Plugins/rehypeMoveImagesOutOfParagraphs.d.ts +2 -0
- package/dist/cjs/Message/Plugins/rehypeMoveImagesOutOfParagraphs.js +47 -0
- package/dist/esm/Message/Message.js +2 -1
- package/dist/esm/Message/Message.test.js +6 -0
- package/dist/esm/Message/Plugins/rehypeMoveImagesOutOfParagraphs.d.ts +2 -0
- package/dist/esm/Message/Plugins/rehypeMoveImagesOutOfParagraphs.js +43 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/Message/Message.test.tsx +9 -0
- package/src/Message/Message.tsx +2 -1
- package/src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts +53 -0
@@ -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 = ``;
|
144
|
+
const INLINE_IMAGE = `inline text `;
|
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,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 = ``;
|
139
|
+
const INLINE_IMAGE = `inline text `;
|
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,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.
|
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 = ``;
|
144
144
|
|
145
|
+
const INLINE_IMAGE = `inline text `;
|
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
|
package/src/Message/Message.tsx
CHANGED
@@ -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
|
+
};
|