diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index 6db4e512f225..de78af33d3a5 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -262,9 +262,6 @@ function BaseTextInput( const inputPaddingLeft = !!prefixCharacter && StyleUtils.getPaddingLeft(StyleUtils.getCharacterPadding(prefixCharacter) + styles.pl1.paddingLeft); const inputPaddingRight = !!suffixCharacter && StyleUtils.getPaddingRight(StyleUtils.getCharacterPadding(suffixCharacter) + styles.pr1.paddingRight); - - // Height fix is needed only for Text single line inputs - const shouldApplyHeight = !isMultiline && !isMarkdownEnabled; return ( <> @@ -356,9 +353,7 @@ function BaseTextInput( inputPaddingRight, inputProps.secureTextEntry && styles.secureInput, - // Explicitly remove `lineHeight` from single line inputs so that long text doesn't disappear - // once it exceeds the input space on iOS (See https://github.com/Expensify/App/issues/13802) - shouldApplyHeight && {height, lineHeight: undefined}, + !isMultiline && {height, lineHeight: undefined}, // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled. ...(autoGrowHeight && !isAutoGrowHeightMarkdown diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index da87a34d47eb..45aa868ad219 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -1,6 +1,6 @@ import {Str} from 'expensify-common'; import type {ForwardedRef, MutableRefObject} from 'react'; -import React, {forwardRef, useCallback, useEffect, useRef, useState} from 'react'; +import React, {forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent, StyleProp, TextInput, TextInputFocusEventData, ViewStyle} from 'react-native'; import {ActivityIndicator, StyleSheet, View} from 'react-native'; import {useSharedValue, withSpring} from 'react-native-reanimated'; @@ -24,8 +24,8 @@ import useMarkdownStyle from '@hooks/useMarkdownStyle'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {isMobileChrome, isMobileSafari, isSafari} from '@libs/Browser'; -import {scrollToRight} from '@libs/InputUtils'; +import * as Browser from '@libs/Browser'; +import * as InputUtils from '@libs/InputUtils'; import isInputAutoFilled from '@libs/isInputAutoFilled'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -98,6 +98,7 @@ function BaseTextInput( const [passwordHidden, setPasswordHidden] = useState(inputProps.secureTextEntry); const [textInputWidth, setTextInputWidth] = useState(0); const [textInputHeight, setTextInputHeight] = useState(0); + const [height, setHeight] = useState(variables.componentSizeLarge); const [width, setWidth] = useState(null); const labelScale = useSharedValue(initialActiveLabel ? styleConst.ACTIVE_LABEL_SCALE : styleConst.INACTIVE_LABEL_SCALE); @@ -186,6 +187,7 @@ function BaseTextInput( const layout = event.nativeEvent.layout; setWidth((prevWidth: number | null) => (autoGrowHeight ? layout.width : prevWidth)); + setHeight((prevHeight: number) => (!multiline ? layout.height : prevHeight)); }, [autoGrowHeight, multiline], ); @@ -261,6 +263,25 @@ function BaseTextInput( ]); const isMultiline = multiline || autoGrowHeight; + /** + * To prevent text jumping caused by virtual DOM calculations on Safari and mobile Chrome, + * make sure to include the `lineHeight`. + * Reference: https://github.com/Expensify/App/issues/26735 + * For other platforms, explicitly remove `lineHeight` from single-line inputs + * to prevent long text from disappearing once it exceeds the input space. + * See https://github.com/Expensify/App/issues/13802 + */ + const lineHeight = useMemo(() => { + if (Browser.isSafari() || Browser.isMobileChrome()) { + const lineHeightValue = StyleSheet.flatten(inputStyle).lineHeight; + if (lineHeightValue !== undefined) { + return lineHeightValue; + } + } + + return undefined; + }, [inputStyle]); + const inputPaddingLeft = !!prefixCharacter && StyleUtils.getPaddingLeft(StyleUtils.getCharacterPadding(prefixCharacter) + styles.pl1.paddingLeft); const inputPaddingRight = !!suffixCharacter && StyleUtils.getPaddingRight(StyleUtils.getCharacterPadding(suffixCharacter) + styles.pr1.paddingRight); @@ -309,6 +330,7 @@ function BaseTextInput( /> ) : null} + {!!iconLeft && ( @@ -358,11 +380,15 @@ function BaseTextInput( inputPaddingRight, inputProps.secureTextEntry && styles.secureInput, + // Explicitly remove `lineHeight` from single line inputs so that long text doesn't disappear + // once it exceeds the input space (See https://github.com/Expensify/App/issues/13802) + !isMultiline && {height, lineHeight}, + // Explicitly change boxSizing attribute for mobile chrome in order to apply line-height // for the issue mentioned here https://github.com/Expensify/App/issues/26735 // Set overflow property to enable the parent flexbox to shrink its size // (See https://github.com/Expensify/App/issues/41766) - !isMultiline && isMobileChrome() && {boxSizing: 'content-box', height: undefined, ...styles.overflowAuto}, + !isMultiline && Browser.isMobileChrome() && {boxSizing: 'content-box', height: undefined, ...styles.overflowAuto}, // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled. ...(autoGrowHeight && !isAutoGrowHeightMarkdown @@ -405,7 +431,7 @@ function BaseTextInput( if (didScrollToEndRef.current || !input.current) { return; } - scrollToRight(input.current); + InputUtils.scrollToRight(input.current); didScrollToEndRef.current = true; }} > @@ -498,7 +524,7 @@ function BaseTextInput( return; } let additionalWidth = 0; - if (isMobileSafari() || isSafari() || isMobileChrome()) { + if (Browser.isMobileSafari() || Browser.isSafari() || Browser.isMobileChrome()) { additionalWidth = 2; } setTextInputWidth(e.nativeEvent.layout.width + additionalWidth); diff --git a/src/styles/index.ts b/src/styles/index.ts index 3252d38c918c..4c321c06be48 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1247,11 +1247,12 @@ const styles = (theme: ThemeColors) => }, textInputMultilineContainer: { - height: '100%', paddingTop: 23, }, textInputAndIconContainer: { + flex: 1, + height: '100%', zIndex: -1, flexDirection: 'row', },