Skip to content

Reset numberOfPointers in LongPressGestureHandler - #4479

Merged
j-piasecki merged 1 commit into
software-mansion:mainfrom
giaBaoJS:fix/long-press-reset-number-of-pointers
Sep 4, 2026
Merged

Reset numberOfPointers in LongPressGestureHandler#4479
j-piasecki merged 1 commit into
software-mansion:mainfrom
giaBaoJS:fix/long-press-reset-number-of-pointers

Conversation

@giaBaoJS

@giaBaoJS giaBaoJS commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Description

LongPressGestureHandler accepts numberOfPointers but never resets it, so the value survives a config update that no longer sets it.

setConfig rebuilds a handler's whole config as resetConfig() followed by updateConfig():

  • web: src/web/handlers/GestureHandler.ts:790
  • Apple: apple/RNGestureHandler.mm:131
  • Android: android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt:911

updateConfig only assigns properties that are present in the incoming config, so every property it can write has to be cleared by resetConfig. numberOfPointers was written but never cleared:

  • src/web/handlers/LongPressGestureHandler.ts:127 writes it, :76 did not reset it
  • android/.../core/LongPressGestureHandler.kt:197 writes it, :34 did not reset it
  • apple/Handlers/RNLongPressHandler.m:255 writes it, :232 did not reset it

Every sibling handler already resets its pointer count, which is what made this stand out: Tap resets minNumberOfPointers, Fling resets numberOfPointersRequired, Pan resets minPointers/maxPointers.

What breaks

GestureDetector re-sends the full config on every update (src/handlers/gestures/GestureDetector/updateHandlers.ts:68), and the config only contains numberOfPointers when the gesture actually sets it. So a long press that stops requesting a multi pointer press keeps the stale requirement:

const longPress = useLongPressGesture(
  twoFingerMode ? { numberOfPointers: 2 } : {}
);

After twoFingerMode flips back to false, the handler still requires 2 pointers. On web tryActivate returns early because trackedPointersCount !== numberOfPointers (src/web/handlers/LongPressGestureHandler.ts:163), so a normal one finger long press never activates again. The same holds for the v2 Gesture.LongPress().numberOfPointers(2) builder and the v1 <LongPressGestureHandler numberOfPointers={2}> prop.

The fix resets the value on all three platforms, using a named default in the two places that had a bare literal.

Test plan

Added src/web/handlers/__tests__/LongPressGestureHandler.test.ts, following the existing GestureHandler.test.ts / webNativeViewGestureHandler.test.ts pattern. One test drives the regression (config with numberOfPointers: 2, then a config without it, then a single pointer press), and one control test confirms numberOfPointers still applies while it is in the config.

Counterfactual, run in this checkout. With the fix:

$ yarn jest src/web/handlers/__tests__/LongPressGestureHandler.test.ts
PASS src/web/handlers/__tests__/LongPressGestureHandler.test.ts
  LongPressGestureHandler config reset
    v a config without numberOfPointers restores the single pointer default (2 ms)
    v numberOfPointers still applies while it stays in the config

Then reverting only src/web/handlers/LongPressGestureHandler.ts and keeping the test:

$ git show HEAD:packages/.../src/web/handlers/LongPressGestureHandler.ts > packages/.../src/web/handlers/LongPressGestureHandler.ts
$ yarn jest src/web/handlers/__tests__/LongPressGestureHandler.test.ts
  x a config without numberOfPointers restores the single pointer default

    expect(received).toBe(expected) // Object.is equality

    Expected: 4
    Received: 2

    > 74 |     expect(handler.state).toBe(State.ACTIVE);

Tests: 1 failed, 1 passed, 2 total

4 is State.ACTIVE, 2 is State.BEGAN: the handler stayed in BEGAN because it was still waiting for a second pointer. Restoring the file turns it green again. The control test passes in both directions, so the failure is specific to the reset.

Checks in this checkout:

  • yarn workspace react-native-gesture-handler test -> 20 suites, 163 tests passing (162 before this change)
  • yarn workspace react-native-gesture-handler ts-check -> clean
  • yarn eslint --ext '.js,.ts,.tsx' src/ -> 0 errors, 0 warnings on the touched files
  • yarn prettier --check './src/**/*.{js,jsx,ts,tsx}' -> all matched files use Prettier code style
  • ./android/gradlew -p android spotlessCheck -q -> exit 0
  • clang-format --style=file on RNLongPressHandler.m -> no diff on the changed lines

The Android and Apple changes mirror the web one and are not covered by the Jest suite; I did not run them on a device.

`setConfig` rebuilds a handler's config as `resetConfig` followed by
`updateConfig`, so every property the setter writes must be cleared by
the reset. The long press handler wrote `numberOfPointers` but never
reset it, so once a gesture was configured with more than one pointer,
dropping the property on a later config update left the old value in
place and single pointer long presses stopped activating.

Sibling handlers already reset their pointer counts: `Tap` resets
`minNumberOfPointers`, `Fling` resets `numberOfPointersRequired` and
`Pan` resets `minPointers`/`maxPointers`.
Copilot AI lite review requested due to automatic review settings September 3, 2026 12:05
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 05ea890e-4211-451d-8b9c-e7149c315f20

📥 Commits

Reviewing files that changed from the base of the PR and between 6f45895 and 2f70415.

📒 Files selected for processing (4)
  • packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt
  • packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m
  • packages/react-native-gesture-handler/src/web/handlers/LongPressGestureHandler.ts
  • packages/react-native-gesture-handler/src/web/handlers/__tests__/LongPressGestureHandler.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes

    • Long-press gestures now consistently restore the default requirement of one pointer when their configuration is reset across Android, iOS, and web.
    • Custom multi-pointer settings remain respected when explicitly configured.
  • Tests

    • Added web coverage verifying default and multi-pointer behavior after configuration resets.

Walkthrough

Changes

Long-press pointer reset defaults

Layer / File(s) Summary
Restore pointer defaults across platforms
packages/react-native-gesture-handler/android/.../LongPressGestureHandler.kt, packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m, packages/react-native-gesture-handler/src/web/handlers/LongPressGestureHandler.ts
Android, Apple, and web handlers restore the single-pointer default during configuration reset.
Validate web configuration resets
packages/react-native-gesture-handler/src/web/handlers/__tests__/LongPressGestureHandler.test.ts
Tests verify single-pointer activation after reset and continued two-pointer behavior when configured.

Suggested reviewers: m-bert

Merge Risk: ⚪ Minimal · up to 2f704

Long-press handlers now restore the default single-pointer requirement when configuration removes a previous multi-pointer setting, preserving explicitly configured multi-pointer behavior. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: resetting numberOfPointers in LongPressGestureHandler.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is narrowly scoped, aligns with the existing resetConfig/updateConfig contract, and includes a targeted web regression test that demonstrates the fix.

Pull request overview

Fixes a stale-config bug where LongPressGestureHandler’s numberOfPointers/touch-count requirement could persist after a config update that no longer specifies it, by resetting the pointer-count default during resetConfig() across web, Apple, and Android implementations.

Changes:

  • Web: introduce a named default for numberOfPointers and reset it in resetConfig().
  • Apple + Android: reset the platform-specific touch/pointer requirement back to the single-pointer default during resetConfig().
  • Add a Jest regression test on web covering removal of numberOfPointers from config updates.
File summaries
File Description
packages/react-native-gesture-handler/src/web/handlers/LongPressGestureHandler.ts Resets numberOfPointers to the default during config reset to prevent stale requirements after updates.
packages/react-native-gesture-handler/src/web/handlers/tests/LongPressGestureHandler.test.ts Adds a regression test verifying that removing numberOfPointers from config restores the single-pointer default, plus a control test.
packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m Resets numberOfTouchesRequired to 1 (non-tvOS) in resetConfig() so stale touch requirements don’t survive config rebuilds.
packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt Resets numberOfPointersRequired to a named default constant during resetConfig().
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@j-piasecki j-piasecki left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@j-piasecki
j-piasecki merged commit 2efd514 into software-mansion:main Sep 4, 2026
11 of 12 checks passed
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.

3 participants