Skip to content

Commit

Permalink
Merge pull request #21371 from akinwale/task-20836
Browse files Browse the repository at this point in the history
  • Loading branch information
thienlnam authored Jun 27, 2023
2 parents 82558a1 + 812bbc5 commit 52a1891
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 40 deletions.
24 changes: 24 additions & 0 deletions src/libs/focusAndUpdateMultilineInputRange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Focus a multiline text input and place the cursor at the end of the value (if there is a value in the input).
*
* When a multiline input contains a text value that goes beyond the scroll height, the cursor will be placed
* at the end of the text value, and automatically scroll the input field to this position after the field gains
* focus. This provides a better user experience in cases where the text in the field has to be edited. The auto-
* scroll behaviour works on all platforms except iOS native.
* See https://github.com/Expensify/App/issues/20836 for more details.
*
* @param {Object} input the input element
*/
export default function focusAndUpdateMultilineInputRange(input) {
if (!input) {
return;
}

input.focus();
if (input.value && input.setSelectionRange) {
const length = input.value.length;
input.setSelectionRange(length, length);
// eslint-disable-next-line no-param-reassign
input.scrollTop = input.scrollHeight;
}
}
26 changes: 3 additions & 23 deletions src/pages/tasks/NewTaskDescriptionPage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useEffect, useRef, useState} from 'react';
import React, {useRef} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
Expand All @@ -14,6 +14,7 @@ import TextInput from '../../components/TextInput';
import Permissions from '../../libs/Permissions';
import ROUTES from '../../ROUTES';
import * as TaskUtils from '../../libs/actions/Task';
import focusAndUpdateMultilineInputRange from '../../libs/focusAndUpdateMultilineInputRange';

const propTypes = {
/** Beta features list */
Expand All @@ -38,17 +39,6 @@ const defaultProps = {
function NewTaskDescriptionPage(props) {
const inputRef = useRef(null);

// The selection will be used to place the cursor at the end if there is prior text in the text input area
const [selection, setSelection] = useState({start: 0, end: 0});

// eslint-disable-next-line rulesdir/prefer-early-return
useEffect(() => {
if (props.task.description) {
const length = props.task.description.length;
setSelection({start: length, end: length});
}
}, [props.task.description]);

// On submit, we want to call the assignTask function and wait to validate
// the response
const onSubmit = (values) => {
Expand All @@ -63,13 +53,7 @@ function NewTaskDescriptionPage(props) {
return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
onEntryTransitionEnd={() => {
if (!inputRef.current) {
return;
}

inputRef.current.focus();
}}
onEntryTransitionEnd={() => focusAndUpdateMultilineInputRange(inputRef.current)}
>
<HeaderWithBackButton
title={props.translate('newTaskPage.description')}
Expand All @@ -93,10 +77,6 @@ function NewTaskDescriptionPage(props) {
submitOnEnter
containerStyles={[styles.autoGrowHeightMultilineInput]}
textAlignVertical="top"
selection={selection}
onSelectionChange={(e) => {
setSelection(e.nativeEvent.selection);
}}
/>
</View>
</Form>
Expand Down
20 changes: 3 additions & 17 deletions src/pages/tasks/TaskDescriptionPage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useRef, useState} from 'react';
import React, {useCallback, useRef} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
Expand All @@ -12,6 +12,7 @@ import styles from '../../styles/styles';
import compose from '../../libs/compose';
import reportPropTypes from '../reportPropTypes';
import * as TaskUtils from '../../libs/actions/Task';
import focusAndUpdateMultilineInputRange from '../../libs/focusAndUpdateMultilineInputRange';

const propTypes = {
/** Current user session */
Expand Down Expand Up @@ -48,21 +49,10 @@ function TaskDescriptionPage(props) {

const inputRef = useRef(null);

// Same as NewtaskDescriptionPage, use the selection to place the cursor correctly if there is prior text
const [selection, setSelection] = useState({start: 0, end: 0});

// eslint-disable-next-line rulesdir/prefer-early-return
useEffect(() => {
if (props.task.report && props.task.report.description) {
const length = props.task.report.description.length;
setSelection({start: length, end: length});
}
}, [props.task.report]);

return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
onEntryTransitionEnd={() => inputRef.current && inputRef.current.focus()}
onEntryTransitionEnd={() => focusAndUpdateMultilineInputRange(inputRef.current)}
>
<HeaderWithBackButton title={props.translate('newTaskPage.task')} />
<Form
Expand All @@ -84,10 +74,6 @@ function TaskDescriptionPage(props) {
submitOnEnter
containerStyles={[styles.autoGrowHeightMultilineInput]}
textAlignVertical="top"
selection={selection}
onSelectionChange={(e) => {
setSelection(e.nativeEvent.selection);
}}
/>
</View>
</Form>
Expand Down

0 comments on commit 52a1891

Please sign in to comment.