From 2663cd88c37cb55cc0b3f296afb9d3d8952551f7 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 09:08:10 +0100
Subject: [PATCH 01/28] Added autoGrowHeight feature

---
 src/components/TextInput/BaseTextInput.js | 26 ++++++++++++++++-------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 6fa78a513449..41d901430c72 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -1,7 +1,7 @@
 import _ from 'underscore';
 import React, {Component} from 'react';
 import {
-    Animated, View, TouchableWithoutFeedback, AppState, Keyboard,
+    Animated, View, TouchableWithoutFeedback, AppState, Keyboard, StyleSheet,
 } from 'react-native';
 import Str from 'expensify-common/lib/str';
 import RNTextInput from '../RNTextInput';
@@ -218,12 +218,15 @@ class BaseTextInput extends Component {
             !this.props.hideFocusedState && this.state.isFocused && styles.borderColorFocus,
             (this.props.hasError || this.props.errorText) && styles.borderColorDanger,
         ], (finalStyles, s) => ({...finalStyles, ...s}), {});
+        const maxHeight = StyleSheet.flatten(this.props.containerStyles).maxHeight;
+        const autoGrowHeight = this.props.autoGrowHeight && this.props.multiline;
 
         return (
             <>
                 <View>
                     <View
                         style={[
+                            (autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
                             !this.props.multiline && styles.componentHeightLarge,
                             ...this.props.containerStyles,
                         ]}
@@ -231,8 +234,10 @@ class BaseTextInput extends Component {
                         <TouchableWithoutFeedback onPress={this.onPress} focusable={false}>
                             <View
 
-                                // When multiline is not supplied, calculating textinput height using onLayout
-                                onLayout={event => !this.props.multiline && this.setState({height: event.nativeEvent.layout.height})}
+                                // When autoGrowHeight is true calculate textinput width or when multiline
+                                // is not supplied calculate textinput height, using onLayout.
+                                onLayout={event => (autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
+                                    || (!this.props.multiline && this.setState({height: event.nativeEvent.layout.height}))}
                                 style={[
                                     textInputContainerStyles,
 
@@ -301,6 +306,9 @@ class BaseTextInput extends Component {
                                             // 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)
                                             !this.props.multiline && {height: this.state.height, lineHeight: undefined},
+
+                                            // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
+                                            autoGrowHeight && this.state.textInputHeight <= maxHeight ? styles.overflowHidden : styles.overflowAuto,
                                         ]}
                                         multiline={this.props.multiline}
                                         maxLength={this.props.maxLength}
@@ -351,17 +359,19 @@ class BaseTextInput extends Component {
                 {/*
                     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 of the input value given textStyle in this component.
+                    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.
                 */}
-                {this.props.autoGrow && (
+                {(this.props.autoGrow || 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={[...this.props.inputStyle, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
-                        onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width + 2})}
+                        style={[...this.props.inputStyle, autoGrowHeight && {maxWidth: this.state.width}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
+                        onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width + 2, textInputHeight: e.nativeEvent.layout.height})}
                     >
-                        {this.state.value || this.props.placeholder}
+                        {/* We are appending a zero width space (\u200B) here as the browser will remove a trailing newline that doesn't
+                        have any characters after it. This allows linebreaks to work properly on web when the user presses enter. */}
+                        {`${this.state.value}${autoGrowHeight ? '\u200B' : ''}` || this.props.placeholder}
                     </Text>
                 )}
             </>

From 3996bfedbe4386b10dda8c3edfc853c2d62d8d86 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 09:08:34 +0100
Subject: [PATCH 02/28] Added autoGrowHeight prop

---
 src/pages/workspace/WorkspaceInvitePage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js
index 413e742372cb..82edfca1722d 100644
--- a/src/pages/workspace/WorkspaceInvitePage.js
+++ b/src/pages/workspace/WorkspaceInvitePage.js
@@ -342,8 +342,8 @@ class WorkspaceInvitePage extends React.Component {
                                     <TextInput
                                         label={this.props.translate('workspace.invite.personalMessagePrompt')}
                                         autoCompleteType="off"
+                                        autoGrowHeight
                                         autoCorrect={false}
-                                        numberOfLines={4}
                                         textAlignVertical="top"
                                         multiline
                                         containerStyles={[styles.workspaceInviteWelcome]}

From 63da7194d1387210e248c7b491103f1b14b0d810 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 09:08:52 +0100
Subject: [PATCH 03/28] Added paddingRight to baseTextInput

---
 src/styles/styles.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/styles/styles.js b/src/styles/styles.js
index 1c7d8656f911..0fa1263170e1 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -843,6 +843,7 @@ const styles = {
         paddingTop: 23,
         paddingBottom: 8,
         paddingLeft: 0,
+        paddingRight: 0,
         borderWidth: 0,
     },
 
@@ -2603,7 +2604,7 @@ const styles = {
     },
 
     workspaceInviteWelcome: {
-        minHeight: 115,
+        maxHeight: 115,
     },
 
     peopleRow: {

From d1e86068ebe0197bbb1e5c9482643ecf167c7c93 Mon Sep 17 00:00:00 2001
From: Olly <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 21:19:46 +0100
Subject: [PATCH 04/28] Changed AND to ternary

Co-authored-by: Fedi Rajhi <fedirjh@gmail.com>
---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 41d901430c72..1840e03006cb 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -366,7 +366,7 @@ class BaseTextInput extends Component {
 
                     // 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={[...this.props.inputStyle, autoGrowHeight && {maxWidth: this.state.width}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
+                        style={[...this.props.inputStyle, autoGrowHeight ? {maxWidth: this.state.width} : {}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
                         onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width + 2, textInputHeight: e.nativeEvent.layout.height})}
                     >
                         {/* We are appending a zero width space (\u200B) here as the browser will remove a trailing newline that doesn't

From fb35aa76a61875a944adf137e23776db75cd900e Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 21:32:27 +0100
Subject: [PATCH 05/28] Added autoGrowHeight to baseTextInputPropTypes

---
 src/components/TextInput/baseTextInputPropTypes.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/components/TextInput/baseTextInputPropTypes.js b/src/components/TextInput/baseTextInputPropTypes.js
index 30169d995528..b0451733848a 100644
--- a/src/components/TextInput/baseTextInputPropTypes.js
+++ b/src/components/TextInput/baseTextInputPropTypes.js
@@ -40,9 +40,12 @@ const propTypes = {
     /** Disable the virtual keyboard  */
     disableKeyboard: PropTypes.bool,
 
-    /** Autogrow input container size based on the entered text  */
+    /** Autogrow input container length based on the entered text  */
     autoGrow: PropTypes.bool,
 
+    /** Autogrow input container height based on the entered text  */
+    autoGrowHeight: PropTypes.bool,
+
     /** Hide the focus styles on TextInput */
     hideFocusedState: PropTypes.bool,
 
@@ -109,6 +112,7 @@ const defaultProps = {
     forceActiveLabel: false,
     disableKeyboard: false,
     autoGrow: false,
+    autoGrowHeight: false,
     hideFocusedState: false,
     innerRef: () => {},
     shouldSaveDraft: false,

From 9c8cc25f9d07af9e1b6280741716378421c1f313 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 21:37:39 +0100
Subject: [PATCH 06/28] Changed to set multiline true when autoGrowHeight

---
 src/components/TextInput/BaseTextInput.js | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 1840e03006cb..d79ed21f3903 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -219,14 +219,13 @@ class BaseTextInput extends Component {
             (this.props.hasError || this.props.errorText) && styles.borderColorDanger,
         ], (finalStyles, s) => ({...finalStyles, ...s}), {});
         const maxHeight = StyleSheet.flatten(this.props.containerStyles).maxHeight;
-        const autoGrowHeight = this.props.autoGrowHeight && this.props.multiline;
 
         return (
             <>
                 <View>
                     <View
                         style={[
-                            (autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
+                            (this.props.autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
                             !this.props.multiline && styles.componentHeightLarge,
                             ...this.props.containerStyles,
                         ]}
@@ -236,7 +235,7 @@ class BaseTextInput extends Component {
 
                                 // When autoGrowHeight is true calculate textinput width or when multiline
                                 // is not supplied calculate textinput height, using onLayout.
-                                onLayout={event => (autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
+                                onLayout={event => (this.props.autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
                                     || (!this.props.multiline && this.setState({height: event.nativeEvent.layout.height}))}
                                 style={[
                                     textInputContainerStyles,
@@ -308,9 +307,9 @@ class BaseTextInput extends Component {
                                             !this.props.multiline && {height: this.state.height, lineHeight: undefined},
 
                                             // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
-                                            autoGrowHeight && this.state.textInputHeight <= maxHeight ? styles.overflowHidden : styles.overflowAuto,
+                                            this.props.autoGrowHeight && this.state.textInputHeight <= maxHeight ? styles.overflowHidden : styles.overflowAuto,
                                         ]}
-                                        multiline={this.props.multiline}
+                                        multiline={this.props.multiline || this.props.autoGrowHeight}
                                         maxLength={this.props.maxLength}
                                         onFocus={this.onFocus}
                                         onBlur={this.onBlur}
@@ -362,16 +361,16 @@ class BaseTextInput extends Component {
                     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.
                 */}
-                {(this.props.autoGrow || autoGrowHeight) && (
+                {(this.props.autoGrow || this.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={[...this.props.inputStyle, autoGrowHeight ? {maxWidth: this.state.width} : {}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
+                        style={[...this.props.inputStyle, this.props.autoGrowHeight ? {maxWidth: this.state.width} : {}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
                         onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width + 2, textInputHeight: e.nativeEvent.layout.height})}
                     >
                         {/* We are appending a zero width space (\u200B) here as the browser will remove a trailing newline that doesn't
                         have any characters after it. This allows linebreaks to work properly on web when the user presses enter. */}
-                        {`${this.state.value}${autoGrowHeight ? '\u200B' : ''}` || this.props.placeholder}
+                        {`${this.state.value}${this.props.autoGrowHeight ? '\u200B' : ''}` || this.props.placeholder}
                     </Text>
                 )}
             </>

From 51a725d0c9ad563a072cba27a5bb5e4e50333d97 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 21:48:50 +0100
Subject: [PATCH 07/28] Updated comment for onLayout

---
 src/components/TextInput/BaseTextInput.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index d79ed21f3903..6310e3d5a150 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -233,8 +233,8 @@ class BaseTextInput extends Component {
                         <TouchableWithoutFeedback onPress={this.onPress} focusable={false}>
                             <View
 
-                                // When autoGrowHeight is true calculate textinput width or when multiline
-                                // is not supplied calculate textinput height, using onLayout.
+                                // When autoGrowHeight is true we calculate the width for the textInput, so It will break lines properly
+                                // or if multiline is not supplied we calculate the textinput height, using onLayout.
                                 onLayout={event => (this.props.autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
                                     || (!this.props.multiline && this.setState({height: event.nativeEvent.layout.height}))}
                                 style={[

From 49e44c77666982ff17ff7a3c9c8cf91cab0c4492 Mon Sep 17 00:00:00 2001
From: Olly <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 23:14:33 +0100
Subject: [PATCH 08/28] Removed multiline prop from TextInput

Co-authored-by: Fedi Rajhi <fedirjh@gmail.com>
---
 src/pages/workspace/WorkspaceInvitePage.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js
index 82edfca1722d..9d8393dfaecf 100644
--- a/src/pages/workspace/WorkspaceInvitePage.js
+++ b/src/pages/workspace/WorkspaceInvitePage.js
@@ -345,7 +345,6 @@ class WorkspaceInvitePage extends React.Component {
                                         autoGrowHeight
                                         autoCorrect={false}
                                         textAlignVertical="top"
-                                        multiline
                                         containerStyles={[styles.workspaceInviteWelcome]}
                                         value={this.state.welcomeNote}
                                         onChangeText={text => this.setState({welcomeNote: text})}

From b598295434fa0bcbab9342e457933bbbf2fc9592 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 23:40:06 +0100
Subject: [PATCH 09/28] Added isMultiline variable

---
 src/components/TextInput/BaseTextInput.js | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 6310e3d5a150..e5f4a3c05903 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -219,6 +219,7 @@ class BaseTextInput extends Component {
             (this.props.hasError || this.props.errorText) && styles.borderColorDanger,
         ], (finalStyles, s) => ({...finalStyles, ...s}), {});
         const maxHeight = StyleSheet.flatten(this.props.containerStyles).maxHeight;
+        const isMultiline = this.props.multiline || this.props.autoGrowHeight;
 
         return (
             <>
@@ -226,7 +227,7 @@ class BaseTextInput extends Component {
                     <View
                         style={[
                             (this.props.autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
-                            !this.props.multiline && styles.componentHeightLarge,
+                            !isMultiline && styles.componentHeightLarge,
                             ...this.props.containerStyles,
                         ]}
                     >
@@ -236,7 +237,7 @@ class BaseTextInput extends Component {
                                 // When autoGrowHeight is true we calculate the width for the textInput, so It will break lines properly
                                 // or if multiline is not supplied we calculate the textinput height, using onLayout.
                                 onLayout={event => (this.props.autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
-                                    || (!this.props.multiline && this.setState({height: event.nativeEvent.layout.height}))}
+                                    || (!isMultiline && this.setState({height: event.nativeEvent.layout.height}))}
                                 style={[
                                     textInputContainerStyles,
 
@@ -248,7 +249,7 @@ class BaseTextInput extends Component {
                                     <>
                                         {/* Adding this background to the label only for multiline text input,
                                     to prevent text overlapping with label when scrolling */}
-                                        {this.props.multiline && <View style={styles.textInputLabelBackground} pointerEvents="none" />}
+                                        {isMultiline && <View style={styles.textInputLabelBackground} pointerEvents="none" />}
                                         <TextInputLabel
                                             label={this.props.label}
                                             labelTranslateY={this.state.labelTranslateY}
@@ -260,7 +261,7 @@ class BaseTextInput extends Component {
                                 <View
                                     style={[
                                         styles.textInputAndIconContainer,
-                                        (this.props.multiline && hasLabel) && styles.textInputMultilineContainer,
+                                        (isMultiline && hasLabel) && styles.textInputMultilineContainer,
                                     ]}
                                     pointerEvents="box-none"
                                 >
@@ -298,18 +299,18 @@ class BaseTextInput extends Component {
                                             styles.flex1,
                                             styles.w100,
                                             this.props.inputStyle,
-                                            (!hasLabel || this.props.multiline) && styles.pv0,
+                                            (!hasLabel || isMultiline) && styles.pv0,
                                             this.props.prefixCharacter && StyleUtils.getPaddingLeft(this.state.prefixWidth + styles.pl1.paddingLeft),
                                             this.props.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)
-                                            !this.props.multiline && {height: this.state.height, lineHeight: undefined},
+                                            !isMultiline && {height: this.state.height, lineHeight: undefined},
 
                                             // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
                                             this.props.autoGrowHeight && this.state.textInputHeight <= maxHeight ? styles.overflowHidden : styles.overflowAuto,
                                         ]}
-                                        multiline={this.props.multiline || this.props.autoGrowHeight}
+                                        multiline={isMultiline}
                                         maxLength={this.props.maxLength}
                                         onFocus={this.onFocus}
                                         onBlur={this.onBlur}
@@ -324,7 +325,7 @@ class BaseTextInput extends Component {
 
                                         // FormSubmit Enter key handler does not have access to direct props.
                                         // `dataset.submitOnEnter` is used to indicate that pressing Enter on this input should call the submit callback.
-                                        dataSet={{submitOnEnter: this.props.multiline && this.props.submitOnEnter}}
+                                        dataSet={{submitOnEnter: isMultiline && this.props.submitOnEnter}}
 
                                     />
                                     {Boolean(this.props.secureTextEntry) && (

From f5490c140bf219e40e820f99296b5096bc7710fa Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 24 Apr 2023 23:49:09 +0100
Subject: [PATCH 10/28] Simplified onLayout

---
 src/components/TextInput/BaseTextInput.js | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index e5f4a3c05903..594fdb3ee5dd 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -236,8 +236,16 @@ class BaseTextInput extends Component {
 
                                 // When autoGrowHeight is true we calculate the width for the textInput, so It will break lines properly
                                 // or if multiline is not supplied we calculate the textinput height, using onLayout.
-                                onLayout={event => (this.props.autoGrowHeight && this.setState({width: event.nativeEvent.layout.width}))
-                                    || (!isMultiline && this.setState({height: event.nativeEvent.layout.height}))}
+                                onLayout={(event) => {
+                                    if (!this.props.autoGrowHeight && this.props.multiline) {
+                                        return;
+                                    }
+
+                                    this.setState(prevState => ({
+                                        width: this.props.autoGrowHeight ? event.nativeEvent.layout.width : prevState.width,
+                                        height: !this.props.multiline ? event.nativeEvent.layout.height : prevState.height,
+                                    }));
+                                }}
                                 style={[
                                     textInputContainerStyles,
 

From 830631064a669125f5151da45c5cc79bd15c7747 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Tue, 25 Apr 2023 10:49:09 +0100
Subject: [PATCH 11/28] Added AutoGrowHeightInput to stories

---
 src/stories/TextInput.stories.js | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js
index 7472f8bc2848..be5edfbebac6 100644
--- a/src/stories/TextInput.stories.js
+++ b/src/stories/TextInput.stories.js
@@ -69,6 +69,17 @@ AutoGrowInput.args = {
     }],
 };
 
+const AutoGrowHeightInput = Template.bind({});
+AutoGrowHeightInput.args = {
+    label: 'Autogrowheight input',
+    name: 'AutoGrowHeight',
+    placeholder: 'My placeholder text',
+    autoGrowHeight: true,
+    textInputContainerStyles: [{
+        maxHeight: 115,
+    }],
+};
+
 const PrefixedInput = Template.bind({});
 PrefixedInput.args = {
     label: 'Prefixed input',

From 971dce9dff4e4d8c21fc0089084405dfa58116da Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Tue, 25 Apr 2023 12:46:33 +0100
Subject: [PATCH 12/28] Added layout const

---
 src/components/TextInput/BaseTextInput.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 594fdb3ee5dd..1901d79b0512 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -241,9 +241,11 @@ class BaseTextInput extends Component {
                                         return;
                                     }
 
+                                    const layout = event.nativeEvent.layout;
+
                                     this.setState(prevState => ({
-                                        width: this.props.autoGrowHeight ? event.nativeEvent.layout.width : prevState.width,
-                                        height: !this.props.multiline ? event.nativeEvent.layout.height : prevState.height,
+                                        width: this.props.autoGrowHeight ? layout.width : prevState.width,
+                                        height: !this.props.multiline ? layout.height : prevState.height,
                                     }));
                                 }}
                                 style={[

From 208e9db04590c8b1729495d2fca6d5f420eff859 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Tue, 25 Apr 2023 13:10:46 +0100
Subject: [PATCH 13/28] Only add zerowidth space if last char is linebreak

---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 1901d79b0512..00181a75b0d7 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -381,7 +381,7 @@ class BaseTextInput extends Component {
                     >
                         {/* We are appending a zero width space (\u200B) here as the browser will remove a trailing newline that doesn't
                         have any characters after it. This allows linebreaks to work properly on web when the user presses enter. */}
-                        {`${this.state.value}${this.props.autoGrowHeight ? '\u200B' : ''}` || this.props.placeholder}
+                        {`${this.state.value}${this.props.autoGrowHeight && (this.state.value.slice(-1) === '\n') ? '\u200B' : ''}` || this.props.placeholder}
                     </Text>
                 )}
             </>

From a8f6a16ff6246f687696949b7d718e364cf26ae5 Mon Sep 17 00:00:00 2001
From: Olly <ollywilks@googlemail.com>
Date: Wed, 26 Apr 2023 09:09:36 +0100
Subject: [PATCH 14/28] Changed props.multiline to isMultiline

Co-authored-by: Fedi Rajhi <fedirjh@gmail.com>
---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 00181a75b0d7..8b12ec00233e 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -245,7 +245,7 @@ class BaseTextInput extends Component {
 
                                     this.setState(prevState => ({
                                         width: this.props.autoGrowHeight ? layout.width : prevState.width,
-                                        height: !this.props.multiline ? layout.height : prevState.height,
+                                        height: !isMultiline ? layout.height : prevState.height,
                                     }));
                                 }}
                                 style={[

From 094db19e87f7c8c497fb0546b442e0b2c65932f7 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 26 Apr 2023 09:19:14 +0100
Subject: [PATCH 15/28] Export AutoGrowHeightInput

---
 src/stories/TextInput.stories.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js
index be5edfbebac6..07c4273193b3 100644
--- a/src/stories/TextInput.stories.js
+++ b/src/stories/TextInput.stories.js
@@ -129,6 +129,7 @@ export {
     ForceActiveLabel,
     PlaceholderInput,
     AutoGrowInput,
+    AutoGrowHeightInput,
     PrefixedInput,
     MaxLengthInput,
     HintAndErrorInput,

From 7c380e71839103afa4878430dfffc202cca4674d Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Mon, 1 May 2023 16:03:47 +0100
Subject: [PATCH 16/28] Add autoGrowHeight prop to TextInput

---
 src/pages/workspace/WorkspaceInviteMessagePage.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js
index f91da6c12a8d..5123a7b9d8a2 100644
--- a/src/pages/workspace/WorkspaceInviteMessagePage.js
+++ b/src/pages/workspace/WorkspaceInviteMessagePage.js
@@ -195,9 +195,8 @@ class WorkspaceInviteMessagePage extends React.Component {
                                 label={this.props.translate('workspace.inviteMessage.personalMessagePrompt')}
                                 autoCompleteType="off"
                                 autoCorrect={false}
-                                numberOfLines={4}
+                                autoGrowHeight
                                 textAlignVertical="top"
-                                multiline
                                 containerStyles={[styles.workspaceInviteWelcome]}
                                 defaultValue={this.state.welcomeNote}
                                 value={this.state.welcomeNote}

From d4b545a12e2762a03376ef510abc83af677f9a53 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Tue, 2 May 2023 10:22:28 +0100
Subject: [PATCH 17/28] Moved MiniReportActionContextMenu to top of view

---
 src/pages/home/report/ReportActionItem.js | 25 +++++++++++------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js
index a47ff6d4de4e..4f275491ffe9 100644
--- a/src/pages/home/report/ReportActionItem.js
+++ b/src/pages/home/report/ReportActionItem.js
@@ -275,6 +275,18 @@ class ReportActionItem extends Component {
                 <Hoverable>
                     {hovered => (
                         <View accessibilityLabel={this.props.translate('accessibilityHints.chatMessage')}>
+                            <MiniReportActionContextMenu
+                                reportID={this.props.report.reportID}
+                                reportAction={this.props.action}
+                                isArchivedRoom={ReportUtils.isArchivedRoom(this.props.report)}
+                                displayAsGroup={this.props.displayAsGroup}
+                                isVisible={
+                                    hovered
+                                    && !this.props.draftMessage
+                                }
+                                draftMessage={this.props.draftMessage}
+                                isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)}
+                            />
                             {this.props.shouldDisplayNewMarker && (
                                 <UnreadActionIndicator reportActionID={this.props.action.reportActionID} />
                             )}
@@ -336,19 +348,6 @@ class ReportActionItem extends Component {
                                         )}
                                 </OfflineWithFeedback>
                             </View>
-                            <MiniReportActionContextMenu
-                                reportID={this.props.report.reportID}
-                                reportAction={this.props.action}
-                                isArchivedRoom={ReportUtils.isArchivedRoom(this.props.report)}
-                                displayAsGroup={this.props.displayAsGroup}
-                                isVisible={
-                                    hovered
-                                    && !this.props.draftMessage
-                                    && !hasErrors
-                                }
-                                draftMessage={this.props.draftMessage}
-                                isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)}
-                            />
                         </View>
                     )}
                 </Hoverable>

From 70824222eb48e835f86f73861d9e5b2e581934b0 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Tue, 2 May 2023 10:27:12 +0100
Subject: [PATCH 18/28] Revert move MiniReportActionContextMenu

---
 src/pages/home/report/ReportActionItem.js | 24 +++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js
index 4f275491ffe9..f3c713b78498 100644
--- a/src/pages/home/report/ReportActionItem.js
+++ b/src/pages/home/report/ReportActionItem.js
@@ -275,18 +275,6 @@ class ReportActionItem extends Component {
                 <Hoverable>
                     {hovered => (
                         <View accessibilityLabel={this.props.translate('accessibilityHints.chatMessage')}>
-                            <MiniReportActionContextMenu
-                                reportID={this.props.report.reportID}
-                                reportAction={this.props.action}
-                                isArchivedRoom={ReportUtils.isArchivedRoom(this.props.report)}
-                                displayAsGroup={this.props.displayAsGroup}
-                                isVisible={
-                                    hovered
-                                    && !this.props.draftMessage
-                                }
-                                draftMessage={this.props.draftMessage}
-                                isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)}
-                            />
                             {this.props.shouldDisplayNewMarker && (
                                 <UnreadActionIndicator reportActionID={this.props.action.reportActionID} />
                             )}
@@ -348,6 +336,18 @@ class ReportActionItem extends Component {
                                         )}
                                 </OfflineWithFeedback>
                             </View>
+                            <MiniReportActionContextMenu
+                                reportID={this.props.report.reportID}
+                                reportAction={this.props.action}
+                                isArchivedRoom={ReportUtils.isArchivedRoom(this.props.report)}
+                                displayAsGroup={this.props.displayAsGroup}
+                                isVisible={
+                                    hovered
+                                    && !this.props.draftMessage
+                                }
+                                draftMessage={this.props.draftMessage}
+                                isChronosReport={ReportUtils.chatIncludesChronos(this.props.report)}
+                            />
                         </View>
                     )}
                 </Hoverable>

From fc49ff6d51c4aeae8f9ccbcca70eed1f75256a0e Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 09:50:33 +0100
Subject: [PATCH 19/28] Add scrollPadding for autoGrowHeight

---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index da268524df51..9b7cd013bc22 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -319,7 +319,7 @@ class BaseTextInput extends Component {
                                             !isMultiline && {height: this.state.height, lineHeight: undefined},
 
                                             // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
-                                            this.props.autoGrowHeight && this.state.textInputHeight <= maxHeight ? styles.overflowHidden : styles.overflowAuto,
+                                            this.props.autoGrowHeight && this.state.textInputHeight <= maxHeight ? [styles.overflowHidden, {scrollPaddingTop: '100px'}] : styles.overflowAuto,
                                         ]}
                                         multiline={isMultiline}
                                         maxLength={this.props.maxLength}

From 40aeb20ad3ffd75d28497d790c0c70e2d669a06c Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 19:08:31 +0100
Subject: [PATCH 20/28] Added minHeight to autoGrowHeight textInput

---
 src/components/TextInput/BaseTextInput.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 9b7cd013bc22..3030246d1823 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -229,6 +229,7 @@ class BaseTextInput extends Component {
                         style={[
                             (this.props.autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
                             !isMultiline && styles.componentHeightLarge,
+                            this.props.autoGrowHeight && {minHeight: variables.componentSizeLarge},
                             ...this.props.containerStyles,
                         ]}
                     >

From 3266612dc9eaa9291a7bf04e3785f8f82fa573b4 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 19:16:45 +0100
Subject: [PATCH 21/28] Added getAutoGrowHeightInputStyle to StyleUtils

---
 src/styles/StyleUtils.js | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js
index b2cd47beace9..4b79b624bcec 100644
--- a/src/styles/StyleUtils.js
+++ b/src/styles/StyleUtils.js
@@ -300,6 +300,24 @@ function getWidthStyle(width) {
     };
 }
 
+/**
+ * Returns auto grow height text input style
+ *
+ * @param {Number} textInputHeight
+ * @param {Number} maxHeight
+ * @returns {Object}
+ */
+function getAutoGrowHeightInputStyle(textInputHeight, maxHeight) {
+    if (textInputHeight > maxHeight) {
+        return styles.overflowAuto;
+    }
+
+    return {
+        ...styles.overflowHidden,
+        scrollPaddingTop: '100px',
+    };
+}
+
 /**
  * Returns a style with backgroundColor and borderColor set to the same color
  *
@@ -1103,6 +1121,7 @@ export {
     getZoomCursorStyle,
     getZoomSizingStyle,
     getWidthStyle,
+    getAutoGrowHeightInputStyle,
     getBackgroundAndBorderStyle,
     getBackgroundColorStyle,
     getBackgroundColorWithOpacityStyle,

From 2344a77deb70cba861c34dc3e188c1c0460ca266 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 19:17:44 +0100
Subject: [PATCH 22/28] Implemented getAutoGrowHeightInputStyle

---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 3030246d1823..e85bebdc113a 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -320,7 +320,7 @@ class BaseTextInput extends Component {
                                             !isMultiline && {height: this.state.height, lineHeight: undefined},
 
                                             // Stop scrollbar flashing when breaking lines with autoGrowHeight enabled.
-                                            this.props.autoGrowHeight && this.state.textInputHeight <= maxHeight ? [styles.overflowHidden, {scrollPaddingTop: '100px'}] : styles.overflowAuto,
+                                            this.props.autoGrowHeight && StyleUtils.getAutoGrowHeightInputStyle(this.state.textInputHeight, maxHeight),
                                         ]}
                                         multiline={isMultiline}
                                         maxLength={this.props.maxLength}

From f125bd676f4e72ebf141c8503787d4de7153f423 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 19:40:21 +0100
Subject: [PATCH 23/28] Added autoGrowHeightInputContainer

---
 src/styles/styles.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/styles/styles.js b/src/styles/styles.js
index 24aafab93cb7..7fd4878fbc43 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -800,6 +800,11 @@ const styles = {
         backgroundColor: themeColors.buttonDefaultBG,
     },
 
+    autoGrowHeightInputContainer: (textInputHeight, maxHeight) => ({
+        height: textInputHeight >= maxHeight ? maxHeight : textInputHeight,
+        minHeight: variables.componentSizeLarge,
+    }),
+
     textInputContainer: {
         flex: 1,
         justifyContent: 'center',

From 6c17fb7e3ce12a76b8ccab180b2cfc82a8abd75c Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Wed, 3 May 2023 19:40:48 +0100
Subject: [PATCH 24/28] Implemented autoGrowHeightInputContainer

---
 src/components/TextInput/BaseTextInput.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index e85bebdc113a..85f08b0a0a73 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -227,7 +227,7 @@ class BaseTextInput extends Component {
                 <View>
                     <View
                         style={[
-                            (this.props.autoGrowHeight && {height: this.state.textInputHeight >= maxHeight ? maxHeight : this.state.textInputHeight}),
+                            this.props.autoGrowHeight && styles.autoGrowHeightInputContainer(this.state.textInputHeight, maxHeight),
                             !isMultiline && styles.componentHeightLarge,
                             this.props.autoGrowHeight && {minHeight: variables.componentSizeLarge},
                             ...this.props.containerStyles,

From 49599359b3a5c557dd2738f8709e9db304c353ef Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Thu, 4 May 2023 11:54:55 +0100
Subject: [PATCH 25/28] remove scrollPaddingTop and add textInput height

---
 src/styles/StyleUtils.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js
index 4b79b624bcec..63a3841288c6 100644
--- a/src/styles/StyleUtils.js
+++ b/src/styles/StyleUtils.js
@@ -314,7 +314,7 @@ function getAutoGrowHeightInputStyle(textInputHeight, maxHeight) {
 
     return {
         ...styles.overflowHidden,
-        scrollPaddingTop: '100px',
+        height: maxHeight,
     };
 }
 

From 4b4dab1d1b20f51893ea1399491567d7784bb90f Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Thu, 4 May 2023 11:55:21 +0100
Subject: [PATCH 26/28] Added scrollPaddingTop to textInputContainer

---
 src/styles/styles.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/styles/styles.js b/src/styles/styles.js
index 7fd4878fbc43..ac8ccda52068 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -813,6 +813,7 @@ const styles = {
         borderBottomWidth: 2,
         borderColor: themeColors.border,
         overflow: 'hidden',
+        scrollPaddingTop: '100%',
     },
 
     textInputLabel: {

From f58ea34bf35802f16e3440db3206de8924eedb34 Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Thu, 4 May 2023 13:55:37 +0100
Subject: [PATCH 27/28] removed duplicate minHeight

---
 src/components/TextInput/BaseTextInput.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 85f08b0a0a73..2e85869c24b9 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -229,7 +229,6 @@ class BaseTextInput extends Component {
                         style={[
                             this.props.autoGrowHeight && styles.autoGrowHeightInputContainer(this.state.textInputHeight, maxHeight),
                             !isMultiline && styles.componentHeightLarge,
-                            this.props.autoGrowHeight && {minHeight: variables.componentSizeLarge},
                             ...this.props.containerStyles,
                         ]}
                     >

From af4d0c7c29b54e732e2829ab12de818b1e62029a Mon Sep 17 00:00:00 2001
From: Oliver Wilks <ollywilks@googlemail.com>
Date: Thu, 4 May 2023 21:28:19 +0100
Subject: [PATCH 28/28] Removed zero width space

---
 src/components/TextInput/BaseTextInput.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 2e85869c24b9..12211de67ba3 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -380,9 +380,7 @@ class BaseTextInput extends Component {
                         style={[...this.props.inputStyle, this.props.autoGrowHeight ? {maxWidth: this.state.width} : {}, styles.hiddenElementOutsideOfWindow, styles.visibilityHidden]}
                         onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width + 2, textInputHeight: e.nativeEvent.layout.height})}
                     >
-                        {/* We are appending a zero width space (\u200B) here as the browser will remove a trailing newline that doesn't
-                        have any characters after it. This allows linebreaks to work properly on web when the user presses enter. */}
-                        {`${this.state.value}${this.props.autoGrowHeight && (this.state.value.slice(-1) === '\n') ? '\u200B' : ''}` || this.props.placeholder}
+                        {this.state.value || this.props.placeholder}
                     </Text>
                 )}
             </>
