Skip to content

Commit 880d12d

Browse files
authored
fix: prevent empty message composer textarea from growing (#3051)
1 parent 686dfcc commit 880d12d

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/components/MessageComposer/__tests__/MessageInput.test.jsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,32 @@ describe(`MessageInputFlat`, () => {
324324
});
325325
});
326326

327+
it('should force single-line placeholder styling while input is empty', async () => {
328+
await renderComponent();
329+
330+
const textarea = await screen.findByPlaceholderText(inputPlaceholder);
331+
332+
expect(textarea.style.whiteSpace).toBe('nowrap');
333+
expect(textarea.style.overflow).toBe('hidden');
334+
expect(textarea.style.textOverflow).toBe('ellipsis');
335+
});
336+
337+
it('should remove empty-state single-line styling after user types', async () => {
338+
await renderComponent();
339+
340+
const textarea = await screen.findByPlaceholderText(inputPlaceholder);
341+
342+
fireEvent.change(textarea, {
343+
target: { value: 'hello world' },
344+
});
345+
346+
await waitFor(() => {
347+
expect(textarea.style.whiteSpace).toBe('');
348+
expect(textarea.style.overflow).toBe('');
349+
expect(textarea.style.textOverflow).toBe('');
350+
});
351+
});
352+
327353
it('should display default value', async () => {
328354
const defaultValue = nanoid();
329355
const { customChannel, customClient } = await setup();

src/components/TextareaComposer/TextareaComposer.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ export const TextareaComposer = ({
107107
textComposer.state,
108108
textComposerStateSelector,
109109
);
110+
// react-textarea-autosize can measure placeholder content as multi-line in narrow layouts,
111+
// producing an inflated initial height (e.g. 2 rows) before the user types.
112+
// Clamp to a single row only while empty unless the integrator explicitly set minRows.
113+
const autosizeRows = !text && minRows == null ? 1 : undefined;
114+
const textareaStyle = text
115+
? undefined
116+
: ({
117+
overflow: 'hidden',
118+
textOverflow: 'ellipsis',
119+
whiteSpace: 'nowrap',
120+
} satisfies React.CSSProperties);
110121

111122
const { enabled } = useStateStore(messageComposer.configState, configStateSelector);
112123
const { quotedMessage } = useStateStore(
@@ -297,8 +308,8 @@ export const TextareaComposer = ({
297308
)}
298309
data-testid='message-input'
299310
disabled={!enabled || !!cooldownRemaining}
300-
maxRows={maxRows}
301-
minRows={minRows}
311+
maxRows={autosizeRows ?? maxRows}
312+
minRows={autosizeRows ?? minRows}
302313
onBlur={onBlur}
303314
onChange={changeHandler}
304315
onCompositionEnd={onCompositionEnd}
@@ -311,6 +322,7 @@ export const TextareaComposer = ({
311322
ref={(ref) => {
312323
textareaRef.current = ref;
313324
}}
325+
style={textareaStyle}
314326
/>
315327
{/* todo: X document the layout change for the accessibility purpose (tabIndex) */}
316328
{!isComposing && (

0 commit comments

Comments
 (0)