@patternfly/chatbot 6.8.0-prerelease.3 → 6.8.0-prerelease.4
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/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -5
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +3 -3
- package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.js +1 -1
- package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.js +2 -2
- package/dist/cjs/MarkdownContent/MarkdownContent.js +15 -1
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
- package/dist/cjs/Message/LinkMessage/LinkMessage.js +5 -1
- package/dist/cjs/Message/Message.test.js +3 -1
- package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.js +2 -5
- package/dist/cjs/MessageBox/JumpButton.test.js +2 -2
- package/dist/cjs/MessageBox/MessageBox.js +79 -28
- package/dist/cjs/MessageBox/MessageBox.test.d.ts +1 -1
- package/dist/cjs/MessageBox/MessageBox.test.js +59 -0
- package/dist/cjs/ResponseActions/ResponseActionButton.test.js +6 -6
- package/dist/cjs/ResponseActions/ResponseActions.test.js +6 -7
- package/dist/cjs/index.d.ts +0 -2
- package/dist/cjs/index.js +1 -4
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +4 -4
- package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.js +2 -2
- package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.js +2 -2
- package/dist/esm/MarkdownContent/MarkdownContent.js +15 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
- package/dist/esm/Message/LinkMessage/LinkMessage.js +6 -2
- package/dist/esm/Message/Message.test.js +3 -1
- package/dist/esm/Message/QuickStarts/QuickStartTileDescription.js +2 -2
- package/dist/esm/MessageBox/JumpButton.test.js +2 -2
- package/dist/esm/MessageBox/MessageBox.js +80 -29
- package/dist/esm/MessageBox/MessageBox.test.d.ts +1 -1
- package/dist/esm/MessageBox/MessageBox.test.js +59 -0
- package/dist/esm/ResponseActions/ResponseActionButton.test.js +7 -7
- package/dist/esm/ResponseActions/ResponseActions.test.js +7 -8
- package/dist/esm/index.d.ts +0 -2
- package/dist/esm/index.js +0 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomResponseActions.tsx +3 -4
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolResponse.tsx +3 -3
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickResponses.tsx +3 -3
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +5 -5
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +7 -31
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx +4 -6
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +3 -3
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx +2 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +2 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSearchActions.tsx +3 -3
- package/patternfly-docs/content/extensions/chatbot/examples/UI/CompactSettings.tsx +10 -5
- package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +10 -5
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +1 -15
- package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +1 -3
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +2 -5
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx +4 -7
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachment.tsx +4 -6
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotCompact.tsx +4 -7
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotDisplayMode.tsx +4 -7
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotScrolling.tsx +4 -8
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +4 -7
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +2 -3
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +4 -4
- package/src/ChatbotHeader/ChatbotHeaderCloseButton.tsx +2 -2
- package/src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx +2 -3
- package/src/MarkdownContent/MarkdownContent.tsx +14 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +2 -2
- package/src/Message/LinkMessage/LinkMessage.tsx +21 -2
- package/src/Message/Message.test.tsx +3 -1
- package/src/Message/QuickStarts/QuickStartTileDescription.tsx +2 -2
- package/src/MessageBox/JumpButton.test.tsx +1 -1
- package/src/MessageBox/MessageBox.test.tsx +91 -0
- package/src/MessageBox/MessageBox.tsx +137 -40
- package/src/ResponseActions/ResponseActionButton.test.tsx +7 -7
- package/src/ResponseActions/ResponseActions.test.tsx +7 -8
- package/dist/cjs/LoadingMessage/LoadingMessage.d.ts +0 -6
- package/dist/cjs/LoadingMessage/LoadingMessage.js +0 -12
- package/dist/cjs/LoadingMessage/LoadingMessage.test.d.ts +0 -1
- package/dist/cjs/LoadingMessage/LoadingMessage.test.js +0 -20
- package/dist/cjs/LoadingMessage/index.d.ts +0 -2
- package/dist/cjs/LoadingMessage/index.js +0 -23
- package/dist/dynamic/LoadingMessage/package.json +0 -1
- package/dist/esm/LoadingMessage/LoadingMessage.d.ts +0 -6
- package/dist/esm/LoadingMessage/LoadingMessage.js +0 -5
- package/dist/esm/LoadingMessage/LoadingMessage.test.d.ts +0 -1
- package/dist/esm/LoadingMessage/LoadingMessage.test.js +0 -15
- package/dist/esm/LoadingMessage/index.d.ts +0 -2
- package/dist/esm/LoadingMessage/index.js +0 -2
- package/src/LoadingMessage/LoadingMessage.test.tsx +0 -15
- package/src/LoadingMessage/LoadingMessage.tsx +0 -27
- package/src/LoadingMessage/__snapshots__/LoadingMessage.test.tsx.snap +0 -64
- package/src/LoadingMessage/index.ts +0 -3
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.ChatbotConversationHistoryDropdown = void 0;
|
|
7
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
5
|
const react_1 = require("react");
|
|
9
6
|
// Import PatternFly components
|
|
10
7
|
const react_core_1 = require("@patternfly/react-core");
|
|
11
|
-
const
|
|
8
|
+
const rh_ui_ellipsis_vertical_fill_icon_1 = require("@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon");
|
|
12
9
|
const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label = 'Conversation options', 'aria-label': ariaLabel, id }) => {
|
|
13
10
|
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
14
11
|
const toggle = (toggleRef) => ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label, position: "bottom",
|
|
15
12
|
// prevents VO announcements of both aria label and tooltip
|
|
16
|
-
aria: "none", children: (0, jsx_runtime_1.jsx)(react_core_1.MenuToggle, { className: "pf-chatbot__history-actions", variant: "plain", "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label, ref: toggleRef, isExpanded: isOpen, onClick: () => setIsOpen(!isOpen), id: id, role: "menuitem", children: (0, jsx_runtime_1.jsx)(
|
|
13
|
+
aria: "none", children: (0, jsx_runtime_1.jsx)(react_core_1.MenuToggle, { className: "pf-chatbot__history-actions", variant: "plain", "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label, ref: toggleRef, isExpanded: isOpen, onClick: () => setIsOpen(!isOpen), id: id, role: "menuitem", children: (0, jsx_runtime_1.jsx)(rh_ui_ellipsis_vertical_fill_icon_1.RhUiEllipsisVerticalFillIcon, {}) }) }));
|
|
17
14
|
return ((0, jsx_runtime_1.jsx)(react_core_1.Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
|
|
18
15
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
|
19
16
|
setIsOpen((prev) => !prev);
|
|
@@ -25,7 +25,7 @@ const ChatbotConversationHistoryDropdown_1 = __importDefault(require("./ChatbotC
|
|
|
25
25
|
const LoadingState_1 = __importDefault(require("./LoadingState"));
|
|
26
26
|
const EmptyState_1 = __importDefault(require("./EmptyState"));
|
|
27
27
|
const ChatbotConversationHistoryNav = (_a) => {
|
|
28
|
-
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, menuListProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Search previous conversations', searchInputProps, handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, hasDrawerHeadDivider, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history', navTitleProps, navTitleIcon = (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
28
|
+
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, menuListProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Search previous conversations', searchInputProps, handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, hasDrawerHeadDivider, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history', navTitleProps, navTitleIcon = (0, jsx_runtime_1.jsx)(react_icons_1.RhUiClockIcon, {}), searchInputScreenReaderText, searchActionStart, searchActionEnd, searchToolbar, menuProps, menuGroupProps, menuContentProps } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "menuListProps", "newChatButtonText", "drawerContent", "onNewChat", "newChatButtonProps", "searchInputPlaceholder", "searchInputAriaLabel", "searchInputProps", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId", "drawerPanelContentProps", "drawerContentProps", "drawerContentBodyProps", "drawerHeadProps", "drawerActionsProps", "drawerCloseButtonProps", "drawerPanelBodyProps", "hasDrawerHeadDivider", "isLoading", "loadingState", "errorState", "emptyState", "noResultsState", "isCompact", "title", "navTitleProps", "navTitleIcon", "searchInputScreenReaderText", "searchActionStart", "searchActionEnd", "searchToolbar", "menuProps", "menuGroupProps", "menuContentProps"]);
|
|
29
29
|
const drawerRef = (0, react_1.useRef)(null);
|
|
30
30
|
const onExpand = () => {
|
|
31
31
|
drawerRef.current && drawerRef.current.focus();
|
|
@@ -33,7 +33,7 @@ const ChatbotConversationHistoryNav = (_a) => {
|
|
|
33
33
|
const isConversation = (item) => item && typeof item === 'object' && 'id' in item && 'text' in item;
|
|
34
34
|
const getNavItem = (conversation) => {
|
|
35
35
|
var _a;
|
|
36
|
-
return ((0, jsx_runtime_1.jsx)(react_core_1.MenuItem, Object.assign({ className: `pf-chatbot__menu-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__menu-item--active' : ''}`, itemId: conversation.id }, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
36
|
+
return ((0, jsx_runtime_1.jsx)(react_core_1.MenuItem, Object.assign({ className: `pf-chatbot__menu-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__menu-item--active' : ''}`, itemId: conversation.id }, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : (0, jsx_runtime_1.jsx)(react_icons_1.RhUiCommentIcon, {}) }), (conversation.menuItems
|
|
37
37
|
? {
|
|
38
38
|
actions: ((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryDropdown_1.default, { menuClassName: conversation.menuClassName, onSelect: conversation.onSelect, menuItems: conversation.menuItems, label: conversation.label }))
|
|
39
39
|
}
|
|
@@ -78,7 +78,7 @@ const ChatbotConversationHistoryNav = (_a) => {
|
|
|
78
78
|
return searchActionStart || searchActionEnd ? ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__history-search-actions", children: (0, jsx_runtime_1.jsxs)(react_core_1.InputGroup, { children: [searchActionStart && (0, jsx_runtime_1.jsx)(react_core_1.InputGroupItem, { children: searchActionStart }), searchInputContainer && (0, jsx_runtime_1.jsx)(react_core_1.InputGroupItem, { isFill: true, children: searchInputContainer }), searchActionEnd && (0, jsx_runtime_1.jsx)(react_core_1.InputGroupItem, { children: searchActionEnd })] }) })) : (searchInputContainer);
|
|
79
79
|
};
|
|
80
80
|
const renderPanelContent = () => {
|
|
81
|
-
const drawer = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerHead, Object.assign({}, drawerHeadProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
81
|
+
const drawer = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerHead, Object.assign({}, drawerHeadProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiEditFillIcon, {}) }, newChatButtonProps, { children: newChatButtonText })))] })) })), hasDrawerHeadDivider && (0, jsx_runtime_1.jsx)(react_core_1.Divider, { className: "pf-chatbot__heading-divider" }), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__heading-container", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__title-container", children: [(0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: "lg", className: "pf-chatbot__title-icon", children: navTitleIcon }), (0, jsx_runtime_1.jsx)(react_core_1.Title, Object.assign({ className: "pf-chatbot__title", headingLevel: "h2" }, navTitleProps, { children: title }))] }), !isLoading && renderSearchAndActions()] }), isLoading ? (0, jsx_runtime_1.jsx)(LoadingState_1.default, Object.assign({}, loadingState)) : renderDrawerContent()] }));
|
|
82
82
|
return ((0, jsx_runtime_1.jsx)(react_core_1.DrawerPanelContent, Object.assign({ "aria-live": "polite", focusTrap: { enabled: true }, defaultSize: "384px" }, drawerPanelContentProps, { children: drawer })));
|
|
83
83
|
};
|
|
84
84
|
// An onKeyDown property must be passed to the Drawer component to handle closing
|
|
@@ -20,6 +20,6 @@ const ChatbotHeaderCloseButtonBase = (_a) => {
|
|
|
20
20
|
var { className, onClick, tooltipProps, menuAriaLabel = 'Close', innerRef, tooltipContent = 'Close', isCompact } = _a, props = __rest(_a, ["className", "onClick", "tooltipProps", "menuAriaLabel", "innerRef", "tooltipContent", "isCompact"]);
|
|
21
21
|
return ((0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__menu${className ? ` ${className}` : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
|
|
22
22
|
// prevents VO announcements of both aria label and tooltip
|
|
23
|
-
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onClick, "aria-label": menuAriaLabel, ref: innerRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
23
|
+
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onClick, "aria-label": menuAriaLabel, ref: innerRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(react_icons_1.RhMicronsCloseIcon, {}) }), size: isCompact ? 'sm' : undefined }, props)) })) }));
|
|
24
24
|
};
|
|
25
25
|
exports.ChatbotHeaderCloseButton = (0, react_1.forwardRef)((props, ref) => ((0, jsx_runtime_1.jsx)(ChatbotHeaderCloseButtonBase, Object.assign({ innerRef: ref }, props))));
|
|
@@ -15,11 +15,11 @@ exports.ChatbotHeaderNewChatButton = void 0;
|
|
|
15
15
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
16
|
const react_1 = require("react");
|
|
17
17
|
const react_core_1 = require("@patternfly/react-core");
|
|
18
|
-
const
|
|
18
|
+
const rh_ui_edit_fill_icon_1 = require("@patternfly/react-icons/dist/esm/icons/rh-ui-edit-fill-icon");
|
|
19
19
|
const ChatbotHeaderNewChatButtonBase = (_a) => {
|
|
20
20
|
var { className, onClick, tooltipProps, menuAriaLabel = 'New chat', innerRef, tooltipContent = 'New chat', isCompact } = _a, props = __rest(_a, ["className", "onClick", "tooltipProps", "menuAriaLabel", "innerRef", "tooltipContent", "isCompact"]);
|
|
21
21
|
return ((0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__menu${className ? ` ${className}` : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
|
|
22
22
|
// prevents VO announcements of both aria label and tooltip
|
|
23
|
-
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onClick, "aria-label": menuAriaLabel, ref: innerRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(
|
|
23
|
+
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: `pf-chatbot__button--toggle-menu ${isCompact ? 'pf-m-compact' : ''}`, variant: "plain", onClick: onClick, "aria-label": menuAriaLabel, ref: innerRef, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: isCompact ? 'lg' : 'xl', isInline: true, children: (0, jsx_runtime_1.jsx)(rh_ui_edit_fill_icon_1.RhUiEditFillIcon, {}) }), size: isCompact ? 'sm' : undefined }, props)) })) }));
|
|
24
24
|
};
|
|
25
25
|
exports.ChatbotHeaderNewChatButton = (0, react_1.forwardRef)((props, ref) => ((0, jsx_runtime_1.jsx)(ChatbotHeaderNewChatButtonBase, Object.assign({ innerRef: ref }, props))));
|
|
@@ -175,7 +175,21 @@ const MarkdownContent = ({ content, isMarkdownDisabled, codeBlockProps, tablePro
|
|
|
175
175
|
}
|
|
176
176
|
}, remarkPlugins: [[remark_gfm_1.default, Object.assign({}, remarkGfmProps)], ...additionalRemarkPlugins], rehypePlugins: rehypePlugins }, reactMarkdownProps, { remarkRehypeOptions: Object.assign({
|
|
177
177
|
// removes sr-only class from footnote labels applied by default
|
|
178
|
-
footnoteLabelProperties: { className: [''] }
|
|
178
|
+
footnoteLabelProperties: { className: [''] },
|
|
179
|
+
// omit default ↩ text; backref icon is rendered in LinkMessage
|
|
180
|
+
footnoteBackContent: (_referenceIndex, rereferenceIndex) => {
|
|
181
|
+
if (rereferenceIndex > 1) {
|
|
182
|
+
return [
|
|
183
|
+
{
|
|
184
|
+
type: 'element',
|
|
185
|
+
tagName: 'sup',
|
|
186
|
+
properties: {},
|
|
187
|
+
children: [{ type: 'text', value: String(rereferenceIndex) }]
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
return [];
|
|
192
|
+
} }, reactMarkdownProps === null || reactMarkdownProps === void 0 ? void 0 : reactMarkdownProps.remarkRehypeOptions), disallowedElements: disallowedElements, children: content })));
|
|
179
193
|
};
|
|
180
194
|
exports.MarkdownContent = MarkdownContent;
|
|
181
195
|
exports.default = exports.MarkdownContent;
|
|
@@ -19,8 +19,8 @@ const react_1 = require("react");
|
|
|
19
19
|
// Import PatternFly components
|
|
20
20
|
const react_core_1 = require("@patternfly/react-core");
|
|
21
21
|
const check_icon_1 = require("@patternfly/react-icons/dist/esm/icons/check-icon");
|
|
22
|
-
const copy_icon_1 = require("@patternfly/react-icons/dist/esm/icons/copy-icon");
|
|
23
22
|
const react_styles_1 = require("@patternfly/react-styles");
|
|
23
|
+
const react_icons_1 = require("@patternfly/react-icons");
|
|
24
24
|
const DEFAULT_EXPANDED_TEXT = 'Show less';
|
|
25
25
|
const DEFAULT_COLLAPSED_TEXT = 'Show more';
|
|
26
26
|
const CodeBlockMessage = (_a) => {
|
|
@@ -75,7 +75,7 @@ const CodeBlockMessage = (_a) => {
|
|
|
75
75
|
return ((0, jsx_runtime_1.jsx)("code", Object.assign({}, props, { className: `pf-chatbot__message-inline-code ${isPrimary ? 'pf-m-primary' : ''}`, children: children })));
|
|
76
76
|
}
|
|
77
77
|
// Setup code block header
|
|
78
|
-
const actions = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_core_1.CodeBlockAction, { className: "pf-chatbot__message-code-block-default-action", children: [language && (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-code-block-language", children: language }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { ref: buttonRef, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : 'Copy code', variant: "plain", className: "pf-chatbot__button--copy", onClick: (event) => handleCopy(event, children), children: copied ? (0, jsx_runtime_1.jsx)(check_icon_1.CheckIcon, {}) : (0, jsx_runtime_1.jsx)(
|
|
78
|
+
const actions = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_core_1.CodeBlockAction, { className: "pf-chatbot__message-code-block-default-action", children: [language && (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-code-block-language", children: language }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { ref: buttonRef, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : 'Copy code', variant: "plain", className: "pf-chatbot__button--copy", onClick: (event) => handleCopy(event, children), children: copied ? (0, jsx_runtime_1.jsx)(check_icon_1.CheckIcon, {}) : (0, jsx_runtime_1.jsx)(react_icons_1.RhUiCopyFillIcon, {}) }), (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { id: tooltipID, content: "Copy", position: "top", triggerRef: buttonRef })] }), customActions] }));
|
|
79
79
|
return ((0, jsx_runtime_1.jsx)("div", { className: (0, react_styles_1.css)('pf-chatbot__message-code-block', shouldRetainStyles && 'pf-m-markdown'), ref: codeBlockRef, children: (0, jsx_runtime_1.jsxs)(react_core_1.CodeBlock, { actions: actions, children: [(0, jsx_runtime_1.jsx)(react_core_1.CodeBlockCode, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: isExpandable ? ((0, jsx_runtime_1.jsx)(react_core_1.ExpandableSection, Object.assign({ variant: react_core_1.ExpandableSectionVariant.truncate, isExpanded: isExpanded, isDetached: true, toggleId: toggleId, contentId: contentId }, expandableSectionProps, { children: children }))) : (children) }) }), isExpandable && ((0, jsx_runtime_1.jsx)(react_core_1.ExpandableSectionToggle, Object.assign({ isExpanded: isExpanded, onToggle: onToggle, direction: "up", toggleId: toggleId, contentId: contentId, hasTruncatedContent: true, className: "pf-chatbot__message-code-toggle" }, expandableSectionToggleProps, { children: isExpanded ? finalExpandedText : finalCollapsedText })))] }) }));
|
|
80
80
|
};
|
|
81
81
|
exports.default = CodeBlockMessage;
|
|
@@ -18,13 +18,17 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
18
18
|
const react_core_1 = require("@patternfly/react-core");
|
|
19
19
|
const react_icons_1 = require("@patternfly/react-icons");
|
|
20
20
|
const react_styles_1 = require("@patternfly/react-styles");
|
|
21
|
+
const isFootnoteBackref = (className) => className === null || className === void 0 ? void 0 : className.includes('data-footnote-backref');
|
|
21
22
|
const LinkMessage = (_a) => {
|
|
22
23
|
var { children, target, href, id, shouldRetainStyles } = _a, props = __rest(_a, ["children", "target", "href", "id", "shouldRetainStyles"]);
|
|
23
24
|
if (target === '_blank') {
|
|
24
|
-
return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: "link", href: href, icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
25
|
+
return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ component: "a", variant: "link", href: href, icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhMicronsExternalLinkIcon, {}), iconPosition: "end", isInline: true, target: target,
|
|
25
26
|
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
26
27
|
id: id }, props, { className: (0, react_styles_1.css)(shouldRetainStyles && 'pf-m-markdown', props === null || props === void 0 ? void 0 : props.className), children: children })));
|
|
27
28
|
}
|
|
29
|
+
if (isFootnoteBackref(props.className)) {
|
|
30
|
+
return ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ isInline: true, component: "a", href: href, variant: "link", id: id, icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiBackwardsIcon, {}) }, props, { className: (0, react_styles_1.css)(shouldRetainStyles && 'pf-m-markdown', props === null || props === void 0 ? void 0 : props.className), children: children })));
|
|
31
|
+
}
|
|
28
32
|
return (
|
|
29
33
|
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
30
34
|
(0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ isInline: true, component: "a", href: href, variant: "link", id: id }, props, { className: (0, react_styles_1.css)(shouldRetainStyles && 'pf-m-markdown', props === null || props === void 0 ? void 0 : props.className), children: children })));
|
|
@@ -36,10 +36,12 @@ jest.mock('@patternfly/react-icons', () => ({
|
|
|
36
36
|
RhUiVolumeUpFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiVolumeUpFillIcon" }),
|
|
37
37
|
RhUiExportIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiExportIcon" }),
|
|
38
38
|
RhUiExportFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiExportFillIcon" }),
|
|
39
|
+
RhMicronsInformationFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhMicronsInformationFillIcon" }),
|
|
39
40
|
CheckIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "CheckIcon" }),
|
|
40
41
|
CloseIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "CloseIcon" }),
|
|
41
42
|
ExternalLinkSquareAltIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "ExternalLinkSquareAltIcon" }),
|
|
42
|
-
TimesIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "TimesIcon" })
|
|
43
|
+
TimesIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "TimesIcon" }),
|
|
44
|
+
RhUiBackwardsIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiBackwardsIcon" })
|
|
43
45
|
}));
|
|
44
46
|
const ALL_ACTIONS = [
|
|
45
47
|
{ label: /Good response/i },
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.pluralizeWord = pluralizeWord;
|
|
7
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
5
|
const react_1 = require("react");
|
|
9
6
|
const react_core_1 = require("@patternfly/react-core");
|
|
10
|
-
const
|
|
7
|
+
const react_icons_1 = require("@patternfly/react-icons");
|
|
11
8
|
/** This function is a helper for pluralizing strings stolen from React.
|
|
12
9
|
*
|
|
13
10
|
* @param {number} i The quantity of the string you want to pluralize
|
|
@@ -28,7 +25,7 @@ const QuickStartTileDescription = ({ description, prerequisites, prerequisiteWor
|
|
|
28
25
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [description, prereqs && prereqs.length > 0 && ((0, jsx_runtime_1.jsxs)(react_core_1.Flex, { spaceItems: { default: 'spaceItemsSm' }, children: [(0, jsx_runtime_1.jsx)("h5", { children: (0, react_core_1.pluralize)(prereqs.length, prerequisiteWord, prerequisiteWordPlural) }), (0, jsx_runtime_1.jsx)(react_core_1.Button, { variant: "link", isInline: true, "data-testid": "qs-card-prereqs", ref: buttonRef, onClick: (e) => {
|
|
29
26
|
e.preventDefault();
|
|
30
27
|
e.stopPropagation();
|
|
31
|
-
}, "aria-label": quickStartButtonAriaLabel, children: (0, jsx_runtime_1.jsx)(
|
|
28
|
+
}, "aria-label": quickStartButtonAriaLabel, children: (0, jsx_runtime_1.jsx)(react_icons_1.RhMicronsInformationFillIcon, {}) }), (0, jsx_runtime_1.jsx)(react_core_1.Popover, { "aria-label": pluralizedPrereq, headerContent: pluralizedPrereq, triggerRef: buttonRef, bodyContent: (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("ul", { "aria-label": pluralizedPrereq, children: prereqs.map((prerequisite, index) => (
|
|
32
29
|
// eslint-disable-next-line react/no-array-index-key
|
|
33
30
|
(0, jsx_runtime_1.jsx)("li", { children: prerequisite }, index))) }) }) })] }))] }));
|
|
34
31
|
};
|
|
@@ -32,8 +32,8 @@ describe('JumpButton', () => {
|
|
|
32
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
|
-
it('should be hidden if isHidden prop is used', () =>
|
|
35
|
+
it('should be hidden if isHidden prop is used', () => {
|
|
36
36
|
(0, react_1.render)((0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", onClick: jest.fn(), isHidden: true }));
|
|
37
37
|
expect(react_1.screen.queryByRole('button', { name: /Back to bottom/i })).toBeFalsy();
|
|
38
|
-
})
|
|
38
|
+
});
|
|
39
39
|
});
|
|
@@ -21,48 +21,77 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
21
21
|
// ============================================================================
|
|
22
22
|
const react_1 = require("react");
|
|
23
23
|
const JumpButton_1 = __importDefault(require("./JumpButton"));
|
|
24
|
+
const react_core_1 = require("@patternfly/react-core");
|
|
25
|
+
const SCROLL_EDGE_DELTA = 100;
|
|
26
|
+
const getScrollMetrics = (element) => {
|
|
27
|
+
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
28
|
+
const roundedScrollTop = Math.round(scrollTop);
|
|
29
|
+
const roundedClientHeight = Math.round(clientHeight);
|
|
30
|
+
const roundedScrollHeight = Math.round(scrollHeight);
|
|
31
|
+
const distanceFromBottom = roundedScrollHeight - roundedScrollTop - roundedClientHeight;
|
|
32
|
+
return {
|
|
33
|
+
roundedScrollTop,
|
|
34
|
+
roundedClientHeight,
|
|
35
|
+
roundedScrollHeight,
|
|
36
|
+
distanceFromBottom,
|
|
37
|
+
atTop: roundedScrollTop === 0,
|
|
38
|
+
nearBottom: distanceFromBottom <= SCROLL_EDGE_DELTA,
|
|
39
|
+
isOverflowing: roundedScrollHeight >= roundedClientHeight
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const isAtBottomEdge = (metrics, enableSmartScroll, autoScroll, pauseAutoScroll, programmaticScroll = false) => metrics.nearBottom ||
|
|
43
|
+
programmaticScroll ||
|
|
44
|
+
(enableSmartScroll && autoScroll && !pauseAutoScroll && metrics.roundedScrollTop > 0);
|
|
45
|
+
const shouldFollowContentGrowth = (metrics, enableSmartScroll, autoScroll, pauseAutoScroll, programmaticScroll) => programmaticScroll ||
|
|
46
|
+
metrics.nearBottom ||
|
|
47
|
+
(enableSmartScroll && autoScroll && !pauseAutoScroll && metrics.roundedScrollTop > 0);
|
|
24
48
|
exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
25
49
|
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
|
-
const [atTop, setAtTop] = (0, react_1.useState)(
|
|
27
|
-
const [atBottom, setAtBottom] = (0, react_1.useState)(
|
|
50
|
+
const [atTop, setAtTop] = (0, react_1.useState)(true);
|
|
51
|
+
const [atBottom, setAtBottom] = (0, react_1.useState)(false);
|
|
28
52
|
const [isOverflowing, setIsOverflowing] = (0, react_1.useState)(false);
|
|
53
|
+
const [hasMeasuredScroll, setHasMeasuredScroll] = (0, react_1.useState)(false);
|
|
29
54
|
const [autoScroll, setAutoScroll] = (0, react_1.useState)(true);
|
|
55
|
+
const autoScrollRef = (0, react_1.useRef)(autoScroll);
|
|
30
56
|
const lastScrollTop = (0, react_1.useRef)(0);
|
|
31
57
|
const animationFrame = (0, react_1.useRef)(null);
|
|
32
58
|
const debounceTimeout = (0, react_1.useRef)(null);
|
|
33
59
|
const pauseAutoScrollRef = (0, react_1.useRef)(false);
|
|
60
|
+
const programmaticScrollRef = (0, react_1.useRef)(false);
|
|
34
61
|
const messageBoxRef = (0, react_1.useRef)(null);
|
|
35
62
|
const scrollQueued = (0, react_1.useRef)(false);
|
|
36
63
|
const resetUserScrollIntentTimeout = (0, react_1.useRef)();
|
|
64
|
+
autoScrollRef.current = autoScroll;
|
|
37
65
|
// Configure handlers
|
|
38
66
|
const handleScroll = (0, react_1.useCallback)(() => {
|
|
39
67
|
const element = messageBoxRef.current;
|
|
40
68
|
if (!element) {
|
|
41
69
|
return;
|
|
42
70
|
}
|
|
43
|
-
const
|
|
44
|
-
const roundedScrollTop =
|
|
45
|
-
const roundedClientHeight = Math.round(clientHeight);
|
|
46
|
-
const roundedScrollHeight = Math.round(scrollHeight);
|
|
47
|
-
const distanceFromBottom = roundedScrollHeight - roundedScrollTop - roundedClientHeight;
|
|
71
|
+
const metrics = getScrollMetrics(element);
|
|
72
|
+
const { roundedScrollTop, distanceFromBottom } = metrics;
|
|
48
73
|
const isScrollingDown = roundedScrollTop > lastScrollTop.current;
|
|
49
74
|
const DELTA_UP = 10;
|
|
50
75
|
const DELTA_DOWN = 50;
|
|
51
76
|
const DEBOUNCE_DELAY = 200;
|
|
52
77
|
const delta = isScrollingDown ? DELTA_DOWN : DELTA_UP;
|
|
53
78
|
const isAtBottom = distanceFromBottom <= delta;
|
|
54
|
-
setAtTop(
|
|
55
|
-
setAtBottom(
|
|
79
|
+
setAtTop(metrics.atTop);
|
|
80
|
+
setAtBottom(isAtBottomEdge(metrics, enableSmartScroll, autoScrollRef.current, pauseAutoScrollRef.current, programmaticScrollRef.current));
|
|
81
|
+
setIsOverflowing(metrics.isOverflowing);
|
|
82
|
+
if (isAtBottom) {
|
|
83
|
+
programmaticScrollRef.current = false;
|
|
84
|
+
}
|
|
56
85
|
if (!enableSmartScroll || scrollQueued.current) {
|
|
57
86
|
return;
|
|
58
87
|
}
|
|
59
|
-
if (roundedScrollTop === 0) {
|
|
88
|
+
if (metrics.roundedScrollTop === 0) {
|
|
60
89
|
pauseAutoScrollRef.current = false;
|
|
61
90
|
}
|
|
62
91
|
if (debounceTimeout.current) {
|
|
63
92
|
clearTimeout(debounceTimeout.current);
|
|
64
93
|
}
|
|
65
|
-
if (!isAtBottom && !pauseAutoScrollRef.current) {
|
|
94
|
+
if (!isAtBottom && !metrics.nearBottom && !pauseAutoScrollRef.current && !programmaticScrollRef.current) {
|
|
66
95
|
setAutoScroll(false);
|
|
67
96
|
}
|
|
68
97
|
// User is near bottom and scrolling down - debounce re-enabling auto-scroll
|
|
@@ -72,14 +101,7 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
72
101
|
}, DEBOUNCE_DELAY);
|
|
73
102
|
}
|
|
74
103
|
lastScrollTop.current = roundedScrollTop;
|
|
75
|
-
}, [
|
|
76
|
-
const checkOverflow = (0, react_1.useCallback)(() => {
|
|
77
|
-
const element = messageBoxRef.current;
|
|
78
|
-
if (element) {
|
|
79
|
-
const { scrollHeight, clientHeight } = element;
|
|
80
|
-
setIsOverflowing(scrollHeight >= clientHeight);
|
|
81
|
-
}
|
|
82
|
-
}, [messageBoxRef]);
|
|
104
|
+
}, [enableSmartScroll]);
|
|
83
105
|
const resumeAutoScroll = (0, react_1.useCallback)(() => {
|
|
84
106
|
if (!enableSmartScroll) {
|
|
85
107
|
return;
|
|
@@ -131,6 +153,7 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
131
153
|
return;
|
|
132
154
|
}
|
|
133
155
|
scrollQueued.current = true;
|
|
156
|
+
programmaticScrollRef.current = true;
|
|
134
157
|
if (animationFrame.current) {
|
|
135
158
|
cancelAnimationFrame(animationFrame.current);
|
|
136
159
|
}
|
|
@@ -138,24 +161,51 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
138
161
|
element.scrollTo({ top: element.scrollHeight, behavior });
|
|
139
162
|
resumeAutoScroll();
|
|
140
163
|
scrollQueued.current = false;
|
|
164
|
+
if (behavior === 'auto') {
|
|
165
|
+
programmaticScrollRef.current = false;
|
|
166
|
+
lastScrollTop.current = element.scrollTop;
|
|
167
|
+
}
|
|
141
168
|
});
|
|
142
169
|
onScrollToBottomClick && onScrollToBottomClick();
|
|
143
170
|
}, [messageBoxRef, enableSmartScroll]);
|
|
144
|
-
|
|
145
|
-
|
|
171
|
+
const measureJumpButtonState = (0, react_1.useCallback)(() => {
|
|
172
|
+
const element = messageBoxRef.current;
|
|
173
|
+
if (!element) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const metrics = getScrollMetrics(element);
|
|
177
|
+
setAtTop(metrics.atTop);
|
|
178
|
+
setAtBottom(isAtBottomEdge(metrics, enableSmartScroll, autoScrollRef.current, pauseAutoScrollRef.current, programmaticScrollRef.current));
|
|
179
|
+
setIsOverflowing(metrics.isOverflowing);
|
|
180
|
+
setHasMeasuredScroll(true);
|
|
181
|
+
}, [enableSmartScroll]);
|
|
182
|
+
const handleContentResize = (0, react_1.useCallback)(() => {
|
|
183
|
+
const element = messageBoxRef.current;
|
|
184
|
+
if (element) {
|
|
185
|
+
const metrics = getScrollMetrics(element);
|
|
186
|
+
const shouldFollow = shouldFollowContentGrowth(metrics, enableSmartScroll, autoScrollRef.current, pauseAutoScrollRef.current, programmaticScrollRef.current);
|
|
187
|
+
if (shouldFollow && !scrollQueued.current) {
|
|
188
|
+
programmaticScrollRef.current = true;
|
|
189
|
+
element.scrollTop = element.scrollHeight - element.clientHeight;
|
|
190
|
+
lastScrollTop.current = element.scrollTop;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
measureJumpButtonState();
|
|
194
|
+
}, [enableSmartScroll, measureJumpButtonState]);
|
|
195
|
+
// Detect scroll position before paint to avoid jump button flash on mount
|
|
196
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
146
197
|
const element = messageBoxRef.current;
|
|
147
198
|
if (!element) {
|
|
148
199
|
return;
|
|
149
200
|
}
|
|
150
|
-
|
|
201
|
+
measureJumpButtonState();
|
|
151
202
|
element.addEventListener('scroll', handleScroll);
|
|
152
|
-
|
|
153
|
-
handleScroll();
|
|
154
|
-
checkOverflow();
|
|
203
|
+
const resizeObserver = (0, react_core_1.getResizeObserver)(element, handleContentResize);
|
|
155
204
|
return () => {
|
|
156
205
|
element.removeEventListener('scroll', handleScroll);
|
|
206
|
+
resizeObserver();
|
|
157
207
|
};
|
|
158
|
-
}, [
|
|
208
|
+
}, [handleContentResize, handleScroll, measureJumpButtonState]);
|
|
159
209
|
(0, react_1.useImperativeHandle)(ref, () => {
|
|
160
210
|
const node = messageBoxRef.current;
|
|
161
211
|
// Attach custom methods to the element
|
|
@@ -176,12 +226,13 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
176
226
|
}
|
|
177
227
|
if (!isScrollingDown) {
|
|
178
228
|
pauseAutoScrollRef.current = true;
|
|
229
|
+
programmaticScrollRef.current = false;
|
|
179
230
|
clearTimeout(resetUserScrollIntentTimeout.current);
|
|
180
231
|
return;
|
|
181
232
|
}
|
|
182
233
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
183
234
|
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
|
184
|
-
if (distanceFromBottom <
|
|
235
|
+
if (distanceFromBottom < SCROLL_EDGE_DELTA) {
|
|
185
236
|
pauseAutoScrollRef.current = false;
|
|
186
237
|
setAutoScroll(true);
|
|
187
238
|
}
|
|
@@ -206,6 +257,6 @@ exports.MessageBox = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
206
257
|
onTouchMove,
|
|
207
258
|
onTouchEnd
|
|
208
259
|
};
|
|
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 pf-chatbot-m-hidden", "aria-live": "polite", children: announcement })] }))
|
|
260
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "top", isHidden: !hasMeasuredScroll || (isOverflowing && atTop), onClick: scrollToTop, jumpButtonProps: jumpButtonTopProps, jumpButtonTooltipProps: jumpButtonTopTooltipProps }), (0, jsx_runtime_1.jsx)(JumpButton_1.default, { position: "bottom", isHidden: !hasMeasuredScroll || (isOverflowing && atBottom), onClick: () => scrollToBottom({ resumeSmartScroll: true }), jumpButtonProps: jumpButtonBottomProps, jumpButtonTooltipProps: jumpButtonBottomTooltipProps }), (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 pf-chatbot-m-hidden", "aria-live": "polite", children: announcement })] }))] }));
|
|
210
261
|
});
|
|
211
262
|
exports.default = exports.MessageBox;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
16
|
const react_1 = require("react");
|
|
17
17
|
const react_2 = require("@testing-library/react");
|
|
18
|
+
require("@testing-library/jest-dom");
|
|
18
19
|
const MessageBox_1 = require("./MessageBox");
|
|
19
20
|
const user_event_1 = __importDefault(require("@testing-library/user-event"));
|
|
20
21
|
describe('MessageBox', () => {
|
|
@@ -232,4 +233,62 @@ describe('MessageBox', () => {
|
|
|
232
233
|
});
|
|
233
234
|
expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
|
|
234
235
|
}));
|
|
236
|
+
it('should keep auto-scroll active during programmatic scroll to bottom', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
237
|
+
var _a, _b;
|
|
238
|
+
const ref = (0, react_1.createRef)();
|
|
239
|
+
(0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { ref: ref, enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
|
|
240
|
+
const element = ref.current;
|
|
241
|
+
Object.defineProperty(element, 'scrollHeight', { configurable: true, value: 1000 });
|
|
242
|
+
Object.defineProperty(element, 'clientHeight', { configurable: true, value: 300 });
|
|
243
|
+
Object.defineProperty(element, 'scrollTop', { configurable: true, value: 0, writable: true });
|
|
244
|
+
(0, react_2.act)(() => {
|
|
245
|
+
var _a;
|
|
246
|
+
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollToBottom({ behavior: 'smooth' });
|
|
247
|
+
});
|
|
248
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.isSmartScrollActive()).toBe(true);
|
|
249
|
+
(0, react_2.act)(() => {
|
|
250
|
+
element.scrollTop = 500;
|
|
251
|
+
element.dispatchEvent(new Event('scroll', { bubbles: true }));
|
|
252
|
+
});
|
|
253
|
+
expect((_b = ref.current) === null || _b === void 0 ? void 0 : _b.isSmartScrollActive()).toBe(true);
|
|
254
|
+
}));
|
|
255
|
+
it('should not scroll to bottom on initial layout when the message box is at the top', () => {
|
|
256
|
+
(0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Tall message content" }) }));
|
|
257
|
+
const region = react_2.screen.getByRole('region');
|
|
258
|
+
Object.defineProperty(region, 'scrollHeight', { configurable: true, value: 1000 });
|
|
259
|
+
Object.defineProperty(region, 'clientHeight', { configurable: true, value: 300 });
|
|
260
|
+
Object.defineProperty(region, 'scrollTop', { configurable: true, value: 0, writable: true });
|
|
261
|
+
(0, react_2.act)(() => {
|
|
262
|
+
region.dispatchEvent(new Event('scroll'));
|
|
263
|
+
});
|
|
264
|
+
expect(region.scrollTop).toBe(0);
|
|
265
|
+
});
|
|
266
|
+
it('should show the bottom jump button at the top on initial load when overflowing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
267
|
+
(0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Tall message content" }) }));
|
|
268
|
+
const region = react_2.screen.getByRole('region');
|
|
269
|
+
Object.defineProperty(region, 'scrollHeight', { configurable: true, value: 1000 });
|
|
270
|
+
Object.defineProperty(region, 'clientHeight', { configurable: true, value: 300 });
|
|
271
|
+
Object.defineProperty(region, 'scrollTop', { configurable: true, value: 0, writable: true });
|
|
272
|
+
(0, react_2.act)(() => {
|
|
273
|
+
region.dispatchEvent(new Event('scroll'));
|
|
274
|
+
});
|
|
275
|
+
yield (0, react_2.waitFor)(() => {
|
|
276
|
+
expect(react_2.screen.queryByRole('button', { name: /Back to top/i })).toBeFalsy();
|
|
277
|
+
expect(react_2.screen.getByRole('button', { name: /Back to bottom/i })).toBeTruthy();
|
|
278
|
+
});
|
|
279
|
+
}));
|
|
280
|
+
it('should hide the bottom jump button while smart scroll is actively following content', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
281
|
+
(0, react_2.render)((0, jsx_runtime_1.jsx)(MessageBox_1.MessageBox, { enableSmartScroll: true, children: (0, jsx_runtime_1.jsx)("div", { children: "Test message content" }) }));
|
|
282
|
+
const region = react_2.screen.getByRole('region');
|
|
283
|
+
Object.defineProperty(region, 'scrollHeight', { configurable: true, value: 1000 });
|
|
284
|
+
Object.defineProperty(region, 'clientHeight', { configurable: true, value: 300 });
|
|
285
|
+
Object.defineProperty(region, 'scrollTop', { configurable: true, value: 640, writable: true });
|
|
286
|
+
(0, react_2.act)(() => {
|
|
287
|
+
region.dispatchEvent(new Event('scroll'));
|
|
288
|
+
});
|
|
289
|
+
yield (0, react_2.waitFor)(() => {
|
|
290
|
+
expect(react_2.screen.getByRole('button', { name: /Back to top/i })).toBeTruthy();
|
|
291
|
+
expect(react_2.screen.queryByRole('button', { name: /Back to bottom/i })).toBeFalsy();
|
|
292
|
+
});
|
|
293
|
+
}));
|
|
235
294
|
});
|
|
@@ -20,35 +20,35 @@ const react_icons_1 = require("@patternfly/react-icons");
|
|
|
20
20
|
const ResponseActionButton_1 = __importDefault(require("./ResponseActionButton"));
|
|
21
21
|
describe('ResponseActionButton', () => {
|
|
22
22
|
it('renders aria-label correctly if not clicked', () => {
|
|
23
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
23
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), ariaLabel: "Download", clickedAriaLabel: "Downloaded" }));
|
|
24
24
|
expect(react_1.screen.getByRole('button', { name: 'Download' })).toBeTruthy();
|
|
25
25
|
});
|
|
26
26
|
it('renders aria-label correctly if clicked', () => {
|
|
27
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
27
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), ariaLabel: "Download", clickedAriaLabel: "Downloaded", isClicked: true }));
|
|
28
28
|
expect(react_1.screen.getByRole('button', { name: 'Downloaded' })).toBeTruthy();
|
|
29
29
|
});
|
|
30
30
|
it('renders tooltip correctly if not clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
31
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), tooltipContent: "Download", clickedTooltipContent: "Downloaded" }));
|
|
32
32
|
expect(react_1.screen.getByRole('button', { name: 'Download' })).toBeTruthy();
|
|
33
33
|
// clicking here just triggers the tooltip; in this button, the logic is divorced from whether it is actually clicked
|
|
34
34
|
yield user_event_1.default.click(react_1.screen.getByRole('button', { name: 'Download' }));
|
|
35
35
|
expect(react_1.screen.getByRole('tooltip', { name: 'Download' })).toBeTruthy();
|
|
36
36
|
}));
|
|
37
37
|
it('renders tooltip correctly if clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
38
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), tooltipContent: "Download", clickedTooltipContent: "Downloaded", isClicked: true }));
|
|
39
39
|
expect(react_1.screen.getByRole('button', { name: 'Downloaded' })).toBeTruthy();
|
|
40
40
|
// clicking here just triggers the tooltip; in this button, the logic is divorced from whether it is actually clicked
|
|
41
41
|
yield user_event_1.default.click(react_1.screen.getByRole('button', { name: 'Downloaded' }));
|
|
42
42
|
expect(react_1.screen.getByRole('tooltip', { name: 'Downloaded' })).toBeTruthy();
|
|
43
43
|
}));
|
|
44
44
|
it('if clicked variant for tooltip is not supplied, it uses the default', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
45
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), tooltipContent: "Download", isClicked: true }));
|
|
46
46
|
// clicking here just triggers the tooltip; in this button, the logic is divorced from whether it is actually clicked
|
|
47
47
|
yield user_event_1.default.click(react_1.screen.getByRole('button', { name: 'Download' }));
|
|
48
48
|
expect(react_1.screen.getByRole('button', { name: 'Download' })).toBeTruthy();
|
|
49
49
|
}));
|
|
50
50
|
it('if clicked variant for aria label is not supplied, it uses the default', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
51
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActionButton_1.default, { icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {}), ariaLabel: "Download", isClicked: true }));
|
|
52
52
|
expect(react_1.screen.getByRole('button', { name: 'Download' })).toBeTruthy();
|
|
53
53
|
}));
|
|
54
54
|
});
|
|
@@ -33,9 +33,8 @@ jest.mock('@patternfly/react-icons', () => ({
|
|
|
33
33
|
RhUiVolumeUpFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiVolumeUpFillIcon" }),
|
|
34
34
|
RhUiExportIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiExportIcon" }),
|
|
35
35
|
RhUiExportFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiExportFillIcon" }),
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
RedoIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RedoIcon" })
|
|
36
|
+
RhMicronsInformationFillIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhMicronsInformationFillIcon" }),
|
|
37
|
+
RhUiRedoIcon: () => (0, jsx_runtime_1.jsx)("div", { children: "RhUiRedoIcon" })
|
|
39
38
|
}));
|
|
40
39
|
const ALL_ACTIONS = [
|
|
41
40
|
{ type: 'positive', label: 'Good response', clickedLabel: 'Good response recorded' },
|
|
@@ -53,7 +52,7 @@ const CUSTOM_ACTIONS = [
|
|
|
53
52
|
onClick: jest.fn(),
|
|
54
53
|
tooltipContent: 'Regenerate',
|
|
55
54
|
clickedTooltipContent: 'Regenerated',
|
|
56
|
-
icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
55
|
+
icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiRedoIcon, {})
|
|
57
56
|
},
|
|
58
57
|
download: {
|
|
59
58
|
ariaLabel: 'Download',
|
|
@@ -61,13 +60,13 @@ const CUSTOM_ACTIONS = [
|
|
|
61
60
|
onClick: jest.fn(),
|
|
62
61
|
tooltipContent: 'Download',
|
|
63
62
|
clickedTooltipContent: 'Downloaded',
|
|
64
|
-
icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
63
|
+
icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {})
|
|
65
64
|
},
|
|
66
65
|
info: {
|
|
67
66
|
ariaLabel: 'Info',
|
|
68
67
|
onClick: jest.fn(),
|
|
69
68
|
tooltipContent: 'Info',
|
|
70
|
-
icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
69
|
+
icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhMicronsInformationFillIcon, {})
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
];
|
|
@@ -323,7 +322,7 @@ describe('ResponseActions', () => {
|
|
|
323
322
|
onClick: jest.fn(),
|
|
324
323
|
ariaLabel: 'Custom',
|
|
325
324
|
tooltipContent: 'Custom action',
|
|
326
|
-
icon: (0, jsx_runtime_1.jsx)(react_icons_1.
|
|
325
|
+
icon: (0, jsx_runtime_1.jsx)(react_icons_1.RhUiExportIcon, {})
|
|
327
326
|
}
|
|
328
327
|
};
|
|
329
328
|
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actions, persistActionSelection: true }));
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -38,8 +38,6 @@ export { default as FilePreview } from './FilePreview';
|
|
|
38
38
|
export * from './FilePreview';
|
|
39
39
|
export { default as ImagePreview } from './ImagePreview';
|
|
40
40
|
export * from './ImagePreview';
|
|
41
|
-
export { default as LoadingMessage } from './LoadingMessage';
|
|
42
|
-
export * from './LoadingMessage';
|
|
43
41
|
export { default as MarkdownContent } from './MarkdownContent';
|
|
44
42
|
export * from './MarkdownContent';
|
|
45
43
|
export { default as Message } from './Message';
|