Skip to content

fix(input): ensure taps on rich text input don't trigger parent onPress - #10

Closed
hsource wants to merge 2 commits into
mainfrom
fix/input-use-pressability
Closed

hsource wants to merge 2 commits into
mainfrom
fix/input-use-pressability

Conversation

@hsource

@hsource hsource commented Sep 23, 2026 •

Copy link
Copy Markdown

Note: this PR has been manually reviewed and is a version of code that's been part of the Wanderlog (wanderlog.com) mobile apps for the past 3 weeks

What/Why?

EnrichedMarkdownTextInput doesn't take part in the JS touch responder system the way React Native TextInput does. Wrap it in a Pressable (for example a card that collapses on press), and tapping the input to focus it also fires the parent's onPress.

JS side (both Android and iOS): Fix to make taps not trigger press handlers in parents

  • Attaches usePressability to the native input, the same way TextInput does. The input now claims the responder, so ancestor pressables don't fire.
  • Adds the matching TextInput props onPress, onPressIn, onPressOut and rejectResponderTermination (default true, iOS only), typed with Pick<TextInputProps, ...> so they stay in sync with React Native. hitSlop already comes from ViewProps. All are documented in API_REFERENCE.md.
  • onPress focuses the input unless editable={false}, through TextInputState.focusTextInput, the same call TextInput's host focus() makes. It is a no-op when the tap already focused the native view, and only matters when the press lands outside it (for example in the hitSlop area). onFocus and onBlur still come from the native events, not from pressability.

Android side: Fix to not make programmatic focus override selection

  • requestFocusProgrammatically no longer calls setSelection, matching ReactEditText.requestFocusProgrammatically.
  • That setSelection call was also the only thing reporting some caret moves to JS. onSelectionChanged ignores changes made during an edit phase, so setValue and programmatic inserts (images, links, mentions) never emitted onChangeSelection. The input now emits the current selection once those phases end, as iOS already does.

The playground wraps the editor in a Pressable with a "Parent presses" counter, and shows the Selection: start-end range reported by onChangeSelection, so both can be checked by hand and in Maestro.

Testing

Checks run: yarn typecheck, eslint, prettier, Jest, ktlint, Android compileDebugKotlin, and example app builds for the iOS simulator (iPhone 17, iOS 26.4) and a Pixel 6a.

Automated testing for JS Pressability fix

input_pressability_test.yaml passes on both platforms. Tapping the editor leaves Parent presses at 0; tapping the label outside it increments it to 1.

iOS Android

Automated flows:

yarn test:e2e:ios .maestro/enrichedMarkdownInput/flows/basic/inline_elements/input_pressability_test.yaml
yarn test:e2e:android .maestro/enrichedMarkdownInput/flows/basic/inline_elements/input_pressability_test.yaml

Manual testing for Android focus setting selection fix

Setup:

yarn && yarn prepare
yarn react-native-example start
yarn react-native-example ios   # then repeat with: yarn react-native-example android
Before After
screen-20260923-115440-1790189674348.mp4
screen-20260923-115833-1790189906493.mp4

PR Checklist

  • Code compiles and runs on iOS
  • Code compiles and runs on Android
  • Updated documentation/README if applicable
  • Ran example app to verify changes
  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

@hsource
hsource force-pushed the fix/input-use-pressability branch from 35f3981 to 358de94 Compare September 23, 2026 18:38
hsource and others added 2 commits September 23, 2026 14:23
Attach usePressability to the native input like React Native TextInput, so
a tap that focuses the input claims the JS responder and no longer fires an
ancestor Pressable's onPress. Adds onPress, onPressIn, onPressOut, hitSlop
and rejectResponderTermination.

On Android, programmatic focus no longer calls setSelection, matching
ReactEditText.requestFocusProgrammatically. Pressability focuses the input
on finger-up, which previously collapsed a long-press word selection.

That setSelection call was also the only thing reporting some caret moves
to JS: onSelectionChanged ignores changes made during an edit phase, so
setValue and programmatic inserts (images, links, mentions) never emitted
onChangeSelection. Emit the current selection after those phases end, as
iOS already does.
Playground wraps the editor in a Pressable with a visible counter so testers
can confirm taps on the input do not bubble to the parent handler, and shows
the current selection range reported by onChangeSelection.

Co-authored-by: Cursor <cursoragent@cursor.com>
@hsource
hsource force-pushed the fix/input-use-pressability branch from 358de94 to 3992094 Compare September 23, 2026 21:23
@hsource hsource changed the title fix(input): match RN TextInput touch and focus behaviour fix(input): ensure taps on rich text input don't trigger parent taps Sep 24, 2026
@hsource hsource changed the title fix(input): ensure taps on rich text input don't trigger parent taps fix(input): ensure taps on rich text input don't trigger parent onPress Sep 24, 2026
@hsource

hsource commented Sep 24, 2026

Copy link
Copy Markdown
Author

Moved upstream: software-mansion#884

@hsource hsource closed this Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant