@patternfly/chatbot 6.5.0-prerelease.7 → 6.5.0-prerelease.8

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.
@@ -4,7 +4,7 @@ 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: (value: string) => void;
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 */
@@ -17,7 +17,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
17
17
  const react_core_1 = require("@patternfly/react-core");
18
18
  const AttachMenu = (_a) => {
19
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: [(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] })));
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;
@@ -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: (0, jsx_runtime_1.jsx)(paperclip_icon_1.PaperclipIcon, {}) }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
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
  });
@@ -1,6 +1,7 @@
1
1
  import type { FunctionComponent } from 'react';
2
2
  import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
3
3
  import { ButtonProps, MenuSearchInputProps, MenuSearchProps, SearchInputProps, TextAreaProps, TooltipProps } from '@patternfly/react-core';
4
+ import { AttachButtonProps } from './AttachButton';
4
5
  import { ChatbotDisplayMode } from '../Chatbot';
5
6
  export interface MessageBarWithAttachMenuProps {
6
7
  /** Flag to enable whether attach menu is open */
@@ -12,7 +13,7 @@ export interface MessageBarWithAttachMenuProps {
12
13
  /** A callback for when the attachment menu toggle is clicked */
13
14
  onAttachMenuToggleClick: () => void;
14
15
  /** A callback for when the input value in the menu changes. */
15
- onAttachMenuInputChange: (value: string) => void;
16
+ onAttachMenuInputChange?: (value: string) => void;
16
17
  /** Function callback called when user selects item in menu. */
17
18
  onAttachMenuSelect?: (event?: React.MouseEvent<Element, MouseEvent>, value?: string | number) => void;
18
19
  /** Placeholder for search input */
@@ -77,11 +78,8 @@ export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
77
78
  isSendButtonDisabled?: boolean;
78
79
  /** Prop to allow passage of additional props to buttons */
79
80
  buttonProps?: {
80
- attach?: {
81
- tooltipContent?: string;
81
+ attach?: AttachButtonProps & {
82
82
  props?: ButtonProps;
83
- inputTestId?: string;
84
- tooltipProps?: Omit<TooltipProps, 'content'>;
85
83
  };
86
84
  stop?: {
87
85
  tooltipContent?: string;
@@ -193,11 +193,11 @@ const MessageBarBase = (_a) => {
193
193
  onChange && onChange({}, message);
194
194
  };
195
195
  const renderButtons = () => {
196
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
196
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
197
197
  if (hasStopButton && handleStopButton) {
198
198
  return ((0, jsx_runtime_1.jsx)(StopButton_1.default, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact, tooltipProps: (_b = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _b === void 0 ? void 0 : _b.tooltipProps }, (_c = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _c === void 0 ? void 0 : _c.props)));
199
199
  }
200
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [attachMenuProps && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))), !attachMenuProps && hasAttachButton && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))), hasMicrophoneButton && ((0, jsx_runtime_1.jsx)(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))), (alwayShowSendButton || message) && ((0, jsx_runtime_1.jsx)(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))] }));
200
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [attachMenuProps && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach))), !attachMenuProps && hasAttachButton && ((0, jsx_runtime_1.jsx)(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.tooltipContent, inputTestId: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.inputTestId, isCompact: isCompact, tooltipProps: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach, (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.props))), hasMicrophoneButton && ((0, jsx_runtime_1.jsx)(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _k === void 0 ? void 0 : _k.tooltipContent, language: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.language, isCompact: isCompact, tooltipProps: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.tooltipProps }, (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.props))), (alwayShowSendButton || message) && ((0, jsx_runtime_1.jsx)(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _p === void 0 ? void 0 : _p.tooltipContent, isCompact: isCompact, tooltipProps: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipProps }, (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.props)))] }));
201
201
  };
202
202
  const messageBarContents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: (0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd }, props)) }), (0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
203
203
  if (attachMenuProps) {
@@ -192,6 +192,15 @@ describe('Message bar', () => {
192
192
  } }));
193
193
  expect(react_1.screen.getByTestId('menu-search-input')).toBeTruthy();
194
194
  });
195
+ it('can remove input from attach menu', () => __awaiter(void 0, void 0, void 0, function* () {
196
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageBar_1.MessageBar, { onSendMessage: jest.fn, attachMenuProps: {
197
+ isAttachMenuOpen: true,
198
+ setIsAttachMenuOpen: jest.fn(),
199
+ onAttachMenuToggleClick: jest.fn(),
200
+ attachMenuItems: ATTACH_MENU_ITEMS
201
+ } }));
202
+ expect(react_1.screen.queryByRole('textbox', { name: /Filter menu items/i })).not.toBeInTheDocument();
203
+ }));
195
204
  it('can hide attach button', () => {
196
205
  (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasAttachButton: false }));
197
206
  expect(react_1.screen.queryByRole('button', { name: 'Attach' })).toBeFalsy();
@@ -223,6 +232,14 @@ describe('Message bar', () => {
223
232
  (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: { attach: { props: { 'aria-label': 'Test' } } } }));
224
233
  yield user_event_1.default.click(react_1.screen.getByRole('button', { name: 'Test' }));
225
234
  }));
235
+ it('can change attach button icon', () => {
236
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: {
237
+ attach: {
238
+ icon: (0, jsx_runtime_1.jsx)("img", { alt: "", src: "" })
239
+ }
240
+ } }));
241
+ expect(react_1.screen.getByRole('img')).toBeVisible();
242
+ });
226
243
  // Stop button
227
244
  // --------------------------------------------------------------------------
228
245
  it('can show stop button', () => {
@@ -4,7 +4,7 @@ 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: (value: string) => void;
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 */
@@ -14,6 +14,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { MenuSearch, MenuSearchInput, SearchInput, Dropdown } from '@patternfly/react-core';
15
15
  export const AttachMenu = (_a) => {
16
16
  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"]);
17
- return (_jsxs(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: [_jsx(MenuSearch, Object.assign({}, menuSearchProps, { children: _jsx(MenuSearchInput, Object.assign({}, menuSearchInputProps, { children: _jsx(SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) })) })), filteredItems] })));
17
+ return (_jsxs(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 && (_jsx(MenuSearch, Object.assign({}, menuSearchProps, { children: _jsx(MenuSearchInput, Object.assign({}, menuSearchInputProps, { children: _jsx(SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) })) }))), filteredItems] })));
18
18
  };
19
19
  export default AttachMenu;
@@ -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>>;
@@ -16,12 +16,12 @@ import { Button, Icon, Tooltip } from '@patternfly/react-core';
16
16
  import { useDropzone } from 'react-dropzone';
17
17
  import { PaperclipIcon } from '@patternfly/react-icons/dist/esm/icons/paperclip-icon';
18
18
  const AttachButtonBase = (_a) => {
19
- 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"]);
19
+ var { onAttachAccepted, onClick, isDisabled, className, tooltipProps, innerRef, tooltipContent = 'Attach', inputTestId, isCompact, allowedFileTypes, minSize, maxSize, maxFiles, isAttachmentDisabled, onAttach, onAttachRejected, validator, dropzoneProps, icon = _jsx(PaperclipIcon, {}) } = _a, props = __rest(_a, ["onAttachAccepted", "onClick", "isDisabled", "className", "tooltipProps", "innerRef", "tooltipContent", "inputTestId", "isCompact", "allowedFileTypes", "minSize", "maxSize", "maxFiles", "isAttachmentDisabled", "onAttach", "onAttachRejected", "validator", "dropzoneProps", "icon"]);
20
20
  const { open, getInputProps } = useDropzone(Object.assign({ multiple: true, onDropAccepted: onAttachAccepted, accept: allowedFileTypes, minSize,
21
21
  maxSize,
22
22
  maxFiles, disabled: isAttachmentDisabled, onDrop: onAttach, onDropRejected: onAttachRejected, validator }, dropzoneProps));
23
23
  return (_jsxs(_Fragment, { children: [_jsx("input", Object.assign({ "data-testid": inputTestId }, getInputProps(), { hidden: true })), _jsx(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,
24
24
  // prevents VO announcements of both aria label and tooltip
25
- aria: "none" }, tooltipProps, { children: _jsx(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: _jsx(Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children: _jsx(PaperclipIcon, {}) }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
25
+ aria: "none" }, tooltipProps, { children: _jsx(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: _jsx(Icon, { iconSize: isCompact ? 'lg' : 'xl', isInline: true, children: icon }), size: isCompact ? 'sm' : undefined }, props)) }))] }));
26
26
  };
27
27
  export const AttachButton = forwardRef((props, ref) => (_jsx(AttachButtonBase, Object.assign({ innerRef: ref }, props))));
@@ -140,4 +140,8 @@ describe('Attach button', () => {
140
140
  expect(validator).toHaveBeenCalledWith(file);
141
141
  expect(onAttachRejected).toHaveBeenCalled();
142
142
  }));
143
+ it('should handle icon prop', () => {
144
+ render(_jsx(AttachButton, { icon: _jsx("img", { alt: "", src: "" }) }));
145
+ expect(screen.getByRole('img')).toBeVisible();
146
+ });
143
147
  });
@@ -1,6 +1,7 @@
1
1
  import type { FunctionComponent } from 'react';
2
2
  import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection } from 'react-dropzone';
3
3
  import { ButtonProps, MenuSearchInputProps, MenuSearchProps, SearchInputProps, TextAreaProps, TooltipProps } from '@patternfly/react-core';
4
+ import { AttachButtonProps } from './AttachButton';
4
5
  import { ChatbotDisplayMode } from '../Chatbot';
5
6
  export interface MessageBarWithAttachMenuProps {
6
7
  /** Flag to enable whether attach menu is open */
@@ -12,7 +13,7 @@ export interface MessageBarWithAttachMenuProps {
12
13
  /** A callback for when the attachment menu toggle is clicked */
13
14
  onAttachMenuToggleClick: () => void;
14
15
  /** A callback for when the input value in the menu changes. */
15
- onAttachMenuInputChange: (value: string) => void;
16
+ onAttachMenuInputChange?: (value: string) => void;
16
17
  /** Function callback called when user selects item in menu. */
17
18
  onAttachMenuSelect?: (event?: React.MouseEvent<Element, MouseEvent>, value?: string | number) => void;
18
19
  /** Placeholder for search input */
@@ -77,11 +78,8 @@ export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
77
78
  isSendButtonDisabled?: boolean;
78
79
  /** Prop to allow passage of additional props to buttons */
79
80
  buttonProps?: {
80
- attach?: {
81
- tooltipContent?: string;
81
+ attach?: AttachButtonProps & {
82
82
  props?: ButtonProps;
83
- inputTestId?: string;
84
- tooltipProps?: Omit<TooltipProps, 'content'>;
85
83
  };
86
84
  stop?: {
87
85
  tooltipContent?: string;
@@ -187,11 +187,11 @@ export const MessageBarBase = (_a) => {
187
187
  onChange && onChange({}, message);
188
188
  };
189
189
  const renderButtons = () => {
190
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
190
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
191
191
  if (hasStopButton && handleStopButton) {
192
192
  return (_jsx(StopButton, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact, tooltipProps: (_b = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _b === void 0 ? void 0 : _b.tooltipProps }, (_c = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _c === void 0 ? void 0 : _c.props)));
193
193
  }
194
- return (_jsxs(_Fragment, { children: [attachMenuProps && (_jsx(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))), !attachMenuProps && hasAttachButton && (_jsx(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))), hasMicrophoneButton && (_jsx(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))), (alwayShowSendButton || message) && (_jsx(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))] }));
194
+ return (_jsxs(_Fragment, { children: [attachMenuProps && (_jsx(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach))), !attachMenuProps && hasAttachButton && (_jsx(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.tooltipContent, inputTestId: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.inputTestId, isCompact: isCompact, tooltipProps: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.tooltipProps, allowedFileTypes: allowedFileTypes, minSize: minSize, maxSize: maxSize, maxFiles: maxFiles, isAttachmentDisabled: isAttachmentDisabled, onAttach: onAttach, onAttachRejected: onAttachRejected, validator: validator, dropzoneProps: dropzoneProps }, buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach, (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.props))), hasMicrophoneButton && (_jsx(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _k === void 0 ? void 0 : _k.tooltipContent, language: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.language, isCompact: isCompact, tooltipProps: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.tooltipProps }, (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.props))), (alwayShowSendButton || message) && (_jsx(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _p === void 0 ? void 0 : _p.tooltipContent, isCompact: isCompact, tooltipProps: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipProps }, (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.props)))] }));
195
195
  };
196
196
  const messageBarContents = (_jsxs(_Fragment, { children: [_jsx("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}`, children: _jsx(TextArea, Object.assign({ className: "pf-chatbot__message-textarea", value: message, onChange: handleChange, "aria-label": isListeningMessage ? listeningText : placeholder, placeholder: isListeningMessage ? listeningText : placeholder, ref: textareaRef, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd }, props)) }), _jsx("div", { className: "pf-chatbot__message-bar-actions", children: renderButtons() })] }));
197
197
  if (attachMenuProps) {
@@ -187,6 +187,15 @@ describe('Message bar', () => {
187
187
  } }));
188
188
  expect(screen.getByTestId('menu-search-input')).toBeTruthy();
189
189
  });
190
+ it('can remove input from attach menu', () => __awaiter(void 0, void 0, void 0, function* () {
191
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, attachMenuProps: {
192
+ isAttachMenuOpen: true,
193
+ setIsAttachMenuOpen: jest.fn(),
194
+ onAttachMenuToggleClick: jest.fn(),
195
+ attachMenuItems: ATTACH_MENU_ITEMS
196
+ } }));
197
+ expect(screen.queryByRole('textbox', { name: /Filter menu items/i })).not.toBeInTheDocument();
198
+ }));
190
199
  it('can hide attach button', () => {
191
200
  render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: false }));
192
201
  expect(screen.queryByRole('button', { name: 'Attach' })).toBeFalsy();
@@ -218,6 +227,14 @@ describe('Message bar', () => {
218
227
  render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: { attach: { props: { 'aria-label': 'Test' } } } }));
219
228
  yield userEvent.click(screen.getByRole('button', { name: 'Test' }));
220
229
  }));
230
+ it('can change attach button icon', () => {
231
+ render(_jsx(MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: {
232
+ attach: {
233
+ icon: _jsx("img", { alt: "", src: "" })
234
+ }
235
+ } }));
236
+ expect(screen.getByRole('img')).toBeVisible();
237
+ });
221
238
  // Stop button
222
239
  // --------------------------------------------------------------------------
223
240
  it('can show stop button', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.5.0-prerelease.7",
3
+ "version": "6.5.0-prerelease.8",
4
4
  "description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -366,7 +366,9 @@ Setting up cluster console...`;
366
366
  <FlexItem>{stage.name}</FlexItem>
367
367
  </Flex>
368
368
  </AccordionToggle>
369
- <AccordionContent id={stage.id.replace('-toggle', '')}>{renderCodeBlock(stage)}</AccordionContent>
369
+ <AccordionContent id={stage.id.replace('-toggle', '')} style={{ border: '0px' }}>
370
+ {renderCodeBlock(stage)}
371
+ </AccordionContent>
370
372
  </AccordionItem>
371
373
  ))}
372
374
  </Accordion>
@@ -21,7 +21,7 @@ export interface AttachMenuProps extends DropdownProps {
21
21
  /** Items in menu */
22
22
  filteredItems: React.ReactNode;
23
23
  /** A callback for when the input value changes. */
24
- handleTextInputChange: (value: string) => void;
24
+ handleTextInputChange?: (value: string) => void;
25
25
  /** Flag to indicate if menu is opened. */
26
26
  isOpen: boolean;
27
27
  /** Additional properties to pass to the Popper */
@@ -73,16 +73,18 @@ export const AttachMenu: FunctionComponent<AttachMenuProps> = ({
73
73
  onSelect={onSelect}
74
74
  {...props}
75
75
  >
76
- <MenuSearch {...menuSearchProps}>
77
- <MenuSearchInput {...menuSearchInputProps}>
78
- <SearchInput
79
- aria-label={searchInputAriaLabel}
80
- onChange={(_event, value) => handleTextInputChange(value)}
81
- placeholder={searchInputPlaceholder}
82
- {...searchInputProps}
83
- />
84
- </MenuSearchInput>
85
- </MenuSearch>
76
+ {handleTextInputChange && (
77
+ <MenuSearch {...menuSearchProps}>
78
+ <MenuSearchInput {...menuSearchInputProps}>
79
+ <SearchInput
80
+ aria-label={searchInputAriaLabel}
81
+ onChange={(_event, value) => handleTextInputChange(value)}
82
+ placeholder={searchInputPlaceholder}
83
+ {...searchInputProps}
84
+ />
85
+ </MenuSearchInput>
86
+ </MenuSearch>
87
+ )}
86
88
  {filteredItems}
87
89
  </Dropdown>
88
90
  );
@@ -173,4 +173,8 @@ describe('Attach button', () => {
173
173
  expect(validator).toHaveBeenCalledWith(file);
174
174
  expect(onAttachRejected).toHaveBeenCalled();
175
175
  });
176
+ it('should handle icon prop', () => {
177
+ render(<AttachButton icon={<img alt="" src="" />} />);
178
+ expect(screen.getByRole('img')).toBeVisible();
179
+ });
176
180
  });
@@ -51,6 +51,8 @@ export interface AttachButtonProps extends ButtonProps {
51
51
  validator?: <T extends File>(file: T) => FileError | readonly FileError[] | null;
52
52
  /** Additional props passed to react-dropzone */
53
53
  dropzoneProps?: DropzoneOptions;
54
+ /** Icon displayed in attach button */
55
+ icon?: React.ReactNode;
54
56
  }
55
57
 
56
58
  const AttachButtonBase: FunctionComponent<AttachButtonProps> = ({
@@ -72,6 +74,7 @@ const AttachButtonBase: FunctionComponent<AttachButtonProps> = ({
72
74
  onAttachRejected,
73
75
  validator,
74
76
  dropzoneProps,
77
+ icon = <PaperclipIcon />,
75
78
  ...props
76
79
  }: AttachButtonProps) => {
77
80
  const { open, getInputProps } = useDropzone({
@@ -113,7 +116,7 @@ const AttachButtonBase: FunctionComponent<AttachButtonProps> = ({
113
116
  onClick={onClick ?? open}
114
117
  icon={
115
118
  <Icon iconSize={isCompact ? 'lg' : 'xl'} isInline>
116
- <PaperclipIcon />
119
+ {icon}
117
120
  </Icon>
118
121
  }
119
122
  size={isCompact ? 'sm' : undefined}
@@ -275,6 +275,20 @@ describe('Message bar', () => {
275
275
  );
276
276
  expect(screen.getByTestId('menu-search-input')).toBeTruthy();
277
277
  });
278
+ it('can remove input from attach menu', async () => {
279
+ render(
280
+ <MessageBar
281
+ onSendMessage={jest.fn}
282
+ attachMenuProps={{
283
+ isAttachMenuOpen: true,
284
+ setIsAttachMenuOpen: jest.fn(),
285
+ onAttachMenuToggleClick: jest.fn(),
286
+ attachMenuItems: ATTACH_MENU_ITEMS
287
+ }}
288
+ />
289
+ );
290
+ expect(screen.queryByRole('textbox', { name: /Filter menu items/i })).not.toBeInTheDocument();
291
+ });
278
292
  it('can hide attach button', () => {
279
293
  render(<MessageBar onSendMessage={jest.fn} hasAttachButton={false} />);
280
294
  expect(screen.queryByRole('button', { name: 'Attach' })).toBeFalsy();
@@ -325,6 +339,20 @@ describe('Message bar', () => {
325
339
  );
326
340
  await userEvent.click(screen.getByRole('button', { name: 'Test' }));
327
341
  });
342
+ it('can change attach button icon', () => {
343
+ render(
344
+ <MessageBar
345
+ onSendMessage={jest.fn}
346
+ hasAttachButton
347
+ buttonProps={{
348
+ attach: {
349
+ icon: <img alt="" src="" />
350
+ }
351
+ }}
352
+ />
353
+ );
354
+ expect(screen.getByRole('img')).toBeVisible();
355
+ });
328
356
 
329
357
  // Stop button
330
358
  // --------------------------------------------------------------------------
@@ -14,7 +14,7 @@ import {
14
14
  // Import Chatbot components
15
15
  import SendButton from './SendButton';
16
16
  import MicrophoneButton from './MicrophoneButton';
17
- import { AttachButton } from './AttachButton';
17
+ import { AttachButton, AttachButtonProps } from './AttachButton';
18
18
  import AttachMenu from '../AttachMenu';
19
19
  import StopButton from './StopButton';
20
20
  import { ChatbotDisplayMode } from '../Chatbot';
@@ -29,7 +29,7 @@ export interface MessageBarWithAttachMenuProps {
29
29
  /** A callback for when the attachment menu toggle is clicked */
30
30
  onAttachMenuToggleClick: () => void;
31
31
  /** A callback for when the input value in the menu changes. */
32
- onAttachMenuInputChange: (value: string) => void;
32
+ onAttachMenuInputChange?: (value: string) => void;
33
33
  /** Function callback called when user selects item in menu. */
34
34
  onAttachMenuSelect?: (event?: React.MouseEvent<Element, MouseEvent>, value?: string | number) => void;
35
35
  /** Placeholder for search input */
@@ -95,12 +95,7 @@ export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
95
95
  isSendButtonDisabled?: boolean;
96
96
  /** Prop to allow passage of additional props to buttons */
97
97
  buttonProps?: {
98
- attach?: {
99
- tooltipContent?: string;
100
- props?: ButtonProps;
101
- inputTestId?: string;
102
- tooltipProps?: Omit<TooltipProps, 'content'>;
103
- };
98
+ attach?: AttachButtonProps & { props?: ButtonProps };
104
99
  stop?: { tooltipContent?: string; props?: ButtonProps; tooltipProps?: Omit<TooltipProps, 'content'> };
105
100
  send?: { tooltipContent?: string; props?: ButtonProps; tooltipProps?: Omit<TooltipProps, 'content'> };
106
101
  microphone?: {
@@ -376,7 +371,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
376
371
  onAttachRejected={onAttachRejected}
377
372
  validator={validator}
378
373
  dropzoneProps={dropzoneProps}
379
- {...buttonProps?.attach?.props}
374
+ {...buttonProps?.attach}
380
375
  />
381
376
  )}
382
377
  {!attachMenuProps && hasAttachButton && (
@@ -396,6 +391,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
396
391
  onAttachRejected={onAttachRejected}
397
392
  validator={validator}
398
393
  dropzoneProps={dropzoneProps}
394
+ {...buttonProps?.attach}
399
395
  {...buttonProps?.attach?.props}
400
396
  />
401
397
  )}