diff --git a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts index ee7a951c57..2da89dee03 100644 --- a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts +++ b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts @@ -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); } }, }; diff --git a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx index 249da97d7e..a866b96752 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx @@ -8,6 +8,7 @@ import { nativeDetectorStyles, } from './common'; import { ReanimatedNativeDetector } from './ReanimatedNativeDetector'; +import { Platform } from 'react-native'; export function NativeDetector({ gesture, @@ -29,6 +30,27 @@ export function NativeDetector({ 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 ( ({ 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} diff --git a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx index 8b4fe6ad25..ba99ef5e67 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx @@ -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; @@ -176,29 +177,12 @@ export function InterceptingGestureDetector({ [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); @@ -213,40 +197,59 @@ export function InterceptingGestureDetector({ 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 ( 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 } // @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} diff --git a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts index ad2280808d..189dbf40e5 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts @@ -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'; @@ -45,63 +43,31 @@ export function useComposedGesture( ); } - const onGestureHandlerStateChange = ( - event: StateChangeEventWithHandlerData + const jsEventHandler = ( + event: GestureHandlerEventWithHandlerData ) => { 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 - ) => { - 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( @@ -117,13 +83,9 @@ export function useComposedGesture( type, config, detectorCallbacks: { - onGestureHandlerStateChange, - onGestureHandlerEvent, - onGestureHandlerTouchEvent, - onReanimatedStateChange, - onReanimatedUpdateEvent, - onReanimatedTouchEvent, - onGestureHandlerAnimatedEvent, + jsEventHandler, + reanimatedEventHandler, + animatedEventHandler, }, externalSimultaneousHandlers: [], gestures, diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts index 98b49879a8..196c2d2777 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts @@ -15,7 +15,6 @@ import { registerGesture, unregisterGesture, } from '../../handlers/handlersRegistry'; -import { Platform } from 'react-native'; import { NativeProxy } from '../NativeProxy'; export function useGesture( @@ -37,13 +36,10 @@ export function useGesture( 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.')); } @@ -75,27 +71,9 @@ export function useGesture( 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, }), @@ -103,9 +81,9 @@ export function useGesture( tag, type, config, - onGestureHandlerEvent, - onReanimatedEvent, - onGestureHandlerAnimatedEvent, + jsEventHandler, + reanimatedEventHandler, + animatedEventHandler, gestureRelations, ] ); diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts index 4704b83999..1f1bb70804 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts @@ -42,19 +42,15 @@ export function useGestureCallbacks( ) { const callbacks = useMemoizedGestureCallbacks(config); - const onGestureHandlerEvent = useGestureEventHandler( - handlerTag, - callbacks, - config - ); + const jsEventHandler = useGestureEventHandler(handlerTag, callbacks, config); - let onReanimatedEvent; + let reanimatedEventHandler; if (!config.disableReanimated) { // eslint-disable-next-line react-hooks/rules-of-hooks const reanimatedHandler = Reanimated?.useHandler(callbacks); // eslint-disable-next-line react-hooks/rules-of-hooks - onReanimatedEvent = useReanimatedEventHandler( + reanimatedEventHandler = useReanimatedEventHandler( handlerTag, callbacks, reanimatedHandler, @@ -62,7 +58,7 @@ export function useGestureCallbacks( ); } - let onGestureHandlerAnimatedEvent: + let animatedEventHandler: | ((event: GestureUpdateEventWithHandlerData) => void) | AnimatedEvent | undefined; @@ -73,16 +69,16 @@ export function useGestureCallbacks( if (__DEV__ && !isNativeAnimatedEvent(config.onUpdate)) { // @ts-expect-error At this point we know it's not a native animated event, so it's callable - onGestureHandlerAnimatedEvent = guardJSAnimatedEvent(config.onUpdate); + animatedEventHandler = guardJSAnimatedEvent(config.onUpdate); } else { // @ts-expect-error The structure of an AnimatedEvent differs from other event types - onGestureHandlerAnimatedEvent = config.onUpdate; + animatedEventHandler = config.onUpdate; } } return { - onGestureHandlerEvent, - onReanimatedEvent, - onGestureHandlerAnimatedEvent, + jsEventHandler, + reanimatedEventHandler, + animatedEventHandler, }; } diff --git a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts index 5b4da179af..dca181be8d 100644 --- a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts +++ b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts @@ -1,27 +1,17 @@ import { AnimatedEvent, - StateChangeEventWithHandlerData, - UpdateEventWithHandlerData, - TouchEvent, GestureUpdateEventWithHandlerData, + GestureHandlerEventWithHandlerData, } from './EventTypes'; export type DetectorCallbacks = { - onGestureHandlerStateChange: ( - event: StateChangeEventWithHandlerData - ) => void; - onGestureHandlerEvent: + jsEventHandler: | undefined - | ((event: UpdateEventWithHandlerData) => void); - onGestureHandlerTouchEvent: (event: TouchEvent) => void; - onReanimatedStateChange: + | ((event: GestureHandlerEventWithHandlerData) => void); + reanimatedEventHandler: | undefined - | ((event: StateChangeEventWithHandlerData) => void); - onReanimatedUpdateEvent: - | undefined - | ((event: UpdateEventWithHandlerData) => void); - onReanimatedTouchEvent: undefined | ((event: TouchEvent) => void); - onGestureHandlerAnimatedEvent: + | ((event: GestureHandlerEventWithHandlerData) => void); + animatedEventHandler: | undefined | AnimatedEvent | ((event: GestureUpdateEventWithHandlerData) => void);