diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 855f4a1de5..d93c7bb91a 100644 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -346,6 +346,7 @@ export function Composer({ {...tapper.inputProps} {...sift.targetProps} ref={mergeRefs([ref, tapper.inputProps.ref, sift.targetProps.ref])} + rawValue={tapper.state.text} onBlur={e => { rest.onBlur?.(e) setActiveFacet(null) diff --git a/src/components/forms/AutosizedTextarea.tsx b/src/components/forms/AutosizedTextarea.tsx index 402075ea27..d81265f4da 100644 --- a/src/components/forms/AutosizedTextarea.tsx +++ b/src/components/forms/AutosizedTextarea.tsx @@ -1,4 +1,4 @@ -import {useMemo, useRef, useState} from 'react' +import {useEffect, useMemo, useRef, useState} from 'react' import { TextInput, type TextInputContentSizeChangeEvent, @@ -16,6 +16,17 @@ export type AutosizedTextareaProps = Omit & { minRows?: number maxRows?: number onUpdateHeight?: (height: number) => void + /** + * In some cases, like on native, we may not pass in an actual `value` prop. + * This prop allows Android to know if the field was cleared and thereby + * reset its height. This is a small hack required because we need to + * explicitly set the `{height: nativeHeight}` on Android. + * + * If you notice height calcuation issues after clearing the field on + * Android, check if this value is being populated and cleared properly in + * the parent component. + */ + rawValue?: string } export function AutosizedTextarea({ @@ -24,6 +35,7 @@ export function AutosizedTextarea({ minRows = 1, maxRows, onUpdateHeight, + rawValue, onChangeText: onChangeTextOuter, onContentSizeChange: onContentSizeChangeOuter, @@ -124,6 +136,22 @@ export function AutosizedTextarea({ onContentSizeChangeOuter?.(e) } + /* + * Manual height clearing required for Android because we're forced to set + * `{height: nativeHeight}` on Android, and even though `onContentSizeChange` + * fires, the height matches the existing height and we aren't able to reset. + */ + const prevRawValue = useRef(rawValue || '') + useEffect(() => { + if (!IS_ANDROID) return // everything else is fine + if (rawValue === undefined) return // uncontrolled + if (prevRawValue.current?.length && rawValue === '') { + setNativeHeight(minInputHeight) + onUpdateHeight?.(minInputHeight) + } + prevRawValue.current = rawValue + }, [rawValue, minInputHeight]) + return (