From c902ea0a45643f6ae894a67bf2c53311aa816c50 Mon Sep 17 00:00:00 2001 From: James Maxell Eroy Date: Thu, 28 Sep 2023 08:11:03 -0700 Subject: [PATCH] Add `onPress` prop (#39701) Summary: TextInput already uses Pressability, but doesn't expose the onPress prop. Link:https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Components/TextInput/TextInput.js#L1381-L1414. Currently TextInput only exposes the onPressIn() and onPressOut() props from Pressability. While onPressOut() can serve the same purpose as onPress() in most cases, it doesn't fare well with PanResponder...say a swipe gesture implemented using PanResponder. When the pointer/cursor exits the hit test bounds of TextInput, onPressOut() will be triggered even though the desired behavior could be that we only want to invoke the event handler when the user lifts their finger from the screen (while still in the hit test bounds of the TextInput). Example of TextInput in a PanResponder: https://snack.expo.dev/jambalaya/panresponder Changelog: [General][Added] Add onPress prop to TextInput Reviewed By: NickGerleman Differential Revision: D49653011 --- .../Components/TextInput/TextInput.d.ts | 5 +++ .../Components/TextInput/TextInput.flow.js | 5 +++ .../Components/TextInput/TextInput.js | 37 +++++++++++++------ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 2c0c099a894fca..fa196a19491df0 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -738,6 +738,11 @@ export interface TextInputProps | ((e: NativeSyntheticEvent) => void) | undefined; + /** + * Called when a single tap gesture is detected. + */ + onPress?: ((e: NativeSyntheticEvent) => void) | undefined; + /** * Callback that is called when a touch is engaged. */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 9adbfe9f6f190b..39ba481b7e4751 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -766,6 +766,11 @@ export type Props = $ReadOnly<{| */ unstable_onKeyPressSync?: ?(e: KeyPressEvent) => mixed, + /** + * Called when a single tap gesture is detected. + */ + onPress?: ?(event: PressEvent) => mixed, + /** * Called when a touch is engaged. */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 481938f08434a5..2dddd7ae6bff38 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -808,6 +808,11 @@ export type Props = $ReadOnly<{| */ unstable_onKeyPressSync?: ?(e: KeyPressEvent) => mixed, + /** + * Called when a single tap gesture is detected. + */ + onPress?: ?(event: PressEvent) => mixed, + /** * Called when a touch is engaged. */ @@ -1378,27 +1383,37 @@ function InternalTextInput(props: Props): React.Node { const accessible = props.accessible !== false; const focusable = props.focusable !== false; + const { + editable, + hitSlop, + onPress, + onPressIn, + onPressOut, + rejectResponderTermination, + } = props; + const config = React.useMemo( () => ({ - hitSlop: props.hitSlop, + hitSlop, onPress: (event: PressEvent) => { - if (props.editable !== false) { + onPress?.(event); + if (editable !== false) { if (inputRef.current != null) { inputRef.current.focus(); } } }, - onPressIn: props.onPressIn, - onPressOut: props.onPressOut, - cancelable: - Platform.OS === 'ios' ? !props.rejectResponderTermination : null, + onPressIn: onPressIn, + onPressOut: onPressOut, + cancelable: Platform.OS === 'ios' ? !rejectResponderTermination : null, }), [ - props.editable, - props.hitSlop, - props.onPressIn, - props.onPressOut, - props.rejectResponderTermination, + editable, + hitSlop, + onPress, + onPressIn, + onPressOut, + rejectResponderTermination, ], );