Reset textarea height after clear (#10911)
This commit is contained in:
@@ -34,6 +34,7 @@ import {
|
|||||||
} from '#/components/Autocomplete'
|
} from '#/components/Autocomplete'
|
||||||
import {
|
import {
|
||||||
AutosizedTextarea,
|
AutosizedTextarea,
|
||||||
|
type AutosizedTextareaHeightApi,
|
||||||
type AutosizedTextareaProps,
|
type AutosizedTextareaProps,
|
||||||
} from '#/components/forms/AutosizedTextarea'
|
} from '#/components/forms/AutosizedTextarea'
|
||||||
import {Span, Text} from '#/components/Typography'
|
import {Span, Text} from '#/components/Typography'
|
||||||
@@ -150,6 +151,13 @@ export function Composer({
|
|||||||
*/
|
*/
|
||||||
const inputScrollSharedValue = useSharedValue(0)
|
const inputScrollSharedValue = useSharedValue(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Imperative handle on the underlying textarea, used to reset its height when
|
||||||
|
* the input is cleared programmatically (Android doesn't fire
|
||||||
|
* `onContentSizeChange` in that case).
|
||||||
|
*/
|
||||||
|
const heightApiRef = useRef<AutosizedTextareaHeightApi>(null)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose imperative internal API
|
* Expose imperative internal API
|
||||||
*/
|
*/
|
||||||
@@ -160,6 +168,7 @@ export function Composer({
|
|||||||
clear: () => {
|
clear: () => {
|
||||||
tapper.inputProps.onChangeText('')
|
tapper.inputProps.onChangeText('')
|
||||||
inputScrollSharedValue.value = 0
|
inputScrollSharedValue.value = 0
|
||||||
|
heightApiRef.current?.resetHeight()
|
||||||
},
|
},
|
||||||
insert: tapper.insert,
|
insert: tapper.insert,
|
||||||
setAutocompleteAnchor: sift.refs.setAnchor,
|
setAutocompleteAnchor: sift.refs.setAnchor,
|
||||||
@@ -321,6 +330,7 @@ export function Composer({
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<AutosizedTextarea
|
<AutosizedTextarea
|
||||||
|
heightApiRef={heightApiRef}
|
||||||
placeholderTextColor={t.palette.contrast_500}
|
placeholderTextColor={t.palette.contrast_500}
|
||||||
accessibilityLabel={label}
|
accessibilityLabel={label}
|
||||||
accessibilityHint={label}
|
accessibilityHint={label}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {useMemo, useRef, useState} from 'react'
|
import {useImperativeHandle, useMemo, useRef, useState} from 'react'
|
||||||
import {
|
import {
|
||||||
TextInput,
|
TextInput,
|
||||||
type TextInputContentSizeChangeEvent,
|
type TextInputContentSizeChangeEvent,
|
||||||
@@ -10,8 +10,18 @@ import {atoms as a, extractPadding, useAlf, web} from '#/alf'
|
|||||||
import {normalizeTextStyles} from '#/alf/typography'
|
import {normalizeTextStyles} from '#/alf/typography'
|
||||||
import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env'
|
import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env'
|
||||||
|
|
||||||
|
export type AutosizedTextareaHeightApi = {
|
||||||
|
/**
|
||||||
|
* Reset the input back to its minimum height. Needed on Android, where the
|
||||||
|
* height is driven by state that only updates via `onContentSizeChange` -
|
||||||
|
* that event doesn't fire when the value is cleared programmatically.
|
||||||
|
*/
|
||||||
|
resetHeight: () => void
|
||||||
|
}
|
||||||
|
|
||||||
export type AutosizedTextareaProps = Omit<TextInputProps, 'multiline'> & {
|
export type AutosizedTextareaProps = Omit<TextInputProps, 'multiline'> & {
|
||||||
ref?: React.Ref<TextInput>
|
ref?: React.Ref<TextInput>
|
||||||
|
heightApiRef?: React.Ref<AutosizedTextareaHeightApi>
|
||||||
label: string
|
label: string
|
||||||
minRows?: number
|
minRows?: number
|
||||||
maxRows?: number
|
maxRows?: number
|
||||||
@@ -20,6 +30,7 @@ export type AutosizedTextareaProps = Omit<TextInputProps, 'multiline'> & {
|
|||||||
|
|
||||||
export function AutosizedTextarea({
|
export function AutosizedTextarea({
|
||||||
ref,
|
ref,
|
||||||
|
heightApiRef,
|
||||||
label,
|
label,
|
||||||
minRows = 1,
|
minRows = 1,
|
||||||
maxRows,
|
maxRows,
|
||||||
@@ -107,6 +118,16 @@ export function AutosizedTextarea({
|
|||||||
* directly drive the `height`.
|
* directly drive the `height`.
|
||||||
*/
|
*/
|
||||||
const [nativeHeight, setNativeHeight] = useState(minInputHeight)
|
const [nativeHeight, setNativeHeight] = useState(minInputHeight)
|
||||||
|
useImperativeHandle(
|
||||||
|
heightApiRef,
|
||||||
|
() => ({
|
||||||
|
resetHeight: () => {
|
||||||
|
setNativeHeight(minInputHeight)
|
||||||
|
onUpdateHeight?.(minInputHeight)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[minInputHeight, onUpdateHeight],
|
||||||
|
)
|
||||||
const onContentSizeChange = (e: TextInputContentSizeChangeEvent) => {
|
const onContentSizeChange = (e: TextInputContentSizeChangeEvent) => {
|
||||||
const contentSize = Math.ceil(e.nativeEvent.contentSize.height)
|
const contentSize = Math.ceil(e.nativeEvent.contentSize.height)
|
||||||
// ios reports the content size without padding
|
// ios reports the content size without padding
|
||||||
|
|||||||
Reference in New Issue
Block a user