Skip to content

Commit 33189fc

Browse files
author
Marc Lundgren
committed
feat: Add ref API to Composer for programmatic send box focus
- Add forwardRef wrapper to Composer component - Expose focusSendBoxInput() method via ComposerRef - Export ComposerRef type for TypeScript consumers - Leverages existing useFocus('sendBox') infrastructure - Returns Promise for async focus handling
1 parent 2654667 commit 33189fc

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

packages/component/src/Composer.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { singleToArray } from 'botframework-webchat-core';
1414
import classNames from 'classnames';
1515
import MarkdownIt from 'markdown-it';
1616
import PropTypes from 'prop-types';
17-
import React, { memo, useCallback, useMemo, useRef, useState, type ReactNode } from 'react';
17+
import React, { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef, useState, type ReactNode } from 'react';
1818
import { Composer as SayComposer } from 'react-say';
1919

2020
import createDefaultAttachmentMiddleware from './Attachment/createMiddleware';
@@ -27,6 +27,7 @@ import {
2727
import { StyleToEmotionObjectComposer, useStyleToEmotionObject } from './hooks/internal/styleToEmotionObject';
2828
import UITracker from './hooks/internal/UITracker';
2929
import useInjectStyles from './hooks/internal/useInjectStyles';
30+
import useFocus from './hooks/useFocus';
3031
import WebChatUIContext from './hooks/internal/WebChatUIContext';
3132
import { FocusSendBoxScope } from './hooks/sendBoxFocus';
3233
import { ScrollRelativeTranscriptScope } from './hooks/transcriptScrollRelative';
@@ -60,6 +61,10 @@ import mapMap from './Utils/mapMap';
6061

6162
const { useGetActivityByKey, useReferenceGrammarID, useStyleOptions, useTrackException } = hooks;
6263

64+
export type ComposerRef = {
65+
focusSendBoxInput: () => Promise<void>;
66+
};
67+
6368
function styleSetToEmotionObjects(styleToEmotionObject, styleSet) {
6469
return mapMap(styleSet, (style, key) => (key === 'options' ? style : styleToEmotionObject(style)));
6570
}
@@ -489,11 +494,25 @@ const InternalComposer = ({
489494
);
490495
};
491496

492-
const Composer = (props: ComposerProps) => (
493-
<WebChatTheme>
494-
<InternalComposer {...props} />
495-
</WebChatTheme>
496-
);
497+
const Composer = forwardRef<ComposerRef, ComposerProps>((props, ref) => {
498+
const focus = useFocus();
499+
500+
useImperativeHandle(
501+
ref,
502+
() => ({
503+
focusSendBoxInput: () => focus('sendBox')
504+
}),
505+
[focus]
506+
);
507+
508+
return (
509+
<WebChatTheme>
510+
<InternalComposer {...props} />
511+
</WebChatTheme>
512+
);
513+
});
514+
515+
Composer.displayName = 'Composer';
497516

498517
Composer.defaultProps = {
499518
...APIComposer.defaultProps,

0 commit comments

Comments
 (0)