Skip to content

Commit bf2b8dc

Browse files
authored
Typed gesture hooks (#3706)
## Description This PR introduces typed hooks for new API. ## Test plan <details> <summary>Tested on the following example:</summary> ```tsx import * as React from 'react'; import { Animated, Button } from 'react-native'; import { GestureHandlerRootView, NativeDetector, usePan, } from 'react-native-gesture-handler'; export default function App() { const [visible, setVisible] = React.useState(true); const gesture = usePan({ onUpdate: (e) => { 'worklet'; console.log(e.handlerData); }, }); return ( <GestureHandlerRootView style={{ flex: 1, backgroundColor: 'white', paddingTop: 8 }}> <Button title="Toggle visibility" onPress={() => { setVisible(!visible); }} /> {visible && ( <NativeDetector gesture={gesture}> <Animated.View style={[ { width: 150, height: 150, backgroundColor: 'blue', opacity: 0.5, borderWidth: 10, borderColor: 'green', marginTop: 20, marginLeft: 40, }, ]} /> </NativeDetector> )} </GestureHandlerRootView> ); } ``` </details> Also on other handlers.
1 parent ee6107f commit bf2b8dc

File tree

16 files changed

+812
-25
lines changed

16 files changed

+812
-25
lines changed

packages/react-native-gesture-handler/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,6 @@ export * from './v3/hooks/relations';
170170

171171
export { SingleGestureName } from './v3/types';
172172

173+
export * from './v3/hooks/gestures';
174+
173175
initialize();

packages/react-native-gesture-handler/src/v3/NativeDetector/NativeDetector.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { tagMessage } from '../../utils';
77
import { configureRelations } from './utils';
88
import { isComposedGesture } from '../hooks/utils/relationUtils';
99

10-
export interface NativeDetectorProps {
10+
export interface NativeDetectorProps<THandlerData, TConfig> {
1111
children?: React.ReactNode;
12-
gesture: Gesture;
12+
gesture: Gesture<THandlerData, TConfig>;
1313
}
1414

1515
const AnimatedNativeDetector =
@@ -18,7 +18,10 @@ const AnimatedNativeDetector =
1818
const ReanimatedNativeDetector =
1919
Reanimated?.default.createAnimatedComponent(HostGestureDetector);
2020

21-
export function NativeDetector({ gesture, children }: NativeDetectorProps) {
21+
export function NativeDetector<THandlerData, TConfig>({
22+
gesture,
23+
children,
24+
}: NativeDetectorProps<THandlerData, TConfig>) {
2225
const NativeDetectorComponent = gesture.config.dispatchesAnimatedEvents
2326
? AnimatedNativeDetector
2427
: gesture.config.shouldUseReanimated
@@ -38,25 +41,25 @@ export function NativeDetector({ gesture, children }: NativeDetectorProps) {
3841

3942
return (
4043
<NativeDetectorComponent
41-
// @ts-ignore TODO: Fix types
44+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
4245
onGestureHandlerStateChange={
4346
gesture.gestureEvents.onGestureHandlerStateChange
4447
}
45-
// @ts-ignore TODO: Fix types
48+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
4649
onGestureHandlerEvent={gesture.gestureEvents.onGestureHandlerEvent}
47-
// @ts-ignore TODO: Fix types
50+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
4851
onGestureHandlerTouchEvent={
4952
gesture.gestureEvents.onGestureHandlerTouchEvent
5053
}
51-
// @ts-ignore TODO: Fix types
54+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
5255
onGestureHandlerReanimatedStateChange={
5356
gesture.gestureEvents.onReanimatedStateChange
5457
}
55-
// @ts-ignore TODO: Fix types
58+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
5659
onGestureHandlerReanimatedEvent={
5760
gesture.gestureEvents.onReanimatedUpdateEvent
5861
}
59-
// @ts-ignore TODO: Fix types
62+
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
6063
onGestureHandlerReanimatedTouchEvent={
6164
gesture.gestureEvents.onReanimatedTouchEvent
6265
}

packages/react-native-gesture-handler/src/v3/NativeDetector/utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ export const traverseAndConfigureRelations = (
126126
});
127127
};
128128

129-
export function configureRelations(gesture: Gesture) {
129+
export function configureRelations<THandlerData, TConfig>(
130+
gesture: Gesture<THandlerData, TConfig>
131+
) {
130132
if (isComposedGesture(gesture)) {
131133
const simultaneousHandlers = new Set<number>(
132134
gesture.externalSimultaneousHandlers
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export type { TapGestureConfig } from './useTap';
2+
export { useTap } from './useTap';
3+
4+
export type { FlingGestureConfig } from './useFling';
5+
export { useFling } from './useFling';
6+
7+
export type { LongPressGestureConfig } from './useLongPress';
8+
export { useLongPress } from './useLongPress';
9+
10+
export type { PinchGestureConfig } from './usePinch';
11+
export { usePinch } from './usePinch';
12+
13+
export type { RotationGestureConfig } from './useRotation';
14+
export { useRotation } from './useRotation';
15+
16+
export type { HoverGestureConfig } from './useHover';
17+
export { useHover } from './useHover';
18+
19+
export type { ManualGestureConfig } from './useManual';
20+
export { useManual } from './useManual';
21+
22+
export type { NativeViewGestureConfig } from './useNative';
23+
export { useNative } from './useNative';
24+
25+
export type { PanGestureConfig } from './usePan';
26+
export { usePan } from './usePan';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {
2+
BaseGestureConfig,
3+
ExcludeInternalConfigProps,
4+
SingleGestureName,
5+
} from '../../types';
6+
import { useGesture } from '../useGesture';
7+
import { cloneConfig } from '../utils';
8+
9+
type FlingGestureProperties = {
10+
/**
11+
* Expressed allowed direction of movement. It's possible to pass one or many
12+
* directions in one parameter:
13+
*
14+
* ```js
15+
* direction={Directions.RIGHT | Directions.LEFT}
16+
* ```
17+
*
18+
* or
19+
*
20+
* ```js
21+
* direction={Directions.DOWN}
22+
* ```
23+
*/
24+
direction?: number;
25+
26+
/**
27+
* Determine exact number of points required to handle the fling gesture.
28+
*/
29+
numberOfPointers?: number;
30+
};
31+
32+
type FlingHandlerData = {
33+
x: number;
34+
y: number;
35+
absoluteX: number;
36+
absoluteY: number;
37+
};
38+
39+
type FlingGestureInternalConfig = BaseGestureConfig<
40+
FlingHandlerData,
41+
FlingGestureProperties
42+
>;
43+
44+
export type FlingGestureConfig =
45+
ExcludeInternalConfigProps<FlingGestureInternalConfig>;
46+
47+
export function useFling(config: FlingGestureConfig) {
48+
const flingConfig = cloneConfig<FlingHandlerData, FlingGestureProperties>(
49+
config
50+
);
51+
52+
return useGesture(SingleGestureName.Fling, flingConfig);
53+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { StylusData } from '../../../handlers/gestureHandlerCommon';
2+
import { HoverEffect } from '../../../handlers/gestures/hoverGesture';
3+
import {
4+
BaseGestureConfig,
5+
ExcludeInternalConfigProps,
6+
SingleGestureName,
7+
} from '../../types';
8+
import { useGesture } from '../useGesture';
9+
import { cloneConfig } from '../utils';
10+
11+
type HoverGestureProperties = {
12+
/**
13+
* Visual effect applied to the view while the view is hovered. The possible values are:
14+
*
15+
* - `HoverEffect.None`
16+
* - `HoverEffect.Lift`
17+
* - `HoverEffect.Highlight`
18+
*
19+
* Defaults to `HoverEffect.None`
20+
*/
21+
hoverEffect?: HoverEffect;
22+
};
23+
24+
type HoverHandlerData = {
25+
x: number;
26+
y: number;
27+
absoluteX: number;
28+
absoluteY: number;
29+
stylusData: StylusData;
30+
};
31+
32+
type HoverGestureInternalConfig = BaseGestureConfig<
33+
HoverHandlerData,
34+
HoverGestureProperties
35+
>;
36+
37+
export type HoverGestureConfig =
38+
ExcludeInternalConfigProps<HoverGestureInternalConfig>;
39+
40+
export function useHover(config: HoverGestureConfig) {
41+
const hoverConfig = cloneConfig<HoverHandlerData, HoverGestureProperties>(
42+
config
43+
);
44+
45+
return useGesture(SingleGestureName.Hover, hoverConfig);
46+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import {
2+
BaseGestureConfig,
3+
ExcludeInternalConfigProps,
4+
SingleGestureName,
5+
} from '../../types';
6+
import { useGesture } from '../useGesture';
7+
import { cloneConfig, remapProps } from '../utils';
8+
9+
type LongPressGestureProperties = {
10+
/**
11+
* Minimum time, expressed in milliseconds, that a finger must remain pressed on
12+
* the corresponding view. The default value is 500.
13+
*/
14+
minDuration?: number;
15+
16+
/**
17+
* Maximum distance, expressed in points, that defines how far the finger is
18+
* allowed to travel during a long press gesture. If the finger travels
19+
* further than the defined distance and the handler hasn't yet activated, it
20+
* will fail to recognize the gesture. The default value is 10.
21+
*/
22+
maxDistance?: number;
23+
24+
/**
25+
* Determine exact number of points required to handle the long press gesture.
26+
*/
27+
numberOfPointers?: number;
28+
};
29+
30+
type LongPressGestureInternalProperties = {
31+
minDurationMs?: number;
32+
maxDist?: number;
33+
numberOfPointers?: number;
34+
};
35+
36+
type LongPressHandlerData = {
37+
x: number;
38+
y: number;
39+
absoluteX: number;
40+
absoluteY: number;
41+
duration: number;
42+
};
43+
44+
export type LongPressGestureConfig = ExcludeInternalConfigProps<
45+
BaseGestureConfig<LongPressHandlerData, LongPressGestureProperties>
46+
>;
47+
48+
type LongPressGestureInternalConfig = BaseGestureConfig<
49+
LongPressHandlerData,
50+
LongPressGestureInternalProperties
51+
>;
52+
53+
const LongPressPropsMapping = new Map<
54+
keyof LongPressGestureProperties,
55+
keyof LongPressGestureInternalProperties
56+
>([
57+
['minDuration', 'minDurationMs'],
58+
['maxDistance', 'maxDist'],
59+
]);
60+
61+
export function useLongPress(config: LongPressGestureConfig) {
62+
const longPressConfig = cloneConfig<
63+
LongPressHandlerData,
64+
LongPressGestureInternalProperties
65+
>(config);
66+
67+
remapProps<LongPressGestureConfig, LongPressGestureInternalConfig>(
68+
longPressConfig,
69+
LongPressPropsMapping
70+
);
71+
72+
if (longPressConfig.shouldCancelWhenOutside === undefined) {
73+
longPressConfig.shouldCancelWhenOutside = true;
74+
}
75+
76+
return useGesture<LongPressHandlerData, LongPressGestureInternalProperties>(
77+
SingleGestureName.LongPress,
78+
longPressConfig
79+
);
80+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
BaseGestureConfig,
3+
ExcludeInternalConfigProps,
4+
SingleGestureName,
5+
} from '../../types';
6+
import { useGesture } from '../useGesture';
7+
import { cloneConfig } from '../utils';
8+
9+
type ManualGestureProperties = Record<string, never>;
10+
type ManualHandlerData = Record<string, never>;
11+
12+
type ManualGestureInternalConfig = BaseGestureConfig<
13+
ManualHandlerData,
14+
ManualGestureProperties
15+
>;
16+
17+
export type ManualGestureConfig =
18+
ExcludeInternalConfigProps<ManualGestureInternalConfig>;
19+
20+
export function useManual(config: ManualGestureConfig) {
21+
const manualConfig = cloneConfig<ManualHandlerData, ManualGestureProperties>(
22+
config
23+
);
24+
25+
return useGesture(SingleGestureName.Manual, manualConfig);
26+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {
2+
BaseGestureConfig,
3+
ExcludeInternalConfigProps,
4+
SingleGestureName,
5+
} from '../../types';
6+
import { useGesture } from '../useGesture';
7+
import { cloneConfig } from '../utils';
8+
9+
type NativeViewGestureProperties = {
10+
/**
11+
* Android only.
12+
*
13+
* Determines whether the handler should check for an existing touch event on
14+
* instantiation.
15+
*/
16+
shouldActivateOnStart?: boolean;
17+
18+
/**
19+
* When `true`, cancels all other gesture handlers when this
20+
* `NativeViewGestureHandler` receives an `ACTIVE` state event.
21+
*/
22+
disallowInterruption?: boolean;
23+
};
24+
25+
type NativeViewHandlerData = {
26+
pointerInside: boolean;
27+
};
28+
29+
type NativeViewGestureInternalConfig = BaseGestureConfig<
30+
NativeViewHandlerData,
31+
NativeViewGestureProperties
32+
>;
33+
34+
export type NativeViewGestureConfig =
35+
ExcludeInternalConfigProps<NativeViewGestureInternalConfig>;
36+
37+
export function useNative(config: NativeViewGestureConfig) {
38+
const nativeConfig = cloneConfig<
39+
NativeViewHandlerData,
40+
NativeViewGestureProperties
41+
>(config);
42+
43+
return useGesture(SingleGestureName.Native, nativeConfig);
44+
}

0 commit comments

Comments
 (0)