diff --git a/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts b/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts index a5a3e13c1e..20afc9fbb6 100644 --- a/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts +++ b/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts @@ -1,4 +1,4 @@ -import { StylusData } from '../web/interfaces'; +import { StylusData } from './gestureHandlerCommon'; export type FlingGestureHandlerEventPayload = { x: number; diff --git a/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts b/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts index 7ec04b358d..3d90c3a7f5 100644 --- a/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts +++ b/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts @@ -165,6 +165,14 @@ export type GestureTouchEvent = { pointerType: PointerType; }; +export interface StylusData { + tiltX: number; + tiltY: number; + azimuthAngle: number; + altitudeAngle: number; + pressure: number; +} + export type GestureUpdateEvent> = GestureEventPayload & GestureEventPayloadT; diff --git a/packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts b/packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts index fc45aefadd..5b40c0442a 100644 --- a/packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts +++ b/packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts @@ -13,15 +13,16 @@ import { import { tapGestureHandlerProps } from '../../TapGestureHandler'; import { hoverGestureHandlerProps } from '../hoverGesture'; import { nativeViewGestureHandlerProps } from '../../NativeViewGestureHandler'; -import { - HandlerStateChangeEvent, - baseGestureHandlerWithDetectorProps, -} from '../../gestureHandlerCommon'; +import { baseGestureHandlerWithDetectorProps } from '../../gestureHandlerCommon'; import { RNRenderer } from '../../../RNRenderer'; import { useCallback, useRef, useState } from 'react'; import { Reanimated } from '../reanimatedWrapper'; import { onGestureHandlerEvent } from '../eventReceiver'; -import { PropsRef } from '../../../web/interfaces'; +import { + GestureHandlerNativeEvent, + PropsRef, + ResultEvent, +} from '../../../web/interfaces'; export const ALLOWED_PROPS = [ ...baseGestureHandlerWithDetectorProps, @@ -168,11 +169,11 @@ export function useForceRender() { export function useWebEventHandlers() { return useRef({ - onGestureHandlerEvent: (e: HandlerStateChangeEvent) => { - onGestureHandlerEvent(e.nativeEvent); + onGestureHandlerEvent: (e: ResultEvent) => { + onGestureHandlerEvent(e.nativeEvent as GestureHandlerNativeEvent); }, - onGestureHandlerStateChange: (e: HandlerStateChangeEvent) => { - onGestureHandlerEvent(e.nativeEvent); + onGestureHandlerStateChange: (e: ResultEvent) => { + onGestureHandlerEvent(e.nativeEvent as GestureHandlerNativeEvent); }, }); } diff --git a/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts b/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts index d445940534..7c8dcbcb48 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts @@ -6,9 +6,9 @@ import { PropsRef, ResultEvent, PointerData, - ResultTouchEvent, TouchEventType, EventTypes, + GestureHandlerNativeEvent, } from '../interfaces'; import EventManager from '../tools/EventManager'; import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator'; @@ -20,6 +20,7 @@ import { PointerType } from '../../PointerType'; import { GestureHandlerDelegate } from '../tools/GestureHandlerDelegate'; import { ActionType } from '../../ActionType'; import { tagMessage } from '../../utils'; +import { StateChangeEvent, TouchEvent, UpdateEvent } from '../../v3/types'; export default abstract class GestureHandler implements IGestureHandler { private lastSentState: State | null = null; @@ -369,7 +370,7 @@ export default abstract class GestureHandler implements IGestureHandler { const { onGestureHandlerEvent, onGestureHandlerTouchEvent }: PropsRef = this.propsRef!.current; - const touchEvent: ResultTouchEvent | undefined = + const touchEvent: ResultEvent | undefined = this.transformTouchEvent(event); if (touchEvent) { @@ -395,12 +396,14 @@ export default abstract class GestureHandler implements IGestureHandler { onGestureHandlerStateChange, onGestureHandlerAnimatedEvent, }: PropsRef = this.propsRef!.current; - const resultEvent: ResultEvent = this.transformEventData( - newState, - oldState - ); - - // In the new API oldState field has to be undefined, unless we send event state changed + const resultEvent: ResultEvent = + this.actionType !== ActionType.NATIVE_DETECTOR + ? this.transformEventData(newState, oldState) + : this.lastSentState !== newState + ? this.transformStateChangeEvent(newState, oldState) + : this.transformUpdateEvent(newState); + + // In the v2 API oldState field has to be undefined, unless we send event state changed // Here the order is flipped to avoid workarounds such as making backup of the state and setting it to undefined first, then changing it back // Flipping order with setting oldState to undefined solves issue, when events were being sent twice instead of once // However, this may cause trouble in the future (but for now we don't know that) @@ -410,7 +413,10 @@ export default abstract class GestureHandler implements IGestureHandler { invokeNullableMethod(onGestureHandlerStateChange, resultEvent); } if (this.state === State.ACTIVE) { - resultEvent.nativeEvent.oldState = undefined; + if (this.actionType !== ActionType.NATIVE_DETECTOR) { + (resultEvent.nativeEvent as GestureHandlerNativeEvent).oldState = + undefined; + } if (onGestureHandlerAnimatedEvent && this.forAnimated) { invokeNullableMethod(onGestureHandlerAnimatedEvent, resultEvent); } @@ -418,10 +424,11 @@ export default abstract class GestureHandler implements IGestureHandler { } }; - private transformEventData(newState: State, oldState: State): ResultEvent { - if (!this.viewRef) { - throw new Error(tagMessage('Cannot handle event when target is null')); - } + private transformEventData( + newState: State, + oldState: State + ): ResultEvent { + this.ensureViewRef(this.viewRef); return { nativeEvent: { numberOfPointers: this.tracker.trackedPointersCount, @@ -439,9 +446,55 @@ export default abstract class GestureHandler implements IGestureHandler { }; } + private transformStateChangeEvent( + newState: State, + oldState: State + ): ResultEvent> { + this.ensureViewRef(this.viewRef); + return { + nativeEvent: { + state: newState, + handlerTag: this.handlerTag, + pointerType: this.pointerType, + oldState: oldState, + numberOfPointers: this.tracker.trackedPointersCount, + handlerData: { + pointerInside: this.delegate.isPointerInBounds( + this.tracker.getAbsoluteCoordsAverage() + ), + ...this.transformNativeEvent(), + target: this.viewRef, + }, + }, + timeStamp: Date.now(), + }; + } + + private transformUpdateEvent( + newState: State + ): ResultEvent> { + this.ensureViewRef(this.viewRef); + return { + nativeEvent: { + state: newState, + handlerTag: this.handlerTag, + pointerType: this.pointerType, + numberOfPointers: this.tracker.trackedPointersCount, + handlerData: { + pointerInside: this.delegate.isPointerInBounds( + this.tracker.getAbsoluteCoordsAverage() + ), + ...this.transformNativeEvent(), + target: this.viewRef, + }, + }, + timeStamp: Date.now(), + }; + } + private transformTouchEvent( event: AdaptedEvent - ): ResultTouchEvent | undefined { + ): ResultEvent | undefined { const rect = this.delegate.measureView(); const all: PointerData[] = []; @@ -571,7 +624,7 @@ export default abstract class GestureHandler implements IGestureHandler { }); }); - const cancelEvent: ResultTouchEvent = { + const cancelEvent: ResultEvent = { nativeEvent: { handlerTag: this.handlerTag, state: this.state, @@ -597,6 +650,12 @@ export default abstract class GestureHandler implements IGestureHandler { } } + private ensureViewRef(viewRef: any): asserts viewRef is number { + if (!viewRef) { + throw new Error(tagMessage('Cannot handle event when target is null')); + } + } + protected transformNativeEvent(): Record { // Those properties are shared by most handlers and if not this method will be overriden const lastCoords = this.tracker.getAbsoluteCoordsAverage(); @@ -888,10 +947,10 @@ export default abstract class GestureHandler implements IGestureHandler { function invokeNullableMethod( method: - | ((event: ResultEvent | ResultTouchEvent) => void) - | { __getHandler: () => (event: ResultEvent | ResultTouchEvent) => void } + | ((event: ResultEvent) => void) + | { __getHandler: () => (event: ResultEvent) => void } | { __nodeConfig: { argMapping: unknown[] } }, - event: ResultEvent | ResultTouchEvent + event: ResultEvent ): void { if (!method) { return; @@ -923,7 +982,7 @@ function invokeNullableMethod( } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const nativeValue = event.nativeEvent[key]; + const nativeValue = (event.nativeEvent as any)[key]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (value?.setValue) { diff --git a/packages/react-native-gesture-handler/src/web/handlers/HoverGestureHandler.ts b/packages/react-native-gesture-handler/src/web/handlers/HoverGestureHandler.ts index 61154f1ca5..6d052863bf 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/HoverGestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/HoverGestureHandler.ts @@ -1,7 +1,8 @@ import { State } from '../../State'; -import { AdaptedEvent, StylusData } from '../interfaces'; +import { AdaptedEvent } from '../interfaces'; import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator'; import GestureHandler from './GestureHandler'; +import { StylusData } from '../../handlers/gestureHandlerCommon'; export default class HoverGestureHandler extends GestureHandler { private stylusData: StylusData | undefined; diff --git a/packages/react-native-gesture-handler/src/web/handlers/PanGestureHandler.ts b/packages/react-native-gesture-handler/src/web/handlers/PanGestureHandler.ts index c5d3f577c6..b6fd9aca25 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/PanGestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/PanGestureHandler.ts @@ -1,6 +1,7 @@ import { State } from '../../State'; import { DEFAULT_TOUCH_SLOP } from '../constants'; -import { AdaptedEvent, Config, StylusData, WheelDevice } from '../interfaces'; +import { AdaptedEvent, Config, WheelDevice } from '../interfaces'; +import { StylusData } from '../../handlers/gestureHandlerCommon'; import GestureHandler from './GestureHandler'; diff --git a/packages/react-native-gesture-handler/src/web/interfaces.ts b/packages/react-native-gesture-handler/src/web/interfaces.ts index 39f89f14c5..3ca65ff9a8 100644 --- a/packages/react-native-gesture-handler/src/web/interfaces.ts +++ b/packages/react-native-gesture-handler/src/web/interfaces.ts @@ -3,10 +3,12 @@ import { ActiveCursor, MouseButton, TouchAction, + StylusData, } from '../handlers/gestureHandlerCommon'; import { Directions } from '../Directions'; -import { State } from '../State'; import { PointerType } from '../PointerType'; +import { GestureHandlerEvent } from '../v3/types'; +import { State } from '../State'; export interface HitSlop { left?: number; @@ -83,7 +85,8 @@ export interface Config extends Record { } type NativeEventArgs = number | State | boolean | undefined; -interface NativeEvent extends Record { +export interface GestureHandlerNativeEvent + extends Record { numberOfPointers: number; state: State; pointerInside: boolean | undefined; @@ -106,42 +109,19 @@ export interface PointerData { absoluteY: number; } -type TouchNativeArgs = number | State | TouchEventType | PointerData[]; - -interface NativeTouchEvent extends Record { - handlerTag: number; - state: State; - eventType: TouchEventType; - changedTouches: PointerData[]; - allTouches: PointerData[]; - numberOfTouches: number; - pointerType: PointerType; -} - -export interface ResultEvent extends Record { - nativeEvent: NativeEvent; - timeStamp: number; -} - -export interface ResultTouchEvent - extends Record { - nativeEvent: NativeTouchEvent; +// Native event has to stay for v2 compatibility +type ResultEventType = GestureHandlerEvent | GestureHandlerNativeEvent; +export interface ResultEvent + extends Record { + nativeEvent: T; timeStamp: number; } export interface PropsRef { - onGestureHandlerEvent: (e: any) => void; - onGestureHandlerAnimatedEvent?: (e: any) => void; - onGestureHandlerStateChange: (e: any) => void; - onGestureHandlerTouchEvent?: (e: any) => void; -} - -export interface StylusData { - tiltX: number; - tiltY: number; - azimuthAngle: number; - altitudeAngle: number; - pressure: number; + onGestureHandlerEvent: (e: ResultEvent) => void; + onGestureHandlerAnimatedEvent?: (e: ResultEvent) => void; + onGestureHandlerStateChange: (e: ResultEvent) => void; + onGestureHandlerTouchEvent?: (e: ResultEvent) => void; } export interface AdaptedEvent { diff --git a/packages/react-native-gesture-handler/src/web/utils.ts b/packages/react-native-gesture-handler/src/web/utils.ts index 2825eff75e..366706c834 100644 --- a/packages/react-native-gesture-handler/src/web/utils.ts +++ b/packages/react-native-gesture-handler/src/web/utils.ts @@ -1,10 +1,6 @@ import { PointerType } from '../PointerType'; -import type { - GestureHandlerRef, - Point, - StylusData, - SVGRef, -} from './interfaces'; +import type { GestureHandlerRef, Point, SVGRef } from './interfaces'; +import { StylusData } from '../handlers/gestureHandlerCommon'; export function isPointerInBounds(view: HTMLElement, { x, y }: Point): boolean { const rect: DOMRect = view.getBoundingClientRect();