Skip to content

Commit dae3ac2

Browse files
Merge pull request #568 from rebeccaalpert/messagebar-ref
fix(MessageBar): Expose external ref for textarea
2 parents 475bcea + 8e92305 commit dae3ac2

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

packages/module/src/MessageBar/MessageBar.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DropdownGroup, DropdownItem, DropdownList } from '@patternfly/react-cor
33
import { BellIcon, CalendarAltIcon, ClipboardIcon, CodeIcon } from '@patternfly/react-icons';
44
import { render, screen } from '@testing-library/react';
55
import userEvent from '@testing-library/user-event';
6+
import { createRef } from 'react';
67
import SourceDetailsMenuItem from '../SourceDetailsMenuItem';
78
import { MessageBar } from './MessageBar';
89

@@ -380,4 +381,10 @@ describe('Message bar', () => {
380381
expect(screen.getByRole('textbox', { name: /Send a message.../i })).toBeTruthy();
381382
expect(screen.getByRole('textbox', { name: /Send a message.../i })).toHaveValue('test');
382383
});
384+
it('should focus textarea when using a custom ref', () => {
385+
const ref = createRef<HTMLTextAreaElement>();
386+
render(<MessageBar onSendMessage={jest.fn} innerRef={ref} />);
387+
ref.current?.focus();
388+
expect(document.activeElement).toBe(screen.getByRole('textbox'));
389+
});
383390
});

packages/module/src/MessageBar/MessageBar.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { ChangeEvent, FunctionComponent, KeyboardEvent as ReactKeyboardEvent } from 'react';
2-
import { useCallback, useEffect, useRef, useState } from 'react';
1+
import type { ChangeEvent, FunctionComponent, KeyboardEvent as ReactKeyboardEvent, Ref } from 'react';
2+
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
33
import { Accept } from 'react-dropzone/.';
44
import { ButtonProps, DropEvent, TextArea, TextAreaProps, TooltipProps } from '@patternfly/react-core';
55

@@ -32,7 +32,7 @@ export interface MessageBarWithAttachMenuProps {
3232
onAttachMenuOpenChange?: (isOpen: boolean) => void;
3333
}
3434

35-
export interface MessageBarProps extends TextAreaProps {
35+
export interface MessageBarProps extends Omit<TextAreaProps, 'innerRef'> {
3636
/** Callback to get the value of input message by user */
3737
onSendMessage: (message: string | number) => void;
3838
/** Class Name for the MessageBar component */
@@ -78,16 +78,19 @@ export interface MessageBarProps extends TextAreaProps {
7878
onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>, value: string | number) => void;
7979
/** Display mode of chatbot, if you want to message bar to resize when the display mode changes */
8080
displayMode?: ChatbotDisplayMode;
81+
/** Whether message bar is compact */
8182
isCompact?: boolean;
8283
/** Specifies the file types accepted by the attachment upload component.
8384
* Files that don't match the accepted types will be disabled in the file picker.
8485
* For example,
8586
* allowedFileTypes: { 'application/json': ['.json'], 'text/plain': ['.txt'] }
8687
**/
8788
allowedFileTypes?: Accept;
89+
/** Ref applied to message bar textarea, for use with focus or other custom behaviors */
90+
innerRef?: React.Ref<HTMLTextAreaElement>;
8891
}
8992

90-
export const MessageBar: FunctionComponent<MessageBarProps> = ({
93+
export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
9194
onSendMessage,
9295
className,
9396
alwayShowSendButton,
@@ -106,14 +109,16 @@ export const MessageBar: FunctionComponent<MessageBarProps> = ({
106109
value,
107110
isCompact = false,
108111
allowedFileTypes,
112+
innerRef,
109113
...props
110114
}: MessageBarProps) => {
111115
// Text Input
112116
// --------------------------------------------------------------------------
113117
const [message, setMessage] = useState<string | number>(value ?? '');
114118
const [isListeningMessage, setIsListeningMessage] = useState<boolean>(false);
115119
const [hasSentMessage, setHasSentMessage] = useState(false);
116-
const textareaRef = useRef<HTMLTextAreaElement>(null);
120+
const inputRef = useRef<HTMLTextAreaElement>(null);
121+
const textareaRef = (innerRef as React.RefObject<HTMLTextAreaElement>) ?? inputRef;
117122
const attachButtonRef = useRef<HTMLButtonElement>(null);
118123

119124
const topMargin = '1rem';
@@ -391,4 +396,9 @@ export const MessageBar: FunctionComponent<MessageBarProps> = ({
391396
return <div className={`pf-chatbot__message-bar ${className ?? ''}`}>{messageBarContents}</div>;
392397
};
393398

399+
const MessageBar = forwardRef((props: MessageBarProps, ref: Ref<HTMLTextAreaElement>) => (
400+
<MessageBarBase innerRef={ref} {...props} />
401+
));
402+
403+
export { MessageBar };
394404
export default MessageBar;

0 commit comments

Comments
 (0)