@patternfly/chatbot 6.4.1 → 6.5.0-prerelease.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/AttachMenu/AttachMenu.d.ts +8 -2
- package/dist/cjs/AttachMenu/AttachMenu.js +2 -2
- package/dist/cjs/ChatbotContent/ChatbotContent.d.ts +2 -0
- package/dist/cjs/ChatbotContent/ChatbotContent.js +2 -2
- package/dist/cjs/ChatbotContent/ChatbotContent.test.js +4 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
- package/dist/cjs/ChatbotFooter/ChatbotFooter.d.ts +5 -2
- package/dist/cjs/ChatbotFooter/ChatbotFooter.js +2 -2
- package/dist/cjs/ChatbotFooter/ChatbotFooter.test.js +5 -1
- package/dist/cjs/CodeModal/CodeModal.js +40 -4
- package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
- package/dist/cjs/Message/Message.d.ts +6 -19
- package/dist/cjs/Message/Message.js +10 -7
- package/dist/cjs/Message/Message.test.js +38 -0
- package/dist/cjs/Message/MessageLoading.d.ts +2 -1
- package/dist/cjs/Message/MessageLoading.js +1 -1
- package/dist/cjs/Message/TableMessage/TableMessage.d.ts +4 -1
- package/dist/cjs/Message/TableMessage/TableMessage.js +2 -2
- package/dist/cjs/Message/TextMessage/TextMessage.d.ts +4 -1
- package/dist/cjs/Message/TextMessage/TextMessage.js +2 -2
- package/dist/cjs/MessageBar/AttachButton.d.ts +2 -0
- package/dist/cjs/MessageBar/AttachButton.js +2 -2
- package/dist/cjs/MessageBar/AttachButton.test.js +4 -0
- package/dist/cjs/MessageBar/MessageBar.d.ts +16 -6
- package/dist/cjs/MessageBar/MessageBar.js +6 -5
- package/dist/cjs/MessageBar/MessageBar.test.js +62 -0
- package/dist/cjs/__mocks__/monaco-editor.d.ts +11 -0
- package/dist/cjs/__mocks__/monaco-editor.js +18 -0
- package/dist/cjs/__mocks__/rehype-highlight.d.ts +2 -0
- package/dist/cjs/__mocks__/rehype-highlight.js +4 -0
- package/dist/css/main.css +81 -10
- package/dist/css/main.css.map +1 -1
- package/dist/esm/AttachMenu/AttachMenu.d.ts +8 -2
- package/dist/esm/AttachMenu/AttachMenu.js +2 -2
- package/dist/esm/ChatbotContent/ChatbotContent.d.ts +2 -0
- package/dist/esm/ChatbotContent/ChatbotContent.js +2 -2
- package/dist/esm/ChatbotContent/ChatbotContent.test.js +4 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
- package/dist/esm/ChatbotFooter/ChatbotFooter.d.ts +5 -2
- package/dist/esm/ChatbotFooter/ChatbotFooter.js +2 -2
- package/dist/esm/ChatbotFooter/ChatbotFooter.test.js +5 -1
- package/dist/esm/CodeModal/CodeModal.js +42 -6
- package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +3 -3
- package/dist/esm/Message/Message.d.ts +6 -19
- package/dist/esm/Message/Message.js +10 -7
- package/dist/esm/Message/Message.test.js +39 -1
- package/dist/esm/Message/MessageLoading.d.ts +2 -1
- package/dist/esm/Message/MessageLoading.js +1 -1
- package/dist/esm/Message/TableMessage/TableMessage.d.ts +4 -1
- package/dist/esm/Message/TableMessage/TableMessage.js +2 -2
- package/dist/esm/Message/TextMessage/TextMessage.d.ts +4 -1
- package/dist/esm/Message/TextMessage/TextMessage.js +2 -2
- package/dist/esm/MessageBar/AttachButton.d.ts +2 -0
- package/dist/esm/MessageBar/AttachButton.js +2 -2
- package/dist/esm/MessageBar/AttachButton.test.js +4 -0
- package/dist/esm/MessageBar/MessageBar.d.ts +16 -6
- package/dist/esm/MessageBar/MessageBar.js +6 -5
- package/dist/esm/MessageBar/MessageBar.test.js +62 -0
- package/dist/esm/__mocks__/monaco-editor.d.ts +11 -0
- package/dist/esm/__mocks__/monaco-editor.js +18 -0
- package/dist/esm/__mocks__/rehype-highlight.d.ts +2 -0
- package/dist/esm/__mocks__/rehype-highlight.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -2
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +3 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithActions.tsx +14 -14
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSelection.tsx +14 -14
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarAttach.tsx +2 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarIndicatorThinking.tsx +15 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +10 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +12 -4
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +2 -2
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/WhiteEmbeddedChatbot.tsx +451 -0
- package/patternfly-docs/patternfly-docs.config.js +1 -0
- package/src/AttachMenu/AttachMenu.tsx +26 -11
- package/src/Chatbot/Chatbot.scss +23 -1
- package/src/ChatbotContent/ChatbotContent.scss +4 -0
- package/src/ChatbotContent/ChatbotContent.test.tsx +5 -0
- package/src/ChatbotContent/ChatbotContent.tsx +4 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +5 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +7 -4
- package/src/ChatbotFooter/ChatbotFooter.scss +21 -0
- package/src/ChatbotFooter/ChatbotFooter.test.tsx +10 -1
- package/src/ChatbotFooter/ChatbotFooter.tsx +10 -3
- package/src/ChatbotHeader/ChatbotHeader.scss +19 -0
- package/src/CodeModal/CodeModal.tsx +58 -7
- package/src/FileDetailsLabel/FileDetailsLabel.tsx +2 -2
- package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +7 -2
- package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +9 -2
- package/src/Message/Message.test.tsx +56 -1
- package/src/Message/Message.tsx +14 -26
- package/src/Message/MessageLoading.scss +7 -0
- package/src/Message/MessageLoading.tsx +2 -2
- package/src/Message/TableMessage/TableMessage.scss +4 -0
- package/src/Message/TableMessage/TableMessage.tsx +6 -2
- package/src/Message/TextMessage/TextMessage.scss +12 -0
- package/src/Message/TextMessage/TextMessage.tsx +11 -2
- package/src/Message/UserFeedback/UserFeedback.scss +2 -1
- package/src/MessageBar/AttachButton.test.tsx +4 -0
- package/src/MessageBar/AttachButton.tsx +4 -1
- package/src/MessageBar/MessageBar.scss +11 -5
- package/src/MessageBar/MessageBar.test.tsx +102 -1
- package/src/MessageBar/MessageBar.tsx +44 -11
- package/src/__mocks__/monaco-editor.ts +19 -0
- package/src/__mocks__/rehype-highlight.ts +3 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'react';
|
|
2
|
-
import { DropdownProps, DropdownToggleProps, PopperOptions } from '@patternfly/react-core';
|
|
2
|
+
import { DropdownProps, DropdownToggleProps, PopperOptions, MenuSearchInputProps, SearchInputProps, MenuSearchProps } from '@patternfly/react-core';
|
|
3
3
|
export interface AttachMenuProps extends DropdownProps {
|
|
4
4
|
/** Items in menu */
|
|
5
5
|
filteredItems: React.ReactNode;
|
|
6
6
|
/** A callback for when the input value changes. */
|
|
7
|
-
handleTextInputChange
|
|
7
|
+
handleTextInputChange?: (value: string) => void;
|
|
8
8
|
/** Flag to indicate if menu is opened. */
|
|
9
9
|
isOpen: boolean;
|
|
10
10
|
/** Additional properties to pass to the Popper */
|
|
@@ -21,6 +21,12 @@ export interface AttachMenuProps extends DropdownProps {
|
|
|
21
21
|
searchInputAriaLabel?: string;
|
|
22
22
|
/** Toggle to be rendered */
|
|
23
23
|
toggle: DropdownToggleProps | ((toggleRef: React.RefObject<any>) => React.ReactNode);
|
|
24
|
+
/** Additional props passed to MenuSearch component */
|
|
25
|
+
menuSearchProps?: Omit<MenuSearchProps, 'ref'>;
|
|
26
|
+
/** Additional props passed to MenuSearchInput component */
|
|
27
|
+
menuSearchInputProps?: Omit<MenuSearchInputProps, 'ref'>;
|
|
28
|
+
/** Additional props passed to SearchInput component */
|
|
29
|
+
searchInputProps?: SearchInputProps;
|
|
24
30
|
}
|
|
25
31
|
export declare const AttachMenu: FunctionComponent<AttachMenuProps>;
|
|
26
32
|
export default AttachMenu;
|
|
@@ -16,8 +16,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
16
16
|
// Import PatternFly components
|
|
17
17
|
const react_core_1 = require("@patternfly/react-core");
|
|
18
18
|
const AttachMenu = (_a) => {
|
|
19
|
-
var { className, filteredItems, handleTextInputChange, isOpen, popperProps = undefined, onOpenChange, onOpenChangeKeys, onSelect, searchInputPlaceholder, searchInputAriaLabel = 'Filter menu items', toggle } = _a, props = __rest(_a, ["className", "filteredItems", "handleTextInputChange", "isOpen", "popperProps", "onOpenChange", "onOpenChangeKeys", "onSelect", "searchInputPlaceholder", "searchInputAriaLabel", "toggle"]);
|
|
20
|
-
return ((0, jsx_runtime_1.jsxs)(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__menu ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOpen, onOpenChange: (isOpen) => onOpenChange(isOpen), onOpenChangeKeys: onOpenChangeKeys !== null && onOpenChangeKeys !== void 0 ? onOpenChangeKeys : ['Esc'], toggle: toggle, popperProps: popperProps, onSelect: onSelect }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.MenuSearch, { children: (0, jsx_runtime_1.jsx)(react_core_1.MenuSearchInput, { children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, { "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }) }) }), filteredItems] })));
|
|
19
|
+
var { className, filteredItems, handleTextInputChange, isOpen, popperProps = undefined, onOpenChange, onOpenChangeKeys, onSelect, searchInputPlaceholder, searchInputAriaLabel = 'Filter menu items', toggle, menuSearchProps, menuSearchInputProps, searchInputProps } = _a, props = __rest(_a, ["className", "filteredItems", "handleTextInputChange", "isOpen", "popperProps", "onOpenChange", "onOpenChangeKeys", "onSelect", "searchInputPlaceholder", "searchInputAriaLabel", "toggle", "menuSearchProps", "menuSearchInputProps", "searchInputProps"]);
|
|
20
|
+
return ((0, jsx_runtime_1.jsxs)(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__menu ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOpen, onOpenChange: (isOpen) => onOpenChange(isOpen), onOpenChangeKeys: onOpenChangeKeys !== null && onOpenChangeKeys !== void 0 ? onOpenChangeKeys : ['Esc'], toggle: toggle, popperProps: popperProps, onSelect: onSelect }, props, { children: [handleTextInputChange && ((0, jsx_runtime_1.jsx)(react_core_1.MenuSearch, Object.assign({}, menuSearchProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.MenuSearchInput, Object.assign({}, menuSearchInputProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) })) }))), filteredItems] })));
|
|
21
21
|
};
|
|
22
22
|
exports.AttachMenu = AttachMenu;
|
|
23
23
|
exports.default = exports.AttachMenu;
|
|
@@ -4,6 +4,8 @@ export interface ChatbotContentProps extends HTMLProps<HTMLDivElement> {
|
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
/** Custom classname for the ChatbotContent component */
|
|
6
6
|
className?: string;
|
|
7
|
+
/** Sets background color to primary */
|
|
8
|
+
isPrimary?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export declare const ChatbotContent: FunctionComponent<ChatbotContentProps>;
|
|
9
11
|
export default ChatbotContent;
|
|
@@ -14,8 +14,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
exports.ChatbotContent = void 0;
|
|
15
15
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
16
|
const ChatbotContent = (_a) => {
|
|
17
|
-
var { children, className } = _a, props = __rest(_a, ["children", "className"]);
|
|
18
|
-
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: `pf-chatbot__content ${className !== null && className !== void 0 ? className : ''}` }, props, { children: children })));
|
|
17
|
+
var { children, className, isPrimary } = _a, props = __rest(_a, ["children", "className", "isPrimary"]);
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: `pf-chatbot__content ${isPrimary ? 'pf-m-primary' : ''} ${className !== null && className !== void 0 ? className : ''}` }, props, { children: children })));
|
|
19
19
|
};
|
|
20
20
|
exports.ChatbotContent = ChatbotContent;
|
|
21
21
|
exports.default = exports.ChatbotContent;
|
|
@@ -15,4 +15,8 @@ describe('ChatbotContent', () => {
|
|
|
15
15
|
const { container } = (0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotContent_1.default, { className: "custom-class", children: "Chatbot Content" }));
|
|
16
16
|
expect(container.querySelector('.custom-class')).toBeTruthy();
|
|
17
17
|
});
|
|
18
|
+
it('should render ChatbotContent with primary class', () => {
|
|
19
|
+
const { container } = (0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotContent_1.default, { isPrimary: true, children: "Chatbot Content" }));
|
|
20
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
21
|
+
});
|
|
18
22
|
});
|
|
@@ -5,8 +5,10 @@ export interface ChatbotConversationHistoryDropdownProps extends Omit<DropdownPr
|
|
|
5
5
|
menuItems: React.ReactNode;
|
|
6
6
|
/** Optional classname applied to conversation settings dropdown */
|
|
7
7
|
menuClassName?: string;
|
|
8
|
-
/** Tooltip content
|
|
8
|
+
/** Tooltip content applied to conversation settings dropdown */
|
|
9
9
|
label?: string;
|
|
10
|
+
/** Aria-label applied to conversation settings dropdown */
|
|
11
|
+
'aria-label'?: string;
|
|
10
12
|
/** Callback for when user selects item. */
|
|
11
13
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
12
14
|
/** Id applied to dropdown menu toggle */
|
|
@@ -9,11 +9,11 @@ const react_1 = require("react");
|
|
|
9
9
|
// Import PatternFly components
|
|
10
10
|
const react_core_1 = require("@patternfly/react-core");
|
|
11
11
|
const ellipsis_v_icon_1 = __importDefault(require("@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon"));
|
|
12
|
-
const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label, id }) => {
|
|
12
|
+
const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label = 'Conversation options', 'aria-label': ariaLabel, id }) => {
|
|
13
13
|
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
14
|
-
const toggle = (toggleRef) => ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label
|
|
14
|
+
const toggle = (toggleRef) => ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label, position: "bottom",
|
|
15
15
|
// 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":
|
|
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)(ellipsis_v_icon_1.default, {}) }) }));
|
|
17
17
|
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
18
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
|
19
19
|
setIsOpen((prev) => !prev);
|
|
@@ -68,4 +68,8 @@ describe('ChatbotConversationHistoryDropdown', () => {
|
|
|
68
68
|
expect(react_1.screen.queryByText('Actions dropdown')).toBeInTheDocument();
|
|
69
69
|
});
|
|
70
70
|
}));
|
|
71
|
+
it('should be able to set a custom aria-label', () => {
|
|
72
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, "aria-label": "Custom conversation options" }));
|
|
73
|
+
expect(react_1.screen.queryByRole('menuitem', { name: /Custom conversation options/i })).toBeInTheDocument();
|
|
74
|
+
});
|
|
71
75
|
});
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { HTMLProps, FunctionComponent } from 'react';
|
|
2
2
|
export interface ChatbotFooterProps extends HTMLProps<HTMLDivElement> {
|
|
3
|
-
/** Children for the
|
|
3
|
+
/** Children for the footer - supports MessageBar and FootNote components*/
|
|
4
4
|
children?: React.ReactNode;
|
|
5
|
-
/** Custom classname for the
|
|
5
|
+
/** Custom classname for the footer component */
|
|
6
6
|
className?: string;
|
|
7
|
+
/** Sets footer to compact styling. */
|
|
7
8
|
isCompact?: boolean;
|
|
9
|
+
/** Sets background color to primary */
|
|
10
|
+
isPrimary?: boolean;
|
|
8
11
|
}
|
|
9
12
|
export declare const ChatbotFooter: FunctionComponent<ChatbotFooterProps>;
|
|
10
13
|
export default ChatbotFooter;
|
|
@@ -15,8 +15,8 @@ exports.ChatbotFooter = void 0;
|
|
|
15
15
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
16
|
const react_core_1 = require("@patternfly/react-core");
|
|
17
17
|
const ChatbotFooter = (_a) => {
|
|
18
|
-
var { children, className, isCompact } = _a, props = __rest(_a, ["children", "className", "isCompact"]);
|
|
19
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: `pf-chatbot__footer ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__footer-container", children: children })] })));
|
|
18
|
+
var { children, className, isCompact, isPrimary } = _a, props = __rest(_a, ["children", "className", "isCompact", "isPrimary"]);
|
|
19
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: `pf-chatbot__footer ${isCompact ? 'pf-m-compact' : ''} ${isPrimary ? 'pf-m-primary' : ''} ${className !== null && className !== void 0 ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__footer-container", children: children })] })));
|
|
20
20
|
};
|
|
21
21
|
exports.ChatbotFooter = ChatbotFooter;
|
|
22
22
|
exports.default = exports.ChatbotFooter;
|
|
@@ -17,7 +17,11 @@ describe('ChatbotFooter', () => {
|
|
|
17
17
|
expect(container.querySelector('.custom-class')).toBeTruthy();
|
|
18
18
|
});
|
|
19
19
|
it('should handle isCompact', () => {
|
|
20
|
-
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, {
|
|
20
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, { isCompact: true, "data-testid": "footer", children: "Chatbot Content" }));
|
|
21
21
|
expect(react_1.screen.getByTestId('footer')).toHaveClass('pf-m-compact');
|
|
22
22
|
});
|
|
23
|
+
it('should handle isPrimary', () => {
|
|
24
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotFooter_1.default, { isPrimary: true, "data-testid": "footer", children: "Chatbot Content" }));
|
|
25
|
+
expect(react_1.screen.getByTestId('footer')).toHaveClass('pf-m-primary');
|
|
26
|
+
});
|
|
23
27
|
});
|
|
@@ -41,15 +41,44 @@ exports.CodeModal = void 0;
|
|
|
41
41
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
42
42
|
const react_1 = require("react");
|
|
43
43
|
const path_browserify_1 = __importDefault(require("path-browserify"));
|
|
44
|
+
const monaco = __importStar(require("monaco-editor"));
|
|
45
|
+
const react_2 = require("@monaco-editor/react");
|
|
44
46
|
// Import PatternFly components
|
|
45
47
|
const react_code_editor_1 = require("@patternfly/react-code-editor");
|
|
46
48
|
const react_core_1 = require("@patternfly/react-core");
|
|
47
49
|
const FileDetails_1 = __importStar(require("../FileDetails"));
|
|
48
50
|
const Chatbot_1 = require("../Chatbot");
|
|
49
51
|
const ChatbotModal_1 = __importDefault(require("../ChatbotModal/ChatbotModal"));
|
|
52
|
+
// Configure Monaco loader to use the npm package instead of CDN
|
|
53
|
+
react_2.loader.config({ monaco });
|
|
50
54
|
const CodeModal = (_a) => {
|
|
51
55
|
var { fileName, code, codeEditorControlClassName: codeEditorClassName, handleModalToggle, isCopyEnabled, isLineNumbersVisible, isModalOpen, isReadOnly, onPrimaryAction, onSecondaryAction, primaryActionBtn, secondaryActionBtn, title, displayMode = Chatbot_1.ChatbotDisplayMode.default, isCompact, modalHeaderClassName, modalBodyClassName, modalFooterClassName } = _a, props = __rest(_a, ["fileName", "code", "codeEditorControlClassName", "handleModalToggle", "isCopyEnabled", "isLineNumbersVisible", "isModalOpen", "isReadOnly", "onPrimaryAction", "onSecondaryAction", "primaryActionBtn", "secondaryActionBtn", "title", "displayMode", "isCompact", "modalHeaderClassName", "modalBodyClassName", "modalFooterClassName"]);
|
|
52
56
|
const [newCode, setNewCode] = (0, react_1.useState)(code);
|
|
57
|
+
const [editorInstance, setEditorInstance] = (0, react_1.useState)(null);
|
|
58
|
+
const [isEditorReady, setIsEditorReady] = (0, react_1.useState)(false);
|
|
59
|
+
const containerRef = (0, react_1.useRef)(null);
|
|
60
|
+
(0, react_1.useEffect)(() => {
|
|
61
|
+
if (!isModalOpen || !isEditorReady || !editorInstance || !containerRef.current) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const handleResize = () => {
|
|
65
|
+
if (editorInstance && isEditorReady && isModalOpen) {
|
|
66
|
+
try {
|
|
67
|
+
window.requestAnimationFrame(() => {
|
|
68
|
+
editorInstance.layout();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
console.error('ChatBot code modal layout error:', error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const observer = (0, react_core_1.getResizeObserver)(containerRef.current, handleResize);
|
|
78
|
+
return () => {
|
|
79
|
+
observer();
|
|
80
|
+
};
|
|
81
|
+
}, [editorInstance, isEditorReady, isModalOpen]);
|
|
53
82
|
const handlePrimaryAction = (_event) => {
|
|
54
83
|
handleModalToggle(_event);
|
|
55
84
|
if (!isReadOnly) {
|
|
@@ -64,18 +93,25 @@ const CodeModal = (_a) => {
|
|
|
64
93
|
onSecondaryAction(_event);
|
|
65
94
|
};
|
|
66
95
|
const onEditorDidMount = (editor, monaco) => {
|
|
67
|
-
editor
|
|
68
|
-
editor.focus();
|
|
96
|
+
setEditorInstance(editor);
|
|
69
97
|
monaco.editor.getModels()[0].updateOptions({ tabSize: 5 });
|
|
98
|
+
if (containerRef.current) {
|
|
99
|
+
setIsEditorReady(true);
|
|
100
|
+
editor.layout();
|
|
101
|
+
editor.focus();
|
|
102
|
+
}
|
|
70
103
|
};
|
|
71
104
|
const onCodeChange = (value) => {
|
|
72
105
|
if (!isReadOnly) {
|
|
73
106
|
setNewCode(value);
|
|
74
107
|
}
|
|
75
108
|
};
|
|
76
|
-
const modal = ((0, jsx_runtime_1.jsxs)(ChatbotModal_1.default, { isOpen: isModalOpen, onClose: handleModalToggle, ouiaId: "CodeModal", "aria-labelledby": "code-modal-title", "aria-describedby": "code-modal", className: `pf-chatbot__code-modal ${isCompact ? 'pf-m-compact' : ''} pf-chatbot__code-modal--${displayMode}`, displayMode: displayMode, isCompact: isCompact, children: [(0, jsx_runtime_1.jsx)(react_core_1.ModalHeader, { className: modalHeaderClassName, title: title, labelId: "code-modal-title" }), (0, jsx_runtime_1.jsx)(react_core_1.ModalBody, { className: modalBodyClassName, id: "code-modal-body", children: (0, jsx_runtime_1.jsxs)(react_core_1.Stack, { className: "pf-chatbot__code-modal-body", children: [(0, jsx_runtime_1.jsx)(react_core_1.StackItem, { className: "pf-chatbot__code-modal-file-details", children: (0, jsx_runtime_1.jsx)(FileDetails_1.default, { fileName: fileName }) }), (0, jsx_runtime_1.jsx)(
|
|
109
|
+
const modal = ((0, jsx_runtime_1.jsxs)(ChatbotModal_1.default, { isOpen: isModalOpen, onClose: handleModalToggle, ouiaId: "CodeModal", "aria-labelledby": "code-modal-title", "aria-describedby": "code-modal", className: `pf-chatbot__code-modal ${isCompact ? 'pf-m-compact' : ''} pf-chatbot__code-modal--${displayMode}`, displayMode: displayMode, isCompact: isCompact, children: [(0, jsx_runtime_1.jsx)(react_core_1.ModalHeader, { className: modalHeaderClassName, title: title, labelId: "code-modal-title" }), (0, jsx_runtime_1.jsx)(react_core_1.ModalBody, { className: modalBodyClassName, id: "code-modal-body", children: (0, jsx_runtime_1.jsxs)(react_core_1.Stack, { className: "pf-chatbot__code-modal-body", children: [(0, jsx_runtime_1.jsx)(react_core_1.StackItem, { className: "pf-chatbot__code-modal-file-details", children: (0, jsx_runtime_1.jsx)(FileDetails_1.default, { fileName: fileName }) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-v6-l-stack__item pf-chatbot__code-modal-editor", ref: containerRef, children: (0, jsx_runtime_1.jsx)(react_code_editor_1.CodeEditor, Object.assign({ isDarkTheme: true, isLineNumbersVisible: isLineNumbersVisible, isLanguageLabelVisible: true, isCopyEnabled: isCopyEnabled, isReadOnly: isReadOnly, code: newCode, language: FileDetails_1.extensionToLanguage[path_browserify_1.default.extname(fileName).slice(1)], onEditorDidMount: onEditorDidMount, onCodeChange: onCodeChange, className: codeEditorClassName, isFullHeight: true, options: {
|
|
77
110
|
glyphMargin: false,
|
|
78
|
-
folding: false
|
|
111
|
+
folding: false,
|
|
112
|
+
// prevents Monaco from handling resizing itself
|
|
113
|
+
// was causing ResizeObserver issues
|
|
114
|
+
automaticLayout: false
|
|
79
115
|
} }, props)) })] }) }), (0, jsx_runtime_1.jsxs)(react_core_1.ModalFooter, { className: modalFooterClassName, children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "primary", onClick: handlePrimaryAction, form: "code-modal-form", children: primaryActionBtn }, "code-modal-primary"), (0, jsx_runtime_1.jsx)(react_core_1.Button, { isBlock: true, variant: "link", onClick: handleSecondaryAction, children: secondaryActionBtn }, "code-modal-secondary")] })] }));
|
|
80
116
|
return modal;
|
|
81
117
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
|
-
|
|
2
|
+
import { LabelProps } from '@patternfly/react-core';
|
|
3
|
+
export interface FileDetailsLabelProps extends Omit<LabelProps, 'onClose' | 'onClick'> {
|
|
3
4
|
/** Name of file, including extension */
|
|
4
5
|
fileName: string;
|
|
5
6
|
/** Unique id of file */
|
|
@@ -16,6 +16,10 @@ export interface CodeBlockMessageProps {
|
|
|
16
16
|
expandedText?: string;
|
|
17
17
|
/** Link text applied to expandable toggle when collapsed */
|
|
18
18
|
collapsedText?: string;
|
|
19
|
+
/** Custom actions added to header of code block, after any default actions such as the "copy" action. */
|
|
20
|
+
customActions?: React.ReactNode;
|
|
21
|
+
/** Sets background colors to be appropriate on primary chatbot background */
|
|
22
|
+
isPrimary?: boolean;
|
|
19
23
|
}
|
|
20
|
-
declare const CodeBlockMessage: ({ children, className, "aria-label": ariaLabel, isExpandable, expandableSectionProps, expandableSectionToggleProps, expandedText, collapsedText, ...props }: CodeBlockMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
declare const CodeBlockMessage: ({ children, className, "aria-label": ariaLabel, isExpandable, expandableSectionProps, expandableSectionToggleProps, expandedText, collapsedText, customActions, isPrimary, ...props }: CodeBlockMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
25
|
export default CodeBlockMessage;
|
|
@@ -24,7 +24,7 @@ const DEFAULT_EXPANDED_TEXT = 'Show less';
|
|
|
24
24
|
const DEFAULT_COLLAPSED_TEXT = 'Show more';
|
|
25
25
|
const CodeBlockMessage = (_a) => {
|
|
26
26
|
var _b;
|
|
27
|
-
var { children, className, 'aria-label': ariaLabel, isExpandable = false, expandableSectionProps, expandableSectionToggleProps, expandedText = DEFAULT_EXPANDED_TEXT, collapsedText = DEFAULT_COLLAPSED_TEXT } = _a, props = __rest(_a, ["children", "className", 'aria-label', "isExpandable", "expandableSectionProps", "expandableSectionToggleProps", "expandedText", "collapsedText"]);
|
|
27
|
+
var { children, className, 'aria-label': ariaLabel, isExpandable = false, expandableSectionProps, expandableSectionToggleProps, expandedText = DEFAULT_EXPANDED_TEXT, collapsedText = DEFAULT_COLLAPSED_TEXT, customActions, isPrimary } = _a, props = __rest(_a, ["children", "className", 'aria-label', "isExpandable", "expandableSectionProps", "expandableSectionToggleProps", "expandedText", "collapsedText", "customActions", "isPrimary"]);
|
|
28
28
|
const [copied, setCopied] = (0, react_1.useState)(false);
|
|
29
29
|
const [isExpanded, setIsExpanded] = (0, react_1.useState)(false);
|
|
30
30
|
const buttonRef = (0, react_1.useRef)();
|
|
@@ -61,10 +61,10 @@ const CodeBlockMessage = (_a) => {
|
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
63
|
if (!String(children).includes('\n')) {
|
|
64
|
-
return ((0, jsx_runtime_1.jsx)("code", Object.assign({}, props, { className:
|
|
64
|
+
return ((0, jsx_runtime_1.jsx)("code", Object.assign({}, props, { className: `pf-chatbot__message-inline-code ${isPrimary ? 'pf-m-primary' : ''}`, children: children })));
|
|
65
65
|
}
|
|
66
66
|
// Setup code block header
|
|
67
|
-
const actions = ((0, jsx_runtime_1.
|
|
67
|
+
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)(copy_icon_1.CopyIcon, {}) }), (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { id: tooltipID, content: "Copy", position: "top", triggerRef: buttonRef })] }), customActions] }));
|
|
68
68
|
return ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-code-block", 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 })))] }) }));
|
|
69
69
|
};
|
|
70
70
|
exports.default = CodeBlockMessage;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import type { FunctionComponent, HTMLProps, MouseEvent as ReactMouseEvent, Ref } from 'react';
|
|
3
3
|
import { Options } from 'react-markdown';
|
|
4
|
-
import { AlertProps, AvatarProps, ButtonProps,
|
|
4
|
+
import { AlertProps, AvatarProps, ButtonProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
|
|
5
|
+
import { CodeBlockMessageProps } from './CodeBlockMessage/CodeBlockMessage';
|
|
5
6
|
import { ActionProps } from '../ResponseActions/ResponseActions';
|
|
6
7
|
import { SourcesCardProps } from '../SourcesCard';
|
|
7
8
|
import { QuickStart, QuickstartAction } from './QuickStarts/types';
|
|
@@ -9,6 +10,7 @@ import QuickResponse from './QuickResponse/QuickResponse';
|
|
|
9
10
|
import { UserFeedbackProps } from './UserFeedback/UserFeedback';
|
|
10
11
|
import { UserFeedbackCompleteProps } from './UserFeedback/UserFeedbackComplete';
|
|
11
12
|
import { TableProps } from '@patternfly/react-table';
|
|
13
|
+
import 'highlight.js/styles/vs2015.css';
|
|
12
14
|
import { PluggableList } from 'unified';
|
|
13
15
|
import { ToolResponseProps } from '../ToolResponse';
|
|
14
16
|
import { DeepThinkingProps } from '../DeepThinking';
|
|
@@ -69,24 +71,7 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
|
|
|
69
71
|
/** Label for the English "Loading message," displayed to screenreaders when loading a message */
|
|
70
72
|
loadingWord?: string;
|
|
71
73
|
/** Props for code blocks */
|
|
72
|
-
codeBlockProps?:
|
|
73
|
-
/** Aria label applied to code blocks */
|
|
74
|
-
'aria-label'?: string;
|
|
75
|
-
/** Class name applied to code blocks */
|
|
76
|
-
className?: string;
|
|
77
|
-
/** Whether code blocks are expandable */
|
|
78
|
-
isExpandable?: boolean;
|
|
79
|
-
/** Length of text initially shown in expandable code blocks; defaults to 10 characters */
|
|
80
|
-
maxLength?: number;
|
|
81
|
-
/** Additional props passed to expandable section if isExpandable is applied */
|
|
82
|
-
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
|
|
83
|
-
/** Additional props passed to expandable toggle if isExpandable is applied */
|
|
84
|
-
expandableSectionToggleProps?: ExpandableSectionToggleProps;
|
|
85
|
-
/** Link text applied to expandable toggle when expanded */
|
|
86
|
-
expandedText?: string;
|
|
87
|
-
/** Link text applied to expandable toggle when collapsed */
|
|
88
|
-
collapsedText?: string;
|
|
89
|
-
};
|
|
74
|
+
codeBlockProps?: CodeBlockMessageProps;
|
|
90
75
|
/** Props for quick responses */
|
|
91
76
|
quickResponses?: QuickResponse[];
|
|
92
77
|
/** Props for quick responses container */
|
|
@@ -160,6 +145,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
|
|
|
160
145
|
toolCall?: ToolCallProps;
|
|
161
146
|
/** Whether user messages default to stripping out images in markdown */
|
|
162
147
|
hasNoImagesInUserMessages?: boolean;
|
|
148
|
+
/** Sets background colors to be appropriate on primary chatbot background */
|
|
149
|
+
isPrimary?: boolean;
|
|
163
150
|
}
|
|
164
151
|
export declare const MessageBase: FunctionComponent<MessageProps>;
|
|
165
152
|
declare const Message: import("react").ForwardRefExoticComponent<Omit<MessageProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -46,6 +46,9 @@ const ImageMessage_1 = __importDefault(require("./ImageMessage/ImageMessage"));
|
|
|
46
46
|
const rehype_unwrap_images_1 = __importDefault(require("rehype-unwrap-images"));
|
|
47
47
|
const rehype_external_links_1 = __importDefault(require("rehype-external-links"));
|
|
48
48
|
const rehype_sanitize_1 = __importDefault(require("rehype-sanitize"));
|
|
49
|
+
const rehype_highlight_1 = __importDefault(require("rehype-highlight"));
|
|
50
|
+
// see the full list of styles here: https://highlightjs.org/examples
|
|
51
|
+
require("highlight.js/styles/vs2015.css");
|
|
49
52
|
const LinkMessage_1 = __importDefault(require("./LinkMessage/LinkMessage"));
|
|
50
53
|
const ErrorMessage_1 = __importDefault(require("./ErrorMessage/ErrorMessage"));
|
|
51
54
|
const MessageInput_1 = __importDefault(require("./MessageInput"));
|
|
@@ -55,13 +58,13 @@ const DeepThinking_1 = __importDefault(require("../DeepThinking"));
|
|
|
55
58
|
const SuperscriptMessage_1 = __importDefault(require("./SuperscriptMessage/SuperscriptMessage"));
|
|
56
59
|
const ToolCall_1 = __importDefault(require("../ToolCall"));
|
|
57
60
|
const MessageBase = (_a) => {
|
|
58
|
-
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 = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps, toolCall, hasNoImagesInUserMessages = true } = _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", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps", "toolCall", "hasNoImagesInUserMessages"]);
|
|
61
|
+
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 = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps, toolCall, hasNoImagesInUserMessages = true, isPrimary } = _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", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps", "toolCall", "hasNoImagesInUserMessages", "isPrimary"]);
|
|
59
62
|
const [messageText, setMessageText] = (0, react_1.useState)(content);
|
|
60
63
|
(0, react_1.useEffect)(() => {
|
|
61
64
|
setMessageText(content);
|
|
62
65
|
}, [content]);
|
|
63
66
|
const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
|
|
64
|
-
let rehypePlugins = [rehype_unwrap_images_1.default, rehypeMoveImagesOutOfParagraphs_1.rehypeMoveImagesOutOfParagraphs];
|
|
67
|
+
let rehypePlugins = [rehype_unwrap_images_1.default, rehypeMoveImagesOutOfParagraphs_1.rehypeMoveImagesOutOfParagraphs, rehype_highlight_1.default];
|
|
65
68
|
if (openLinkInNewTab) {
|
|
66
69
|
rehypePlugins = rehypePlugins.concat([[rehype_external_links_1.default, { target: '_blank' }, rehype_sanitize_1.default]]);
|
|
67
70
|
}
|
|
@@ -94,13 +97,13 @@ const MessageBase = (_a) => {
|
|
|
94
97
|
p: (props) => {
|
|
95
98
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
96
99
|
const { node } = props, rest = __rest(props, ["node"]);
|
|
97
|
-
return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, rest));
|
|
100
|
+
return (0, jsx_runtime_1.jsx)(TextMessage_1.default, Object.assign({ component: react_core_1.ContentVariants.p }, rest, { isPrimary: isPrimary }));
|
|
98
101
|
},
|
|
99
102
|
code: (_a) => {
|
|
100
103
|
var { children } = _a, props = __rest(_a, ["children"]);
|
|
101
104
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
102
105
|
const { node } = props, codeProps = __rest(props, ["node"]);
|
|
103
|
-
return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, codeProps, codeBlockProps, { children: children })));
|
|
106
|
+
return ((0, jsx_runtime_1.jsx)(CodeBlockMessage_1.default, Object.assign({}, codeProps, codeBlockProps, { isPrimary: isPrimary, children: children })));
|
|
104
107
|
},
|
|
105
108
|
h1: (props) => {
|
|
106
109
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -153,7 +156,7 @@ const MessageBase = (_a) => {
|
|
|
153
156
|
return (0, jsx_runtime_1.jsx)(ListItemMessage_1.default, Object.assign({}, rest));
|
|
154
157
|
},
|
|
155
158
|
// table requires node attribute for calculating headers for mobile breakpoint
|
|
156
|
-
table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps)),
|
|
159
|
+
table: (props) => (0, jsx_runtime_1.jsx)(TableMessage_1.default, Object.assign({}, props, tableProps, { isPrimary: isPrimary })),
|
|
157
160
|
tbody: (props) => {
|
|
158
161
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
159
162
|
const { node } = props, rest = __rest(props, ["node"]);
|
|
@@ -206,7 +209,7 @@ const MessageBase = (_a) => {
|
|
|
206
209
|
};
|
|
207
210
|
const renderMessage = () => {
|
|
208
211
|
if (isLoading) {
|
|
209
|
-
return (0, jsx_runtime_1.jsx)(MessageLoading_1.default, { loadingWord: loadingWord });
|
|
212
|
+
return (0, jsx_runtime_1.jsx)(MessageLoading_1.default, { loadingWord: loadingWord, isPrimary: isPrimary });
|
|
210
213
|
}
|
|
211
214
|
if (isEditable) {
|
|
212
215
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [beforeMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: beforeMainContent }), (0, jsx_runtime_1.jsx)(MessageInput_1.default, Object.assign({ content: messageText, editPlaceholder: editPlaceholder, updateWord: updateWord, cancelWord: cancelWord, onEditUpdate: (event, value) => {
|
|
@@ -218,7 +221,7 @@ const MessageBase = (_a) => {
|
|
|
218
221
|
};
|
|
219
222
|
return ((0, jsx_runtime_1.jsxs)("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}`, "aria-live": isLiveRegion ? 'polite' : undefined, "aria-atomic": isLiveRegion ? false : undefined, ref: innerRef }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps)), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-contents", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-meta", children: [name && ((0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__message-name", children: (0, jsx_runtime_1.jsx)(react_core_1.Truncate, { content: name }) })), role === 'bot' && ((0, jsx_runtime_1.jsx)(react_core_1.Label, { variant: "outline", isCompact: true, children: botWord })), (0, jsx_runtime_1.jsx)(react_core_1.Timestamp, { date: date, children: timestamp })] }), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-response", children: [(0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__message-and-actions", children: [renderMessage(), afterMainContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: afterMainContent }), toolResponse && (0, jsx_runtime_1.jsx)(ToolResponse_1.default, Object.assign({}, toolResponse)), deepThinking && (0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, deepThinking)), toolCall && (0, jsx_runtime_1.jsx)(ToolCall_1.default, Object.assign({}, toolCall)), !isLoading && sources && (0, jsx_runtime_1.jsx)(SourcesCard_1.default, Object.assign({}, sources, { isCompact: isCompact })), quickStarts && quickStarts.quickStart && ((0, jsx_runtime_1.jsx)(QuickStartTile_1.default, { quickStart: quickStarts.quickStart, onSelectQuickStart: quickStarts.onSelectQuickStart, minuteWord: quickStarts.minuteWord, minuteWordPlural: quickStarts.minuteWordPlural, prerequisiteWord: quickStarts.prerequisiteWord, prerequisiteWordPlural: quickStarts.prerequisiteWordPlural, quickStartButtonAriaLabel: quickStarts.quickStartButtonAriaLabel, isCompact: isCompact })), !isLoading && !isEditable && actions && (0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actions }), userFeedbackForm && (0, jsx_runtime_1.jsx)(UserFeedback_1.default, Object.assign({}, userFeedbackForm, { timestamp: dateString, isCompact: isCompact })), userFeedbackComplete && ((0, jsx_runtime_1.jsx)(UserFeedbackComplete_1.default, Object.assign({}, userFeedbackComplete, { timestamp: dateString, isCompact: isCompact }))), !isLoading && quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, isCompact: isCompact }))] }), attachments && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachments-container", children: attachments.map((attachment) => {
|
|
220
223
|
var _a;
|
|
221
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachment", children: (0, jsx_runtime_1.jsx)(FileDetailsLabel_1.default, { fileName: attachment.name, fileId: attachment.id, onClose: attachment.onClose, onClick: attachment.onClick, isLoading: attachment.isLoading, closeButtonAriaLabel: attachment.closeButtonAriaLabel, languageTestId: attachment.languageTestId, spinnerTestId: attachment.spinnerTestId }) }, (_a = attachment.id) !== null && _a !== void 0 ? _a : attachment.name));
|
|
224
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-attachment", children: (0, jsx_runtime_1.jsx)(FileDetailsLabel_1.default, { fileName: attachment.name, fileId: attachment.id, onClose: attachment.onClose, onClick: attachment.onClick, isLoading: attachment.isLoading, closeButtonAriaLabel: attachment.closeButtonAriaLabel, languageTestId: attachment.languageTestId, spinnerTestId: attachment.spinnerTestId, variant: isPrimary ? 'outline' : undefined }) }, (_a = attachment.id) !== null && _a !== void 0 ? _a : attachment.name));
|
|
222
225
|
}) })), !isLoading && endContent && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: endContent })] })] })] })));
|
|
223
226
|
};
|
|
224
227
|
exports.MessageBase = MessageBase;
|
|
@@ -493,6 +493,12 @@ describe('Message', () => {
|
|
|
493
493
|
(0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { 'aria-label': 'test' } }));
|
|
494
494
|
expect(react_2.screen.getByRole('button', { name: 'test' })).toBeTruthy();
|
|
495
495
|
});
|
|
496
|
+
it('should be able to add custom actions to CodeMessage', () => {
|
|
497
|
+
(0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: {
|
|
498
|
+
customActions: ((0, jsx_runtime_1.jsx)(react_core_1.CodeBlockAction, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, { children: "New custom action" }) }))
|
|
499
|
+
} }));
|
|
500
|
+
expect(react_2.screen.getByRole('button', { name: /New custom action/i })).toBeTruthy();
|
|
501
|
+
});
|
|
496
502
|
it('should handle hasRoundAvatar correctly when it is true', () => {
|
|
497
503
|
(0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", hasRoundAvatar: true }));
|
|
498
504
|
expect(react_2.screen.getByRole('img')).toBeTruthy();
|
|
@@ -825,4 +831,36 @@ describe('Message', () => {
|
|
|
825
831
|
expect(react_2.screen.getByText('Thought for 3 seconds')).toBeTruthy();
|
|
826
832
|
expect(react_2.screen.getByText("Here's why I said this.")).toBeTruthy();
|
|
827
833
|
});
|
|
834
|
+
it('should handle isPrimary correctly for inline code when it is true', () => {
|
|
835
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: INLINE_CODE, isPrimary: true }));
|
|
836
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
837
|
+
});
|
|
838
|
+
it('should handle isPrimary correctly for inline code when it is false', () => {
|
|
839
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: INLINE_CODE }));
|
|
840
|
+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
|
|
841
|
+
});
|
|
842
|
+
it('should handle isPrimary correctly for table when it is true', () => {
|
|
843
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: TABLE, isPrimary: true }));
|
|
844
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
845
|
+
});
|
|
846
|
+
it('should handle isPrimary correctly for table when it is false', () => {
|
|
847
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: TABLE }));
|
|
848
|
+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
|
|
849
|
+
});
|
|
850
|
+
it('should handle isPrimary correctly for loading when it is true', () => {
|
|
851
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isPrimary: true, isLoading: true }));
|
|
852
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
853
|
+
});
|
|
854
|
+
it('should handle isPrimary correctly for loading when it is false', () => {
|
|
855
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isLoading: true }));
|
|
856
|
+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
|
|
857
|
+
});
|
|
858
|
+
it('should handle isPrimary correctly for attachments when it is true', () => {
|
|
859
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", isPrimary: true, attachments: [{ name: 'testAttachment' }] }));
|
|
860
|
+
expect(container.querySelector('.pf-m-outline')).toBeTruthy();
|
|
861
|
+
});
|
|
862
|
+
it('should handle isPrimary correctly for attachments when it is false', () => {
|
|
863
|
+
const { container } = (0, react_2.render)((0, jsx_runtime_1.jsx)(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "", attachments: [{ name: 'testAttachment' }] }));
|
|
864
|
+
expect(container.querySelector('.pf-m-outline')).toBeFalsy();
|
|
865
|
+
});
|
|
828
866
|
});
|
|
@@ -4,5 +4,5 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
4
4
|
// ============================================================================
|
|
5
5
|
// Chatbot Main - Message - Processing
|
|
6
6
|
// ============================================================================
|
|
7
|
-
const MessageLoading = ({ loadingWord }) => ((0, jsx_runtime_1.jsx)("div", { className:
|
|
7
|
+
const MessageLoading = ({ loadingWord, isPrimary }) => ((0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-loading ${isPrimary ? 'pf-m-primary' : ''}`, children: (0, jsx_runtime_1.jsx)("span", { className: "pf-chatbot__message-loading-dots", children: (0, jsx_runtime_1.jsx)("span", { className: "pf-v6-screen-reader", children: loadingWord }) }) }));
|
|
8
8
|
exports.default = MessageLoading;
|
|
@@ -15,5 +15,8 @@ export interface TableNode {
|
|
|
15
15
|
tagName: string;
|
|
16
16
|
type: string;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
export interface TableMessageProps {
|
|
19
|
+
isPrimary?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare const TableMessage: ({ children, isPrimary, ...props }: Omit<TableProps, "ref"> & ExtraProps & TableMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
22
|
export default TableMessage;
|
|
@@ -19,7 +19,7 @@ const react_1 = require("react");
|
|
|
19
19
|
const react_table_1 = require("@patternfly/react-table");
|
|
20
20
|
const TableMessage = (_a) => {
|
|
21
21
|
var _b;
|
|
22
|
-
var { children } = _a, props = __rest(_a, ["children"]);
|
|
22
|
+
var { children, isPrimary } = _a, props = __rest(_a, ["children", "isPrimary"]);
|
|
23
23
|
const { className } = props, rest = __rest(props, ["className"]);
|
|
24
24
|
// This allows us to parse the nested data we get back from the 3rd party Markdown parser
|
|
25
25
|
// Open to feedback here if there is a better way to do this
|
|
@@ -60,6 +60,6 @@ const TableMessage = (_a) => {
|
|
|
60
60
|
}
|
|
61
61
|
return (
|
|
62
62
|
// gridBreakPoint is so we show mobile-styled-PF table
|
|
63
|
-
(0, jsx_runtime_1.jsx)(react_table_1.Table, Object.assign({ "aria-label": props['aria-label'], gridBreakPoint: "grid", className: `pf-chatbot__message-table ${className ? className : ''}` }, rest, { children: modifyChildren(children) })));
|
|
63
|
+
(0, jsx_runtime_1.jsx)(react_table_1.Table, Object.assign({ "aria-label": props['aria-label'], gridBreakPoint: "grid", className: `pf-chatbot__message-table ${isPrimary ? 'pf-m-primary' : ''} ${className ? className : ''}` }, rest, { children: modifyChildren(children) })));
|
|
64
64
|
};
|
|
65
65
|
exports.default = TableMessage;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { ExtraProps } from 'react-markdown';
|
|
2
2
|
import { ContentProps } from '@patternfly/react-core';
|
|
3
|
-
|
|
3
|
+
export interface TextMessageProps {
|
|
4
|
+
isPrimary?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const TextMessage: ({ component, children, isPrimary, ...props }: Omit<ContentProps, "ref"> & ExtraProps & TextMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
7
|
export default TextMessage;
|
|
@@ -14,7 +14,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
15
15
|
const react_core_1 = require("@patternfly/react-core");
|
|
16
16
|
const TextMessage = (_a) => {
|
|
17
|
-
var { component, children } = _a, props = __rest(_a, ["component", "children"]);
|
|
18
|
-
return ((0, jsx_runtime_1.jsx)("span", { className:
|
|
17
|
+
var { component, children, isPrimary } = _a, props = __rest(_a, ["component", "children", "isPrimary"]);
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("span", { className: `pf-chatbot__message-text ${isPrimary ? 'pf-m-primary' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.Content, Object.assign({ component: component }, props, { children: children })) }));
|
|
19
19
|
};
|
|
20
20
|
exports.default = TextMessage;
|
|
@@ -41,5 +41,7 @@ export interface AttachButtonProps extends ButtonProps {
|
|
|
41
41
|
validator?: <T extends File>(file: T) => FileError | readonly FileError[] | null;
|
|
42
42
|
/** Additional props passed to react-dropzone */
|
|
43
43
|
dropzoneProps?: DropzoneOptions;
|
|
44
|
+
/** Icon displayed in attach button */
|
|
45
|
+
icon?: React.ReactNode;
|
|
44
46
|
}
|
|
45
47
|
export declare const AttachButton: import("react").ForwardRefExoticComponent<AttachButtonProps & import("react").RefAttributes<any>>;
|
|
@@ -19,12 +19,12 @@ const react_core_1 = require("@patternfly/react-core");
|
|
|
19
19
|
const react_dropzone_1 = require("react-dropzone");
|
|
20
20
|
const paperclip_icon_1 = require("@patternfly/react-icons/dist/esm/icons/paperclip-icon");
|
|
21
21
|
const AttachButtonBase = (_a) => {
|
|
22
|
-
var { onAttachAccepted, onClick, isDisabled, className, tooltipProps, innerRef, tooltipContent = 'Attach', inputTestId, isCompact, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps } = _a, props = __rest(_a, ["onAttachAccepted", "onClick", "isDisabled", "className", "tooltipProps", "innerRef", "tooltipContent", "inputTestId", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps"]);
|
|
22
|
+
var { onAttachAccepted, onClick, isDisabled, className, tooltipProps, innerRef, tooltipContent = 'Attach', inputTestId, isCompact, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps, icon = (0, jsx_runtime_1.jsx)(paperclip_icon_1.PaperclipIcon, {}) } = _a, props = __rest(_a, ["onAttachAccepted", "onClick", "isDisabled", "className", "tooltipProps", "innerRef", "tooltipContent", "inputTestId", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps", "icon"]);
|
|
23
23
|
const { open, getInputProps } = (0, react_dropzone_1.useDropzone)(Object.assign({ multiple: true, onDropAccepted: onAttachAccepted, accept: allowedFileTypes, minSize,
|
|
24
24
|
maxSize,
|
|
25
25
|
maxFiles, disabled: isAttachmentDisabled, onDrop: onAttach, onDropRejected: onAttachRejected, validator }, dropzoneProps));
|
|
26
26
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", Object.assign({ "data-testid": inputTestId }, getInputProps(), { hidden: true })), (0, jsx_runtime_1.jsx)(react_core_1.Tooltip, Object.assign({ id: "pf-chatbot__tooltip--attach", content: tooltipContent, position: "top", entryDelay: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.entryDelay) || 0, exitDelay: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.exitDelay) || 0, distance: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.distance) || 8, animationDuration: (tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.animationDuration) || 0,
|
|
27
27
|
// prevents VO announcements of both aria label and tooltip
|
|
28
|
-
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ variant: "plain", ref: innerRef, className: `pf-chatbot__button--attach ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": props['aria-label'] || 'Attach', isDisabled: isDisabled, onClick: onClick !== null && onClick !== void 0 ? onClick : open, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children:
|
|
28
|
+
aria: "none" }, tooltipProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ variant: "plain", ref: innerRef, className: `pf-chatbot__button--attach ${isCompact ? 'pf-m-compact' : ''} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": props['aria-label'] || 'Attach', isDisabled: isDisabled, onClick: onClick !== null && onClick !== void 0 ? onClick : open, icon: (0, jsx_runtime_1.jsx)(react_core_1.Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children: icon }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
|
|
29
29
|
};
|
|
30
30
|
exports.AttachButton = (0, react_1.forwardRef)((props, ref) => ((0, jsx_runtime_1.jsx)(AttachButtonBase, Object.assign({ innerRef: ref }, props))));
|
|
@@ -145,4 +145,8 @@ describe('Attach button', () => {
|
|
|
145
145
|
expect(validator).toHaveBeenCalledWith(file);
|
|
146
146
|
expect(onAttachRejected).toHaveBeenCalled();
|
|
147
147
|
}));
|
|
148
|
+
it('should handle icon prop', () => {
|
|
149
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, { icon: (0, jsx_runtime_1.jsx)("img", { alt: "", src: "" }) }));
|
|
150
|
+
expect(react_1.screen.getByRole('img')).toBeVisible();
|
|
151
|
+
});
|
|
148
152
|
});
|