From 9604655fdf3c4768d72f46aaf9372f743d444257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= Date: Mon, 25 May 2026 15:48:29 +0200 Subject: [PATCH 1/3] Correctly attach v3 handlers --- .../src/web/handlers/GestureHandler.ts | 17 +++++++++++------ .../src/web/handlers/IGestureHandler.ts | 2 ++ .../web/handlers/NativeViewGestureHandler.ts | 4 ++-- .../src/web/tools/GestureHandlerWebDelegate.ts | 5 ++++- 4 files changed, 19 insertions(+), 9 deletions(-) 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 7cf242452b..9e5023a3e4 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import { ActionType, usesNativeOrVirtualDetector } from '../../ActionType'; +import { ActionType } from '../../ActionType'; import type { ActiveCursor, GestureTouchEvent, @@ -98,6 +98,13 @@ export default abstract class GestureHandler implements IGestureHandler { this.delegate.init(viewRef, this); } + public usesNativeOrVirtualDetector(): boolean { + return ( + this.actionType === ActionType.NATIVE_DETECTOR || + this.actionType === ActionType.VIRTUAL_DETECTOR + ); + } + public detach() { if (this.state === State.ACTIVE) { this.cancel(); @@ -413,7 +420,7 @@ export default abstract class GestureHandler implements IGestureHandler { return; } - if (!usesNativeOrVirtualDetector(this.actionType)) { + if (!this.usesNativeOrVirtualDetector()) { onGestureHandlerEvent?.(touchEvent); return; } @@ -440,9 +447,7 @@ export default abstract class GestureHandler implements IGestureHandler { const isStateChange = this.lastSentState !== newState; - const resultEvent: ResultEvent = !usesNativeOrVirtualDetector( - this.actionType - ) + const resultEvent: ResultEvent = !this.usesNativeOrVirtualDetector() ? this.transformEventData(newState, oldState) : isStateChange ? this.transformStateChangeEvent(newState, oldState) @@ -467,7 +472,7 @@ export default abstract class GestureHandler implements IGestureHandler { } // Cover only V3 path due to different event shape - if (!isStateChange && usesNativeOrVirtualDetector(this.actionType)) { + if (!isStateChange && this.usesNativeOrVirtualDetector()) { const handlerData = ( resultEvent.nativeEvent as GestureUpdateEventWithHandlerData ).handlerData; diff --git a/packages/react-native-gesture-handler/src/web/handlers/IGestureHandler.ts b/packages/react-native-gesture-handler/src/web/handlers/IGestureHandler.ts index 806c815816..47b3a0e93f 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/IGestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/IGestureHandler.ts @@ -33,6 +33,8 @@ export default interface IGestureHandler { readonly touchAction?: TouchAction | undefined; readonly userSelect?: UserSelect | undefined; + usesNativeOrVirtualDetector: () => boolean; + attachEventManager: (manager: EventManager) => void; isButtonInConfig: ( diff --git a/packages/react-native-gesture-handler/src/web/handlers/NativeViewGestureHandler.ts b/packages/react-native-gesture-handler/src/web/handlers/NativeViewGestureHandler.ts index aa535d6408..ba507ade1b 100644 --- a/packages/react-native-gesture-handler/src/web/handlers/NativeViewGestureHandler.ts +++ b/packages/react-native-gesture-handler/src/web/handlers/NativeViewGestureHandler.ts @@ -1,6 +1,6 @@ import { Platform } from 'react-native'; -import { type ActionType, usesNativeOrVirtualDetector } from '../../ActionType'; +import { type ActionType } from '../../ActionType'; import { State } from '../../State'; import { deepEqual } from '../../utils'; import type { NativeHandlerData } from '../../v3/hooks/gestures/native/NativeTypes'; @@ -59,7 +59,7 @@ export default class NativeViewGestureHandler extends GestureHandler { this.restoreViewStyles(view); - if (usesNativeOrVirtualDetector(this.actionType)) { + if (this.usesNativeOrVirtualDetector()) { this.role = (view.getAttribute( NATIVE_GESTURE_ROLE_ATTRIBUTE diff --git a/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts b/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts index 50e45e0b18..c35d10cc9b 100644 --- a/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts +++ b/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts @@ -43,7 +43,10 @@ export class GestureHandlerWebDelegate } this.gestureHandler = handler; - this.view = findNodeHandle(viewRef) as unknown as HTMLElement; + + this.view = handler.usesNativeOrVirtualDetector() + ? (viewRef as unknown as HTMLElement) + : (findNodeHandle(viewRef) as unknown as HTMLElement); this.defaultViewStyles = { userSelect: this.view.style.userSelect, From 512c9fb2ef55d18d04c9696a8b806628ae63f293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= Date: Mon, 25 May 2026 16:20:06 +0200 Subject: [PATCH 2/3] Remove usesNativeOrVirtualDetector from ActionType --- packages/react-native-gesture-handler/src/ActionType.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/react-native-gesture-handler/src/ActionType.ts b/packages/react-native-gesture-handler/src/ActionType.ts index 10391e17bf..07071aa2dd 100644 --- a/packages/react-native-gesture-handler/src/ActionType.ts +++ b/packages/react-native-gesture-handler/src/ActionType.ts @@ -9,12 +9,3 @@ export const ActionType = { // eslint-disable-next-line @typescript-eslint/no-redeclare -- backward compatibility; it can be used as a type and as a value export type ActionType = (typeof ActionType)[keyof typeof ActionType]; - -export function usesNativeOrVirtualDetector( - actionType: ActionType | null -): boolean { - return ( - actionType === ActionType.NATIVE_DETECTOR || - actionType === ActionType.VIRTUAL_DETECTOR - ); -} From df381f591bbf87c741d29c8ba47187e8c4ca7b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= Date: Tue, 26 May 2026 09:44:40 +0200 Subject: [PATCH 3/3] Fix SVG --- .../src/web/tools/GestureHandlerWebDelegate.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts b/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts index c35d10cc9b..001c869962 100644 --- a/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts +++ b/packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts @@ -4,7 +4,12 @@ import { State } from '../../State'; import { tagMessage } from '../../utils'; import { SingleGestureName } from '../../v3/types'; import type IGestureHandler from '../handlers/IGestureHandler'; -import { getEffectiveBoundingRect, isPointerInBounds } from '../utils'; +import type { SVGRef } from '../interfaces'; +import { + getEffectiveBoundingRect, + isPointerInBounds, + isRNSVGElement, +} from '../utils'; import type EventManager from './EventManager'; import type { GestureHandlerDelegate, @@ -44,9 +49,11 @@ export class GestureHandlerWebDelegate this.gestureHandler = handler; - this.view = handler.usesNativeOrVirtualDetector() - ? (viewRef as unknown as HTMLElement) - : (findNodeHandle(viewRef) as unknown as HTMLElement); + this.view = + handler.usesNativeOrVirtualDetector() && + !isRNSVGElement(viewRef as unknown as SVGRef) + ? (viewRef as unknown as HTMLElement) + : (findNodeHandle(viewRef) as unknown as HTMLElement); this.defaultViewStyles = { userSelect: this.view.style.userSelect,