File tree Expand file tree Collapse file tree 2 files changed +40
-2
lines changed
MessageComposer/__tests__ Expand file tree Collapse file tree 2 files changed +40
-2
lines changed Original file line number Diff line number Diff 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 ( ) ;
Original file line number Diff line number Diff 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 && (
You can’t perform that action at this time.
0 commit comments