Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ import type {BaseTextInputProps, BaseTextInputRef} from '@components/TextInput/B
import * as styleConst from '@components/TextInput/styleConst';
import TextInputClearButton from '@components/TextInput/TextInputClearButton';
import TextInputLabel from '@components/TextInput/TextInputLabel';
import TextInputMeasurement from '@components/TextInput/TextInputMeasurement';
import useHtmlPaste from '@hooks/useHtmlPaste';
import useLocalize from '@hooks/useLocalize';
import useMarkdownStyle from '@hooks/useMarkdownStyle';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import getPlatform from '@libs/getPlatform';
import isInputAutoFilled from '@libs/isInputAutoFilled';
import variables from '@styles/variables';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -80,10 +78,6 @@ function BaseTextInput(
}: BaseTextInputProps,
ref: ForwardedRef<BaseTextInputRef>,
) {
// For iOS, we don't need to measure the text input because it already has auto grow behavior
// See TextInputMeasurement.ios.tsx for more details
const isExternalAutoGrowMeasurement = getPlatform() !== CONST.PLATFORM.IOS && autoGrow;

const InputComponent = InputComponentMap.get(type) ?? RNTextInput;
const isMarkdownEnabled = type === 'markdown';
const isAutoGrowHeightMarkdown = isMarkdownEnabled && autoGrowHeight;
Expand Down Expand Up @@ -253,7 +247,7 @@ function BaseTextInput(
styles.textInputContainer,
textInputContainerStyles,
!!contentWidth && StyleUtils.getWidthStyle(textInputWidth),
isExternalAutoGrowMeasurement && StyleUtils.getAutoGrowWidthInputContainerStyles(textInputWidth, autoGrowExtraSpace),
autoGrow && StyleUtils.getAutoGrowWidthInputContainerStyles(textInputWidth, autoGrowExtraSpace),
!hideFocusedState && isFocused && styles.borderColorFocus,
(!!hasError || !!errorText) && styles.borderColorDanger,
autoGrowHeight && {scrollPaddingTop: typeof maxAutoGrowHeight === 'number' ? 2 * maxAutoGrowHeight : undefined},
Expand All @@ -265,10 +259,6 @@ function BaseTextInput(

// Height fix is needed only for Text single line inputs
const shouldApplyHeight = !isMultiline && !isMarkdownEnabled;

// Fix iOS cursor jumping when entering first character using HW keyboard https://github.com/Expensify/App/pull/59078#issuecomment-2802834037
const selection = inputProps.selection?.end === 0 && inputProps.selection?.start === 0 ? undefined : inputProps.selection;

return (
<>
<View style={[containerStyles]}>
Expand Down Expand Up @@ -355,8 +345,8 @@ function BaseTextInput(
placeholderTextColor={placeholderTextColor ?? theme.placeholderText}
underlineColorAndroid="transparent"
style={[
!autoGrow && styles.flex1,
!autoGrow && styles.w100,
styles.flex1,
styles.w100,
inputStyle,
(!hasLabel || isMultiline) && styles.pv0,
inputPaddingLeft,
Expand Down Expand Up @@ -387,7 +377,7 @@ function BaseTextInput(
keyboardType={inputProps.keyboardType}
inputMode={!disableKeyboard ? inputProps.inputMode : CONST.INPUT_MODE.NONE}
value={uncontrolled ? undefined : value}
selection={selection}
selection={inputProps.selection}
readOnly={isReadOnly}
defaultValue={defaultValue}
markdownStyle={markdownStyle}
Expand Down Expand Up @@ -451,21 +441,55 @@ function BaseTextInput(
/>
)}
</View>
<TextInputMeasurement
value={value}
placeholder={placeholder}
contentWidth={contentWidth}
autoGrowHeight={autoGrowHeight}
maxAutoGrowHeight={maxAutoGrowHeight}
width={width}
inputStyle={inputStyle}
inputPaddingLeft={inputPaddingLeft}
autoGrow={autoGrow}
isAutoGrowHeightMarkdown={isAutoGrowHeightMarkdown}
onSetTextInputWidth={setTextInputWidth}
onSetTextInputHeight={setTextInputHeight}
isPrefixCharacterPaddingCalculated={isPrefixCharacterPaddingCalculated}
/>
{!!contentWidth && isPrefixCharacterPaddingCalculated && (
<View
style={[inputStyle as ViewStyle, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden, styles.wAuto, inputPaddingLeft]}
onLayout={(e) => {
if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) {
return;
}
setTextInputWidth(e.nativeEvent.layout.width);
setTextInputHeight(e.nativeEvent.layout.height);
}}
>
<Text
style={[
inputStyle,
autoGrowHeight && styles.autoGrowHeightHiddenInput(width ?? 0, typeof maxAutoGrowHeight === 'number' ? maxAutoGrowHeight : undefined),
{width: contentWidth},
]}
>
{/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */}
{value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder}
</Text>
</View>
)}
{/*
Text input component doesn't support auto grow by default.
This text view is used to calculate width or height of the input value given textStyle in this component.
This Text component is intentionally positioned out of the screen.
*/}
{(!!autoGrow || autoGrowHeight) && !isAutoGrowHeightMarkdown && (
<Text
style={[
inputStyle,
autoGrowHeight && styles.autoGrowHeightHiddenInput(width ?? 0, typeof maxAutoGrowHeight === 'number' ? maxAutoGrowHeight : undefined),
styles.hiddenElementOutsideOfWindow,
styles.visibilityHidden,
]}
onLayout={(e) => {
if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) {
return;
}
// Add +2 to width so that cursor is not cut off / covered at the end of text content
setTextInputWidth(e.nativeEvent.layout.width + 2);
setTextInputHeight(e.nativeEvent.layout.height);
}}
>
{/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */}
{value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder}
</Text>
)}
</>
);
}
Expand Down
75 changes: 58 additions & 17 deletions src/components/TextInput/BaseTextInput/implementation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ import type {BaseTextInputProps, BaseTextInputRef} from '@components/TextInput/B
import {ACTIVE_LABEL_SCALE, ACTIVE_LABEL_TRANSLATE_Y, INACTIVE_LABEL_SCALE, INACTIVE_LABEL_TRANSLATE_Y} from '@components/TextInput/styleConst';
import TextInputClearButton from '@components/TextInput/TextInputClearButton';
import TextInputLabel from '@components/TextInput/TextInputLabel';
import TextInputMeasurement from '@components/TextInput/TextInputMeasurement';
import useHtmlPaste from '@hooks/useHtmlPaste';
import useLocalize from '@hooks/useLocalize';
import useMarkdownStyle from '@hooks/useMarkdownStyle';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {isMobileChrome} from '@libs/Browser';
import {isMobileChrome, isMobileSafari, isSafari} from '@libs/Browser';
import {scrollToRight} from '@libs/InputUtils';
import isInputAutoFilled from '@libs/isInputAutoFilled';
import variables from '@styles/variables';
Expand Down Expand Up @@ -467,21 +466,63 @@ function BaseTextInput(
/>
)}
</View>
<TextInputMeasurement
value={value}
placeholder={placeholder}
contentWidth={contentWidth}
autoGrowHeight={autoGrowHeight}
maxAutoGrowHeight={maxAutoGrowHeight}
width={width}
inputStyle={inputStyle}
inputPaddingLeft={inputPaddingLeft}
autoGrow={autoGrow}
isAutoGrowHeightMarkdown={isAutoGrowHeightMarkdown}
onSetTextInputWidth={setTextInputWidth}
onSetTextInputHeight={setTextInputHeight}
isPrefixCharacterPaddingCalculated={isPrefixCharacterPaddingCalculated}
/>
{!!contentWidth && isPrefixCharacterPaddingCalculated && (
<View
style={[inputStyle as ViewStyle, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden, styles.wAuto, inputPaddingLeft]}
onLayout={(e) => {
if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) {
return;
}
setTextInputWidth(e.nativeEvent.layout.width);
setTextInputHeight(e.nativeEvent.layout.height);
}}
>
<Text
style={[
inputStyle,
autoGrowHeight && styles.autoGrowHeightHiddenInput(width ?? 0, typeof maxAutoGrowHeight === 'number' ? maxAutoGrowHeight : undefined),
{width: contentWidth},
]}
>
{/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */}
{value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder}
</Text>
</View>
)}
{/*
Text input component doesn't support auto grow by default.
We're using a hidden text input to achieve that.
This text view is used to calculate width or height of the input value given textStyle in this component.
This Text component is intentionally positioned out of the screen.
*/}
{(!!autoGrow || autoGrowHeight) && !isAutoGrowHeightMarkdown && (
// Add +2 to width on Safari browsers so that text is not cut off due to the cursor or when changing the value
// Reference: https://github.com/Expensify/App/issues/8158, https://github.com/Expensify/App/issues/26628
// For mobile Chrome, ensure proper display of the text selection handle (blue bubble down).
// Reference: https://github.com/Expensify/App/issues/34921
<Text
style={[
inputStyle,
autoGrowHeight && styles.autoGrowHeightHiddenInput(width ?? 0, typeof maxAutoGrowHeight === 'number' ? maxAutoGrowHeight : undefined),
styles.hiddenElementOutsideOfWindow,
styles.visibilityHidden,
]}
onLayout={(e) => {
if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) {
return;
}
let additionalWidth = 0;
if (isMobileSafari() || isSafari() || isMobileChrome()) {
additionalWidth = 2;
}
setTextInputWidth(e.nativeEvent.layout.width + additionalWidth);
setTextInputHeight(e.nativeEvent.layout.height);
}}
>
{/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */}
{value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder}
</Text>
)}
</>
);
}
Expand Down
7 changes: 0 additions & 7 deletions src/components/TextInput/TextInputMeasurement/index.ios.tsx

This file was deleted.

91 changes: 0 additions & 91 deletions src/components/TextInput/TextInputMeasurement/index.tsx

This file was deleted.

44 changes: 0 additions & 44 deletions src/components/TextInput/TextInputMeasurement/types.ts

This file was deleted.