Skip to content

Commit 6313763

Browse files
j-piaseckim-bert
andauthored
[General] Move the end flag to the event passed to onDeactivate and onFinalize (#3887)
## Description Up to this point, the API mirrored V2, where `success` was being passed as an additional parameter to the end callbacks. This PR changes it, so the flag is being passed as part of the event to the callbacks. I also think that the approach to working with gestures is to assume that they will succeed, so I changed the flag to `canceled`. This also seems to be the easiest one to explain in the docs - "the gesture was canceled due to failure to meet activation criteria, the activation of another gesture, by the OS". ## Test plan Verify that `calceled` exists in events passed to `onDeactivate` and `onFinalize`. --------- Co-authored-by: Michał Bert <63123542+m-bert@users.noreply.github.com>
1 parent 0d7a377 commit 6313763

21 files changed

Lines changed: 131 additions & 243 deletions

File tree

apps/common-app/src/new_api/components/switchAndInput/index.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
} from 'react-native-gesture-handler';
77
import React, { useState } from 'react';
88
import { StyleSheet, Text, View } from 'react-native';
9-
import type { NativeGestureEvent } from 'react-native-gesture-handler';
109

1110
export default function SwitchTextInputExample() {
1211
const [switchOn, setSwitchOn] = useState(false);
@@ -22,8 +21,8 @@ export default function SwitchTextInputExample() {
2221
<TextInput
2322
onBegin={() => console.log('[TextInput] onBegin')}
2423
onActivate={() => console.log('[TextInput] onActivate')}
25-
onFinalize={(_: NativeGestureEvent, s: boolean) =>
26-
console.log('[TextInput] onFinalize', s)
24+
onFinalize={(e) =>
25+
console.log('[TextInput] onFinalize', e.canceled)
2726
}
2827
style={styles.input}
2928
placeholder="Type here..."
@@ -50,9 +49,7 @@ export default function SwitchTextInputExample() {
5049
<View style={styles.switchRow}>
5150
<Switch
5251
onBegin={() => console.log('[Switch] onBegin')}
53-
onFinalize={(_: NativeGestureEvent, s: boolean) =>
54-
console.log('[Switch] onFinalize', s)
55-
}
52+
onFinalize={(e) => console.log('[Switch] onFinalize', e.canceled)}
5653
value={switchOn}
5754
onValueChange={(v: boolean) => {
5855
console.log('[Switch] onValueChange', v);

apps/common-app/src/new_api/hover_mouse/hover/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ function useColoredHover(
3030
onActivate: () => {
3131
console.log('hover start', color);
3232
},
33-
onDeactivate: (_, success) => {
34-
console.log('hover end', color, 'failed', !success);
33+
onDeactivate: (e) => {
34+
console.log('hover end', color, 'failed', e.canceled);
3535
},
3636
onFinalize: () => {
3737
hovered.value = false;

apps/common-app/src/new_api/showcase/overlap/index.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function OverlapSiblings() {
3131
const [elevated, setElevated] = React.useState('');
3232

3333
const tapPurple = useTapGesture({
34-
onDeactivate: (_e, success) => {
35-
if (success) {
34+
onDeactivate: (e) => {
35+
if (!e.canceled) {
3636
setElevated('purple');
3737
feedbackRef.current?.showMessage('Tapped purple');
3838
}
@@ -41,8 +41,8 @@ function OverlapSiblings() {
4141
});
4242

4343
const tapBlue = useTapGesture({
44-
onDeactivate: (_e, success) => {
45-
if (success) {
44+
onDeactivate: (e) => {
45+
if (!e.canceled) {
4646
setElevated('blue');
4747
feedbackRef.current?.showMessage('Tapped blue');
4848
}
@@ -75,8 +75,8 @@ function OverlapParents() {
7575
const [elevated, setElevated] = React.useState('');
7676

7777
const tapRed = useTapGesture({
78-
onDeactivate: (_e, success) => {
79-
if (success) {
78+
onDeactivate: (e) => {
79+
if (!e.canceled) {
8080
feedbackRef.current?.showMessage('Tapped purple');
8181
setElevated('purple');
8282
}
@@ -85,8 +85,8 @@ function OverlapParents() {
8585
});
8686

8787
const tapGreen = useTapGesture({
88-
onDeactivate: (_e, success) => {
89-
if (success) {
88+
onDeactivate: (e) => {
89+
if (!e.canceled) {
9090
feedbackRef.current?.showMessage('Tapped blue');
9191
setElevated('blue');
9292
}

apps/common-app/src/new_api/simple/longPress/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ export default function LongPressExample() {
3838
duration: 100,
3939
});
4040
},
41-
onFinalize: (_, success) => {
42-
finalise_color.value = success ? COLORS.GREEN : COLORS.RED;
41+
onFinalize: (e) => {
42+
finalise_color.value = e.canceled ? COLORS.RED : COLORS.GREEN;
4343
colorProgress.value = 1;
4444
colorProgress.value = withTiming(
4545
0,

packages/docs-gesture-handler/docs/fundamentals/callbacks-events.mdx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,18 @@ Called each time a pointer tracked by the gesture changes state, typically due t
5555
### onDeactivate
5656

5757
```ts
58-
onDeactivate: (event: GestureEvent<HandlerData>, didSucceed: boolean) => void
58+
onDeactivate: (event: GestureEndEvent<HandlerData>) => void
5959
```
6060

61-
Called when handler stops recognizing gestures, but only if the handler activated. It is called before `onFinalize`. If the handler was interrupted, the `didSucceed` argument is set to `false`. Otherwise it is set to `true`.
61+
Called when handler stops recognizing gestures, but only if the handler activated. It is called before `onFinalize`. The event object contains a `canceled` property — if the gesture was interrupted, `canceled` is set to `true`. Otherwise it is set to `false`.
6262

6363
### onFinalize
6464

6565
```ts
66-
onFinalize: (event: GestureEvent<HandlerData>, didSucceed: boolean) => void
66+
onFinalize: (event: GestureEndEvent<HandlerData>) => void
6767
```
6868

69-
Called when handler stops recognizing gestures. If the handler managed to activate, the `didSucceed` argument is set to `true` and `onFinalize` will be called right after `onDeactivate`. Otherwise it is set to `false`.
69+
Called when handler stops recognizing gestures. The event object contains a `canceled` property — if the handler failed to activate or was interrupted, `canceled` is set to `true`. If the handler managed to activate and completed successfully, `canceled` is set to `false` and `onFinalize` will be called right after `onDeactivate`.
7070

7171
### onTouchesDown
7272

@@ -107,14 +107,18 @@ Called when there will be no more information about this pointer. It may be call
107107
<CollapsibleCode
108108
label="Show composed types definitions"
109109
expandedLabel="Hide composed types definitions"
110-
lineBounds={[0, 4]}
110+
lineBounds={[0, 8]}
111111
src={`
112112
export type GestureEvent<HandlerData> = {
113113
handlerTag: number;
114114
numberOfPointers: number;
115115
pointerType: PointerType;
116116
} & HandlerData;
117117
118+
export type GestureEndEvent<HandlerData> = {
119+
canceled: boolean;
120+
} & GestureEvent<HandlerData>;
121+
118122
export enum PointerType {
119123
TOUCH,
120124
STYLUS,
@@ -126,6 +130,10 @@ export enum PointerType {
126130

127131
`GestureEvent` contains properties common to all gestures (`handlerTag`, `numberOfPointers`, `pointerType`) along with gesture-specific data defined in each gesture's documentation.
128132

133+
### GestureEndEvent
134+
135+
`GestureEndEvent` extends `GestureEvent` with a `canceled` property. It is used in the [`onDeactivate`](#ondeactivate) and [`onFinalize`](#onfinalize) callbacks. When `canceled` is `true`, the gesture was interrupted or failed to activate. When `false`, the gesture completed successfully.
136+
129137
### TouchEvent
130138

131139
<CollapsibleCode

packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-callbacks.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ Set the callback that is being called when the gesture is recognized by the hand
2424

2525
{
2626
<CodeBlock className="language-ts">
27-
{`onDeactivate: (event: ${props.gesture}HandlerData, didSucceed: boolean) => void`}
27+
{`onDeactivate: (event: ${props.gesture}HandlerData & { canceled: boolean }) => void`}
2828
</CodeBlock>
2929
}
3030

31-
Set the callback that is being called when the gesture that was recognized by the handler finishes. It will be called only if the handler was previously in the active state.
31+
Set the callback that is being called when the gesture that was recognized by the handler finishes. It will be called only if the handler was previously in the active state. The event object contains a `canceled` property — if the gesture was interrupted, `canceled` is set to `true`. Otherwise it is set to `false`.
3232

3333
### onFinalize
3434

3535
{
3636
<CodeBlock className="language-ts">
37-
{`onFinalize: (event: ${props.gesture}HandlerData, didSucceed: boolean) => void`}
37+
{`onFinalize: (event: ${props.gesture}HandlerData & { canceled: boolean }) => void`}
3838
</CodeBlock>
3939
}
4040

41-
Set the callback that is being called when the handler finalizes handling gesture - the gesture was recognized and has finished or it failed to recognize.
41+
Set the callback that is being called when the handler finalizes handling gesture - the gesture was recognized and has finished or it failed to recognize. The event object contains a `canceled` property — if the gesture failed to activate or was interrupted, `canceled` is set to `true`. Otherwise it is set to `false`.
4242

4343
### onTouchesDown
4444

packages/docs-gesture-handler/docs/guides/upgrading-to-3.mdx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,32 @@ code2={
9292
`}
9393
/>
9494

95+
### canceled instead of success
96+
97+
In RNGH2, `onEnd` and `onFinalize` received a second `success` boolean parameter. In RNGH3, this has been replaced with a `canceled` property on the event object itself. Note that the logic is inverted — `canceled: true` corresponds to the old `success: false`.
98+
99+
<CodeComparison
100+
label1={"RNGH 2"}
101+
label2={"RNGH 3"}
102+
code1={
103+
`const gesture = Gesture.Tap()
104+
.onEnd((event, success) => {
105+
if (success) {
106+
console.log('Gesture succeeded!');
107+
}
108+
});
109+
`}
110+
code2={
111+
`const gesture = useTapGesture({
112+
onDeactivate: (event) => {
113+
if (!event.canceled) {
114+
console.log('Gesture succeeded!');
115+
}
116+
},
117+
});
118+
`}
119+
/>
120+
95121
### onChange
96122

97123
`onChange` callback has been removed, and its functionality has been integrated into `onUpdate`. You can now access `change*` properties in `onUpdate` callback.

packages/docs-gesture-handler/docs/under-the-hood/state.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ States manage the internal recognition process. You can hook into these transiti
1414
| **`UNDETERMINED`** | The default initial state of every handler. ||
1515
| **`BEGAN`** | The handler has started receiving touch data but hasn't yet met the activation criteria. | [`onBegin`](/docs/fundamentals/callbacks-events#onbegin) |
1616
| **`ACTIVE`** | The gesture is recognized and activation criteria are met. | [`onActivate`](/docs/fundamentals/callbacks-events#onactivate) when it first transitions into the `ACTIVE` state. <br /><br /> [`onUpdate`](/docs/fundamentals/callbacks-events#onupdate) when it has new data about the gesture. |
17-
| **`END`** | The user successfully completed the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) with `didSucceed` parameter set to `true`. <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `didSucceed` parameter set to `true`. |
18-
| **`FAILED`** | The handler failed to recognize the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) if the gesture was in `ACTIVE` state before. `didSucceed` parameter will be set to `false` <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `didSucceed` parameter set to `false`. |
19-
| **`CANCELLED`** | The system interrupted the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) if the gesture was in `ACTIVE` state before. `didSucceed` parameter will be set to `false` <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `didSucceed` parameter set to `false`. |
17+
| **`END`** | The user successfully completed the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) with `event.canceled` set to `false`. <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `event.canceled` set to `false`. |
18+
| **`FAILED`** | The handler failed to recognize the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) if the gesture was in `ACTIVE` state before, with `event.canceled` set to `true`. <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `event.canceled` set to `true`. |
19+
| **`CANCELLED`** | The system interrupted the gesture. | [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) if the gesture was in `ACTIVE` state before, with `event.canceled` set to `true`. <br/><br/> [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) with `event.canceled` set to `true`. |

packages/react-native-gesture-handler/src/v3/components/GestureButtons.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import type {
55
RawButtonProps,
66
RectButtonProps,
77
} from './GestureButtonsProps';
8+
import type { GestureEndEvent, GestureEvent } from '../types';
89
import React, { useRef } from 'react';
9-
import type { GestureEvent } from '../types';
1010
import GestureHandlerButton from '../../components/GestureHandlerButton';
1111
import type { NativeHandlerData } from '../hooks/gestures/native/NativeTypes';
1212
import createNativeWrapper from '../createNativeWrapper';
1313

1414
type CallbackEventType = GestureEvent<NativeHandlerData>;
15+
type EndCallbackEventType = GestureEndEvent<NativeHandlerData>;
1516

1617
/**
1718
* @deprecated `RawButton` is deprecated, use `Clickable` instead
@@ -66,23 +67,23 @@ export const BaseButton = (props: BaseButtonProps) => {
6667
props.onActivate?.(e);
6768
};
6869

69-
const onDeactivate = (e: CallbackEventType, didSucceed: boolean) => {
70+
const onDeactivate = (e: EndCallbackEventType) => {
7071
onActiveStateChange?.(false);
7172

72-
if (didSucceed && !longPressDetected.current) {
73+
if (!e.canceled && !longPressDetected.current) {
7374
onPress?.(e.pointerInside);
7475
}
7576

76-
props.onDeactivate?.(e, didSucceed);
77+
props.onDeactivate?.(e);
7778
};
7879

79-
const onFinalize = (e: CallbackEventType, didSucceed: boolean) => {
80+
const onFinalize = (e: EndCallbackEventType) => {
8081
if (longPressTimeout.current !== undefined) {
8182
clearTimeout(longPressTimeout.current);
8283
longPressTimeout.current = undefined;
8384
}
8485

85-
props.onFinalize?.(e, didSucceed);
86+
props.onFinalize?.(e);
8687
};
8788

8889
return (

packages/react-native-gesture-handler/src/v3/components/Pressable.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,13 @@ const Pressable = (props: PressableProps) => {
273273
stateMachine.reset();
274274
handlePressOut(pressableEvent, false);
275275
},
276-
onFinalize: (_event, success) => {
276+
onFinalize: (event) => {
277277
if (Platform.OS !== 'web') {
278278
return;
279279
}
280280

281281
stateMachine.handleEvent(
282-
success ? StateMachineEvent.FINALIZE : StateMachineEvent.CANCEL
282+
event.canceled ? StateMachineEvent.CANCEL : StateMachineEvent.FINALIZE
283283
);
284284

285285
handleFinalize();
@@ -312,14 +312,14 @@ const Pressable = (props: PressableProps) => {
312312
stateMachine.handleEvent(StateMachineEvent.NATIVE_START);
313313
}
314314
},
315-
onFinalize: (_event, success) => {
315+
onFinalize: (event) => {
316316
// On Web we use LongPress.onFinalize instead of Native.onFinalize,
317317
// as Native cancels on mouse move, and LongPress does not.
318318
if (Platform.OS === 'web') {
319319
return;
320320
}
321321
stateMachine.handleEvent(
322-
success ? StateMachineEvent.FINALIZE : StateMachineEvent.CANCEL
322+
event.canceled ? StateMachineEvent.CANCEL : StateMachineEvent.FINALIZE
323323
);
324324

325325
handleFinalize();

0 commit comments

Comments
 (0)