Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Fix/auto grow textinput #10

Closed
wants to merge 5 commits into from
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
7 changes: 7 additions & 0 deletions src/components/TextInput/AutoGrowView/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function AutoGrowView() {
return null;
}

AutoGrowView.displayName = 'AutoGrowView';

export default AutoGrowView;
38 changes: 38 additions & 0 deletions src/components/TextInput/AutoGrowView/index.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import Text from '../../Text';
import styles from '../../../styles/styles';

/**
* Text input component doesn't support auto grow by default on the web
* 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.
* @param {Object} props - props passed from above
* @returns {React.Component}
*/
function AutoGrowView(props) {
return (
// Add +2 to width so that the first digit of amount do not cut off on mWeb - https://github.com/Expensify/App/issues/8158.
<Text
style={[...props.inputStyle, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
onLayout={(e) => {
// setTextInputWidth(e.nativeEvent.layout.width + 2);
// setTextInputHeight(e.nativeEvent.layout.height);
}}
>
{props.text}
</Text>
);
}

AutoGrowView.displayName = 'AutoGrowView';
AutoGrowView.propTypes = {
text: PropTypes.string.isRequired,
inputStyle: PropTypes.arrayOf(PropTypes.shape({})),
};
AutoGrowView.defaultProps = {
inputStyle: [],
};

export default AutoGrowView;
33 changes: 9 additions & 24 deletions src/components/TextInput/BaseTextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import getSecureEntryKeyboardType from '../../libs/getSecureEntryKeyboardType';
import CONST from '../../CONST';
import FormHelpMessage from '../FormHelpMessage';
import isInputAutoFilled from '../../libs/isInputAutoFilled';
import AutoGrowView from './AutoGrowView';
import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';

function BaseTextInput(props) {
Expand Down Expand Up @@ -229,10 +230,10 @@ function BaseTextInput(props) {
const textInputContainerStyles = StyleSheet.flatten([
styles.textInputContainer,
...props.textInputContainerStyles,
props.autoGrow && StyleUtils.getWidthStyle(textInputWidth),
// TODO: props.autoGrow && StyleUtils.getWidthStyle(textInputWidth),
!props.hideFocusedState && isFocused && styles.borderColorFocus,
(props.hasError || props.errorText) && styles.borderColorDanger,
props.autoGrowHeight && {scrollPaddingTop: 2 * maxHeight},
// TODO: props.autoGrowHeight && {scrollPaddingTop: 2 * maxHeight},
]);
const isMultiline = props.multiline || props.autoGrowHeight;

Expand All @@ -253,7 +254,7 @@ function BaseTextInput(props) {
textInputContainerStyles,

// When autoGrow is on and minWidth is not supplied, add a minWidth to allow the input to be focusable.
props.autoGrow && !textInputContainerStyles.minWidth && styles.mnw2,
// TODO: props.autoGrow && !textInputContainerStyles.minWidth && styles.mnw2,
]}
>
{hasLabel ? (
Expand Down Expand Up @@ -308,8 +309,8 @@ function BaseTextInput(props) {
placeholderTextColor={themeColors.placeholderText}
underlineColorAndroid="transparent"
style={[
styles.flex1,
styles.w100,
!props.autoGrow && styles.flex1,
!props.autoGrow && styles.w100,
props.inputStyle,
(!hasLabel || isMultiline) && styles.pv0,
props.prefixCharacter && StyleUtils.getPaddingLeft(prefixWidth + styles.pl1.paddingLeft),
Expand All @@ -320,7 +321,7 @@ function BaseTextInput(props) {
!isMultiline && {height, lineHeight: undefined},

// Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
props.autoGrowHeight && StyleUtils.getAutoGrowHeightInputStyle(textInputHeight, maxHeight),
// TODO: props.autoGrowHeight && StyleUtils.getAutoGrowHeightInputStyle(textInputHeight, maxHeight),
]}
multiline={isMultiline}
maxLength={props.maxLength}
Expand Down Expand Up @@ -369,24 +370,8 @@ function BaseTextInput(props) {
/>
)}
</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.
*/}
{(props.autoGrow || props.autoGrowHeight) && (
// Add +2 to width so that the first digit of amount do not cut off on mWeb - https://github.com/Expensify/App/issues/8158.
<Text
style={[...props.inputStyle, props.autoGrowHeight && styles.autoGrowHeightHiddenInput(width, maxHeight), styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
onLayout={(e) => {
setTextInputWidth(e.nativeEvent.layout.width + 2);
setTextInputHeight(e.nativeEvent.layout.height);
}}
>
{props.value || props.placeholder}
</Text>
)}
{/* TODO: idea, do we need to put shit on the styles, when we could make the container grow by this view (on web)? */}
{(props.autoGrow || props.autoGrowHeight) && <AutoGrowView inputStyle={[...props.inputStyle, props.autoGrowHeight && styles.autoGrowHeightHiddenInput(width, maxHeight)]} />}
</>
);
}
Expand Down
25 changes: 11 additions & 14 deletions src/pages/iou/steps/MoneyRequestAmountPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ class MoneyRequestAmountPage extends React.Component {
amount: selectedAmountAsString,
selectedCurrencyCode: _.isUndefined(props.iou.selectedCurrencyCode) ? CONST.CURRENCY.USD : props.iou.selectedCurrencyCode,
shouldUpdateSelection: true,
selection: {
start: selectedAmountAsString.length,
end: selectedAmountAsString.length,
},
};
this.selection = {
start: selectedAmountAsString.length,
end: selectedAmountAsString.length,
};
}

Expand Down Expand Up @@ -144,12 +144,10 @@ class MoneyRequestAmountPage extends React.Component {
// More info: https://github.com/Expensify/App/issues/16974
const newAmountWithoutSpaces = this.stripSpacesFromAmount(newAmount);
if (!this.validateAmount(newAmountWithoutSpaces)) {
// Use a shallow copy of selection to trigger setSelection
// More info: https://github.com/Expensify/App/issues/16385
return {amount: prevState.amount, selection: {...prevState.selection}};
return prevState;
}
const selection = this.getNewSelection(prevState.selection, prevState.amount.length, newAmountWithoutSpaces.length);
return {amount: this.stripCommaFromAmount(newAmountWithoutSpaces), selection};
this.selection = this.getNewSelection(this.selection, prevState.amount.length, newAmountWithoutSpaces.length);
return {amount: this.stripCommaFromAmount(newAmountWithoutSpaces)};
}

/**
Expand Down Expand Up @@ -246,16 +244,16 @@ class MoneyRequestAmountPage extends React.Component {
if (key === '<' || key === 'Backspace') {
if (this.state.amount.length > 0) {
this.setState((prevState) => {
const selectionStart = prevState.selection.start === prevState.selection.end ? prevState.selection.start - 1 : prevState.selection.start;
const amount = `${prevState.amount.substring(0, selectionStart)}${prevState.amount.substring(prevState.selection.end)}`;
const selectionStart = this.selection.start === this.selection.end ? this.selection.start - 1 : this.selection.start;
const amount = `${prevState.amount.substring(0, selectionStart)}${prevState.amount.substring(this.selection.end)}`;
return this.getNewState(prevState, amount);
});
}
return;
}

this.setState((prevState) => {
const amount = this.addLeadingZero(`${prevState.amount.substring(0, prevState.selection.start)}${key}${prevState.amount.substring(prevState.selection.end)}`);
const amount = this.addLeadingZero(`${prevState.amount.substring(0, this.selection.start)}${key}${prevState.amount.substring(this.selection.end)}`);
return this.getNewState(prevState, amount);
});
}
Expand Down Expand Up @@ -335,12 +333,11 @@ class MoneyRequestAmountPage extends React.Component {
placeholder={this.props.numberFormat(0)}
ref={(el) => (this.textInput = el)}
selectedCurrencyCode={this.state.selectedCurrencyCode}
selection={this.state.selection}
onSelectionChange={(e) => {
if (!this.state.shouldUpdateSelection) {
return;
}
this.setState({selection: e.nativeEvent.selection});
this.selection = e.nativeEvent.selection;
}}
/>
</View>
Expand Down