From 393de9002bb73a767d00ae4b3af18e4467325b86 Mon Sep 17 00:00:00 2001 From: adeboyedn Date: Thu, 24 Apr 2025 13:53:32 +0100 Subject: [PATCH 1/3] fix(TextInput): prevent keyboard from opening when scrolling long text (#4666) --- src/components/TextInput/TextInput.tsx | 33 ++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/components/TextInput/TextInput.tsx b/src/components/TextInput/TextInput.tsx index 1bdd7cef00..4eb7a29891 100644 --- a/src/components/TextInput/TextInput.tsx +++ b/src/components/TextInput/TextInput.tsx @@ -9,7 +9,6 @@ import { NativeSyntheticEvent, TextLayoutEventData, } from 'react-native'; - import TextInputAffix, { Props as TextInputAffixProps, } from './Adornment/TextInputAffix'; @@ -172,6 +171,11 @@ export type Props = React.ComponentPropsWithRef & { * Example: `borderRadius`, `borderColor` */ underlineStyle?: StyleProp; + /** + * Pass true to disable input focus on scroll. + * See: https://github.com/callstack/react-native-paper/issues/4666 + */ + disableFocusOnScroll?: boolean; }; interface CompoundedComponent @@ -223,7 +227,10 @@ const TextInput = forwardRef( error: errorProp = false, multiline = false, editable = true, + disableFocusOnScroll = false, contentStyle, + onScroll, + onTouchEnd, render = DefaultRenderer, theme: themeOverrides, ...rest @@ -280,6 +287,7 @@ const TextInput = forwardRef( width: null, height: null, }); + const [isScrolling, setScrolling] = React.useState(false); const timer = React.useRef(); @@ -403,6 +411,22 @@ const TextInput = forwardRef( [rightLayout.height, rightLayout.width] ); + const handleTouchEnd = (args: any) => { + if (disableFocusOnScroll) { + setScrolling(false); + } + // also handle component specific event + onTouchEnd?.(args); + }; + + const handleScroll = (args: any) => { + if (disableFocusOnScroll) { + setScrolling(true); + } + // also handle component specific event + onScroll?.(args); + }; + const handleFocus = (args: any) => { if (disabled || !editable) { return; @@ -484,7 +508,12 @@ const TextInput = forwardRef( disabled={disabled} error={errorProp} multiline={multiline} - editable={editable} + // if disabledFocusOnScroll is enabled + editable={ + (disableFocusOnScroll ? !isScrolling : undefined) || editable + } + onTouchEnd={handleTouchEnd} + onScroll={handleScroll} render={render} {...rest} theme={theme} From 302903227e983226d4d0bc8f9160d60ac2c2c671 Mon Sep 17 00:00:00 2001 From: adeboyedn Date: Thu, 24 Apr 2025 17:39:03 +0100 Subject: [PATCH 2/3] fix: failing workflow --- .../__fixtures__/rewrite-imports/output.js | 20 +++++++++---------- src/components/TextInput/TextInput.tsx | 5 ++++- .../__snapshots__/TextInput.test.tsx.snap | 18 +++++++++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/babel/__fixtures__/rewrite-imports/output.js b/src/babel/__fixtures__/rewrite-imports/output.js index ecaff8d814..f74849db33 100644 --- a/src/babel/__fixtures__/rewrite-imports/output.js +++ b/src/babel/__fixtures__/rewrite-imports/output.js @@ -1,12 +1,12 @@ /* eslint-disable prettier/prettier */ -import PaperProvider from "react-native-paper/lib/module/core/PaperProvider"; -import BottomNavigation from "react-native-paper/lib/module/components/BottomNavigation/BottomNavigation"; -import Button from "react-native-paper/lib/module/components/Button/Button"; -import FAB from "react-native-paper/lib/module/components/FAB"; -import Appbar from "react-native-paper/lib/module/components/Appbar"; -import * as MD2Colors from "react-native-paper/lib/module/styles/themes/v2/colors"; -import { MD3Colors } from "react-native-paper/lib/module/styles/themes/v3/tokens"; +import PaperProvider from "react-native-paper/lib\\module\\core\\PaperProvider"; +import BottomNavigation from "react-native-paper/lib\\module\\components\\BottomNavigation\\BottomNavigation"; +import Button from "react-native-paper/lib\\module\\components\\Button\\Button"; +import FAB from "react-native-paper/lib\\module\\components\\FAB"; +import Appbar from "react-native-paper/lib\\module\\components\\Appbar"; +import * as MD2Colors from "react-native-paper/lib\\module\\styles\\themes\\v2\\colors"; +import { MD3Colors } from "react-native-paper/lib\\module\\styles\\themes\\v3\\tokens"; import { NonExistent, NonExistentSecond as Stuff } from "react-native-paper/lib/module/index.js"; -import { ThemeProvider } from "react-native-paper/lib/module/core/theming"; -import { withTheme } from "react-native-paper/lib/module/core/theming"; -import { DefaultTheme } from "react-native-paper/lib/module/core/theming"; +import { ThemeProvider } from "react-native-paper/lib\\module\\core\\theming"; +import { withTheme } from "react-native-paper/lib\\module\\core\\theming"; +import { DefaultTheme } from "react-native-paper/lib\\module\\core\\theming"; diff --git a/src/components/TextInput/TextInput.tsx b/src/components/TextInput/TextInput.tsx index 4eb7a29891..0c0290dd33 100644 --- a/src/components/TextInput/TextInput.tsx +++ b/src/components/TextInput/TextInput.tsx @@ -555,8 +555,11 @@ const TextInput = forwardRef( disabled={disabled} error={errorProp} multiline={multiline} - editable={editable} render={render} + // if disabledFocusOnScroll is enabled + editable={(disableFocusOnScroll ? !isScrolling : undefined) || editable} + onTouchEnd={handleTouchEnd} + onScroll={handleScroll} {...rest} theme={theme} value={value} diff --git a/src/components/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/components/__tests__/__snapshots__/TextInput.test.tsx.snap index f57eb469b0..27f43a74fb 100644 --- a/src/components/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -184,6 +184,8 @@ exports[`call onPress when affix adornment pressed 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Enter your phone number" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -498,6 +500,8 @@ exports[`correctly applies a component as the text label 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -724,6 +728,8 @@ exports[`correctly applies cursorColor prop 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -950,6 +956,8 @@ exports[`correctly applies default textAlign based on default RTL 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -1208,6 +1216,8 @@ exports[`correctly applies height to multiline Outline TextInput 1`] = ` onChangeText={[Function]} onFocus={[Function]} onLayout={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type Something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -1435,6 +1445,8 @@ exports[`correctly applies paddingLeft from contentStyleProp 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -1663,6 +1675,8 @@ exports[`correctly applies textAlign center 1`] = ` onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -1889,6 +1903,8 @@ exports[`correctly renders left-side affix adornment, and right-side icon adornm onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" @@ -2315,6 +2331,8 @@ exports[`correctly renders left-side icon adornment, and right-side affix adornm onBlur={[Function]} onChangeText={[Function]} onFocus={[Function]} + onScroll={[Function]} + onTouchEnd={[Function]} placeholder="Type something" placeholderTextColor="transparent" selectionColor="rgba(103, 80, 164, 1)" From 8ec13959290c9a10596da02cdecc5ecd84d2f124 Mon Sep 17 00:00:00 2001 From: adeboyedn Date: Thu, 24 Apr 2025 18:44:55 +0100 Subject: [PATCH 3/3] fix: lint and test --- .../__fixtures__/rewrite-imports/output.js | 20 +++++++++---------- src/components/TextInput/TextInput.tsx | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/babel/__fixtures__/rewrite-imports/output.js b/src/babel/__fixtures__/rewrite-imports/output.js index f74849db33..ecaff8d814 100644 --- a/src/babel/__fixtures__/rewrite-imports/output.js +++ b/src/babel/__fixtures__/rewrite-imports/output.js @@ -1,12 +1,12 @@ /* eslint-disable prettier/prettier */ -import PaperProvider from "react-native-paper/lib\\module\\core\\PaperProvider"; -import BottomNavigation from "react-native-paper/lib\\module\\components\\BottomNavigation\\BottomNavigation"; -import Button from "react-native-paper/lib\\module\\components\\Button\\Button"; -import FAB from "react-native-paper/lib\\module\\components\\FAB"; -import Appbar from "react-native-paper/lib\\module\\components\\Appbar"; -import * as MD2Colors from "react-native-paper/lib\\module\\styles\\themes\\v2\\colors"; -import { MD3Colors } from "react-native-paper/lib\\module\\styles\\themes\\v3\\tokens"; +import PaperProvider from "react-native-paper/lib/module/core/PaperProvider"; +import BottomNavigation from "react-native-paper/lib/module/components/BottomNavigation/BottomNavigation"; +import Button from "react-native-paper/lib/module/components/Button/Button"; +import FAB from "react-native-paper/lib/module/components/FAB"; +import Appbar from "react-native-paper/lib/module/components/Appbar"; +import * as MD2Colors from "react-native-paper/lib/module/styles/themes/v2/colors"; +import { MD3Colors } from "react-native-paper/lib/module/styles/themes/v3/tokens"; import { NonExistent, NonExistentSecond as Stuff } from "react-native-paper/lib/module/index.js"; -import { ThemeProvider } from "react-native-paper/lib\\module\\core\\theming"; -import { withTheme } from "react-native-paper/lib\\module\\core\\theming"; -import { DefaultTheme } from "react-native-paper/lib\\module\\core\\theming"; +import { ThemeProvider } from "react-native-paper/lib/module/core/theming"; +import { withTheme } from "react-native-paper/lib/module/core/theming"; +import { DefaultTheme } from "react-native-paper/lib/module/core/theming"; diff --git a/src/components/TextInput/TextInput.tsx b/src/components/TextInput/TextInput.tsx index 0c0290dd33..b97d398e4b 100644 --- a/src/components/TextInput/TextInput.tsx +++ b/src/components/TextInput/TextInput.tsx @@ -9,6 +9,7 @@ import { NativeSyntheticEvent, TextLayoutEventData, } from 'react-native'; + import TextInputAffix, { Props as TextInputAffixProps, } from './Adornment/TextInputAffix';