Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,12 @@ function getHandlerData(
};

if (eventName === 'onGestureHandlerStateChange') {
componentOrGesture.detectorCallbacks.onGestureHandlerStateChange({
componentOrGesture.detectorCallbacks.jsEventHandler?.({
oldState: oldState as State,
...event,
});
} else if (eventName === 'onGestureHandlerEvent') {
componentOrGesture.detectorCallbacks.onGestureHandlerEvent?.(event);
componentOrGesture.detectorCallbacks.jsEventHandler?.(event);
}
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
nativeDetectorStyles,
} from './common';
import { ReanimatedNativeDetector } from './ReanimatedNativeDetector';
import { Platform } from 'react-native';

export function NativeDetector<THandlerData, TConfig>({
gesture,
Expand All @@ -29,37 +30,54 @@ export function NativeDetector<THandlerData, TConfig>({
return isComposedGesture(gesture) ? gesture.tags : [gesture.tag];
}, [gesture]);

// On web, we're triggering Reanimated callbacks ourselves, based on the type.
// To handle this properly, we need to provide all three callbacks, so we set
// all three to the Reanimated event handler.
// On native, Reanimated handles routing internally based on the event names
// passed to the useEvent hook. We only need to pass it once, so that Reanimated
// can setup its internal listeners.
const reanimatedHandlers =
Platform.OS === 'web'
? {
onGestureHandlerReanimatedEvent:
gesture.detectorCallbacks.reanimatedEventHandler,
onGestureHandlerReanimatedStateChange:
gesture.detectorCallbacks.reanimatedEventHandler,
onGestureHandlerReanimatedTouchEvent:
gesture.detectorCallbacks.reanimatedEventHandler,
}
: {
onGestureHandlerReanimatedEvent:
gesture.detectorCallbacks.reanimatedEventHandler,
};

return (
<NativeDetectorComponent
touchAction={touchAction}
userSelect={userSelect}
enableContextMenu={enableContextMenu}
pointerEvents={'box-none'}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerStateChange={
gesture.detectorCallbacks.onGestureHandlerStateChange
}
onGestureHandlerStateChange={gesture.detectorCallbacks.jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerEvent={gesture.detectorCallbacks.onGestureHandlerEvent}
onGestureHandlerEvent={gesture.detectorCallbacks.jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerTouchEvent={
gesture.detectorCallbacks.onGestureHandlerTouchEvent
}
onGestureHandlerTouchEvent={gesture.detectorCallbacks.jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedStateChange={
gesture.detectorCallbacks.onReanimatedStateChange
reanimatedHandlers.onGestureHandlerReanimatedStateChange
}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedEvent={
gesture.detectorCallbacks.onReanimatedUpdateEvent
reanimatedHandlers.onGestureHandlerReanimatedEvent
}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedTouchEvent={
gesture.detectorCallbacks.onReanimatedTouchEvent
reanimatedHandlers.onGestureHandlerReanimatedTouchEvent
}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerAnimatedEvent={
gesture.detectorCallbacks.onGestureHandlerAnimatedEvent
gesture.detectorCallbacks.animatedEventHandler
}
moduleId={globalThis._RNGH_MODULE_ID}
handlerTags={handlerTags}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { tagMessage } from '../../../utils';
import { useEnsureGestureHandlerRootView } from '../useEnsureGestureHandlerRootView';
import { ReanimatedNativeDetector } from '../ReanimatedNativeDetector';
import { Platform } from 'react-native';

interface VirtualChildrenForNative {
viewTag: number;
Expand Down Expand Up @@ -176,29 +177,12 @@ export function InterceptingGestureDetector<THandlerData, TConfig>({
[virtualChildren, gesture?.detectorCallbacks]
);

const reanimatedUpdateEvents = useMemo(
() => getHandlers('onReanimatedUpdateEvent'),
const reanimatedEvents = useMemo(
() => getHandlers('reanimatedEventHandler'),
[getHandlers]
);
const reanimatedEventHandler = Reanimated?.useComposedEventHandler(
reanimatedUpdateEvents
);

const reanimatedStateChangeEvents = useMemo(
() => getHandlers('onReanimatedStateChange'),
[getHandlers]
);
const reanimatedStateChangeHandler = Reanimated?.useComposedEventHandler(
reanimatedStateChangeEvents
);

const reanimatedTouchEvents = useMemo(
() => getHandlers('onReanimatedTouchEvent'),
[getHandlers]
);
const reanimatedTouchEventHandler = Reanimated?.useComposedEventHandler(
reanimatedTouchEvents
);
const reanimatedEventHandler =
Reanimated?.useComposedEventHandler(reanimatedEvents);

ensureNativeDetectorComponent(NativeDetectorComponent);

Expand All @@ -213,40 +197,59 @@ export function InterceptingGestureDetector<THandlerData, TConfig>({
return [];
}, [gesture]);

// On web, we're triggering Reanimated callbacks ourselves, based on the type.
// To handle this properly, we need to provide all three callbacks, so we set
// all three to the Reanimated event handler.
// On native, Reanimated handles routing internally based on the event names
// passed to the useEvent hook. We only need to pass it once, so that Reanimated
// can setup its internal listeners.
const reanimatedHandlers =
Platform.OS === 'web'
? {
onGestureHandlerReanimatedEvent: reanimatedEventHandler,
onGestureHandlerReanimatedStateChange: reanimatedEventHandler,
onGestureHandlerReanimatedTouchEvent: reanimatedEventHandler,
}
: {
onGestureHandlerReanimatedEvent: reanimatedEventHandler,
};

const jsEventHandler = useMemo(
() => createGestureEventHandler('jsEventHandler'),
[createGestureEventHandler]
);

return (
<InterceptingDetectorContext value={contextValue}>
<NativeDetectorComponent
pointerEvents={'box-none'}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerStateChange={useMemo(
() => createGestureEventHandler('onGestureHandlerStateChange'),
[createGestureEventHandler]
)}
onGestureHandlerStateChange={jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerEvent={jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerEvent={useMemo(
() => createGestureEventHandler('onGestureHandlerEvent'),
[createGestureEventHandler]
)}
onGestureHandlerTouchEvent={jsEventHandler}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerAnimatedEvent={
gesture?.detectorCallbacks.onGestureHandlerAnimatedEvent
gesture?.detectorCallbacks.animatedEventHandler
}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerTouchEvent={useMemo(
() => createGestureEventHandler('onGestureHandlerTouchEvent'),
[createGestureEventHandler]
)}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedStateChange={
shouldUseReanimatedDetector ? reanimatedStateChangeHandler : undefined
shouldUseReanimatedDetector
? reanimatedHandlers.onGestureHandlerReanimatedStateChange
: undefined
}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedEvent={
shouldUseReanimatedDetector ? reanimatedEventHandler : undefined
shouldUseReanimatedDetector
? reanimatedHandlers.onGestureHandlerReanimatedEvent
: undefined
Comment on lines +244 to +246
Copy link
Contributor

Choose a reason for hiding this comment

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

So this is the only callback used by the native side, right?

}
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
onGestureHandlerReanimatedTouchEvent={
shouldUseReanimatedDetector ? reanimatedTouchEventHandler : undefined
shouldUseReanimatedDetector
? reanimatedHandlers.onGestureHandlerReanimatedTouchEvent
: undefined
}
handlerTags={handlerTags}
style={nativeDetectorStyles.detector}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import {
StateChangeEventWithHandlerData,
UpdateEventWithHandlerData,
TouchEvent,
ComposedGesture,
ComposedGestureName,
AnyGesture,
ComposedGestureConfig,
GestureHandlerEventWithHandlerData,
} from '../../types';
import { tagMessage } from '../../../utils';
import { Reanimated } from '../../../handlers/gestures/reanimatedWrapper';
Expand Down Expand Up @@ -45,63 +43,31 @@ export function useComposedGesture(
);
}

const onGestureHandlerStateChange = (
event: StateChangeEventWithHandlerData<unknown>
const jsEventHandler = (
event: GestureHandlerEventWithHandlerData<unknown>
) => {
for (const gesture of gestures) {
if (gesture.detectorCallbacks.onGestureHandlerStateChange) {
gesture.detectorCallbacks.onGestureHandlerStateChange(event);
if (gesture.detectorCallbacks.jsEventHandler) {
gesture.detectorCallbacks.jsEventHandler(event);
}
}
};

const onGestureHandlerEvent = (
event: UpdateEventWithHandlerData<unknown>
) => {
for (const gesture of gestures) {
if (gesture.detectorCallbacks.onGestureHandlerEvent) {
gesture.detectorCallbacks.onGestureHandlerEvent(event);
}
}
};

const onGestureHandlerTouchEvent = (event: TouchEvent) => {
for (const gesture of gestures) {
if (gesture.detectorCallbacks.onGestureHandlerTouchEvent) {
gesture.detectorCallbacks.onGestureHandlerTouchEvent(event);
}
}
};

const onReanimatedStateChange = Reanimated?.useComposedEventHandler(
gestures.map(
(gesture) => gesture.detectorCallbacks.onReanimatedStateChange || null
)
);

const onReanimatedUpdateEvent = Reanimated?.useComposedEventHandler(
gestures.map(
(gesture) => gesture.detectorCallbacks.onReanimatedUpdateEvent || null
)
);

const onReanimatedTouchEvent = Reanimated?.useComposedEventHandler(
const reanimatedEventHandler = Reanimated?.useComposedEventHandler(
gestures.map(
(gesture) => gesture.detectorCallbacks.onReanimatedTouchEvent || null
(gesture) => gesture.detectorCallbacks.reanimatedEventHandler || null
)
);

let onGestureHandlerAnimatedEvent;
let animatedEventHandler;

const gesturesWithAnimatedEvent = gestures.filter(
(gesture) =>
gesture.detectorCallbacks.onGestureHandlerAnimatedEvent !== undefined
(gesture) => gesture.detectorCallbacks.animatedEventHandler !== undefined
);

if (gesturesWithAnimatedEvent.length > 0) {
onGestureHandlerAnimatedEvent =
gesturesWithAnimatedEvent[0].detectorCallbacks
.onGestureHandlerAnimatedEvent;
animatedEventHandler =
gesturesWithAnimatedEvent[0].detectorCallbacks.animatedEventHandler;

if (__DEV__ && gesturesWithAnimatedEvent.length > 1) {
console.warn(
Expand All @@ -117,13 +83,9 @@ export function useComposedGesture(
type,
config,
detectorCallbacks: {
onGestureHandlerStateChange,
onGestureHandlerEvent,
onGestureHandlerTouchEvent,
onReanimatedStateChange,
onReanimatedUpdateEvent,
onReanimatedTouchEvent,
onGestureHandlerAnimatedEvent,
jsEventHandler,
reanimatedEventHandler,
animatedEventHandler,
},
externalSimultaneousHandlers: [],
gestures,
Expand Down
40 changes: 9 additions & 31 deletions packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
registerGesture,
unregisterGesture,
} from '../../handlers/handlersRegistry';
import { Platform } from 'react-native';
import { NativeProxy } from '../NativeProxy';

export function useGesture<THandlerData, TConfig>(
Expand All @@ -37,13 +36,10 @@ export function useGesture<THandlerData, TConfig>(
prepareConfig(config);

// TODO: Call only necessary hooks depending on which callbacks are defined (?)
const {
onGestureHandlerEvent,
onReanimatedEvent,
onGestureHandlerAnimatedEvent,
} = useGestureCallbacks(tag, config);
const { jsEventHandler, reanimatedEventHandler, animatedEventHandler } =
useGestureCallbacks(tag, config);

if (config.shouldUseReanimatedDetector && !onReanimatedEvent) {
if (config.shouldUseReanimatedDetector && !reanimatedEventHandler) {
throw new Error(tagMessage('Failed to create reanimated event handlers.'));
}

Expand Down Expand Up @@ -75,37 +71,19 @@ export function useGesture<THandlerData, TConfig>(
type,
config,
detectorCallbacks: {
onGestureHandlerStateChange: onGestureHandlerEvent,
onGestureHandlerEvent: onGestureHandlerEvent,
onGestureHandlerTouchEvent: onGestureHandlerEvent,
onGestureHandlerAnimatedEvent,
// On web, we're triggering Reanimated callbacks ourselves, based on the type.
// To handle this properly, we need to provide all three callbacks, so we set
// all three to the Reanimated event handler.
// On native, Reanimated handles routing internally based on the event names
// passed to the useEvent hook. We only need to pass it once, so that Reanimated
// can setup its internal listeners.
...(Platform.OS === 'web'
? {
onReanimatedUpdateEvent: onReanimatedEvent,
onReanimatedStateChange: onReanimatedEvent,
onReanimatedTouchEvent: onReanimatedEvent,
}
: {
onReanimatedUpdateEvent: onReanimatedEvent,
onReanimatedStateChange: undefined,
onReanimatedTouchEvent: undefined,
}),
jsEventHandler,
animatedEventHandler,
reanimatedEventHandler,
},
gestureRelations,
}),
[
tag,
type,
config,
onGestureHandlerEvent,
onReanimatedEvent,
onGestureHandlerAnimatedEvent,
jsEventHandler,
reanimatedEventHandler,
animatedEventHandler,
gestureRelations,
]
);
Expand Down
Loading
Loading