Repository navigation
Commit bcd4b52
authored
[Web] Drop handlers that never began from the orchestrator (#4505)
## Description
A button pressed inside its element but outside a negative `hitSlop`
killed every other button on the page: nothing pressed after that would
begin, until the first button was pressed properly.
The orchestrator records a handler on pointer-down, before the handler
calls `begin()`. When the hit slop check rejects the pointer, `begin()`
bails and the handler stays `UNDETERMINED`. On release it goes through
`fail()`, which only acts on `BEGAN` and `ACTIVE`, so it never reaches a
finished state and the orchestrator's finished-handler cleanup never
drops it. Every later button then finds the stale entry in
`shouldBeginWithRecordedHandlers` and cancels itself. A handler waiting
for such an entry through `waitFor` would stay parked the same way.
`recordHandlerIfNotPresent` now drops recorded handlers that are
`UNDETERMINED` with no tracked pointers before a new gesture consults
the list. That combination only describes a handler whose pointer
sequence ended without a begin: every handler adds the pointer to its
tracker before recording itself, so anything in flight has at least one.
## Test plan
Added tests in `GestureHandler.test.ts`, the first fails without the
fix.
Manually, on web: a `Touchable` with `hitSlop={-40}` next to a second,
plain `Touchable` with a press counter.
- tap the second button: counts
- tap the first button in its outer 40 px band: nothing, as expected
- tap the second button again: counts, previously it was dead
<details>
<summary>Tested on the following code:</summary>
```tsx
import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Touchable } from 'react-native-gesture-handler';
// Web only: a button pressed inside its element but outside a negative hitSlop
// never begins, yet it was already recorded by the orchestrator on pointer-down.
// Nothing ever finishes it, so it stays recorded and every other button cancels
// itself against the stale entry. Pressing the trap inside its slop clears it.
const TRAP_SLOP = -40;
export default function EmptyExample() {
const [trap, setTrap] = useState(0);
const [victim, setVictim] = useState(0);
return (
<View style={styles.container}>
<Text>
1. tap "victim" (counts). 2. tap the outer {-TRAP_SLOP}px band of "trap"
(nothing, expected). 3. tap "victim" again: should count.
</Text>
<Touchable
hitSlop={TRAP_SLOP}
onPress={() => setTrap((n) => n + 1)}
style={styles.trap}>
<View style={styles.trapInner}>
<Text style={styles.text}>trap: {trap}</Text>
</View>
</Touchable>
<Touchable onPress={() => setVictim((n) => n + 1)} style={styles.victim}>
<Text style={styles.text}>victim: {victim}</Text>
</Touchable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
gap: 12,
},
text: {
color: 'white',
fontWeight: '600',
},
trap: {
height: 120,
borderRadius: 8,
backgroundColor: '#d5865b',
padding: -TRAP_SLOP,
},
trapInner: {
flex: 1,
borderRadius: 4,
backgroundColor: '#b4643a',
justifyContent: 'center',
alignItems: 'center',
},
victim: {
height: 44,
borderRadius: 8,
backgroundColor: '#3a3a3a',
justifyContent: 'center',
alignItems: 'center',
},
});
```
</details>1 parent c5db1fc commit bcd4b52
2 files changed
Lines changed: 78 additions & 1 deletion
File tree
- packages/react-native-gesture-handler/src/web
- handlers/__tests__
- tools
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
1 | 2 | | |
2 | | - | |
| 3 | + | |
| 4 | + | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
| |||
112 | 114 | | |
113 | 115 | | |
114 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
274 | 274 | | |
275 | 275 | | |
276 | 276 | | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
277 | 294 | | |
| 295 | + | |
| 296 | + | |
278 | 297 | | |
279 | 298 | | |
280 | 299 | | |
| |||
0 commit comments