Skip to content

Commit 4285b4f

Browse files
akwasniewskim-bert
andauthored
[web] handle common props in virtual detector (#3982)
## Description Common web-only props `enableContextMenu`, `touchAction`, `userSelect` were not properly handled inside virtual detector. This PR fixes it. ## Test plan Tested on the following example <details> ```tsx import { COLORS, commonStyles, Feedback } from '../common-app/src/common'; import React, { useRef } from 'react'; import { View } from 'react-native'; import { InterceptingGestureDetector, useTapGesture, VirtualGestureDetector, } from 'react-native-gesture-handler'; import Svg, { Circle, Rect } from 'react-native-svg'; export default function LogicDetectorExample() { const feedbackRef = useRef<{ showMessage: (msg: string) => void }>(null); const circleElementTap = useTapGesture({ onActivate: () => { feedbackRef.current?.showMessage('Tapped circle!'); }, disableReanimated: true, }); const rectElementTap = useTapGesture({ onActivate: () => { feedbackRef.current?.showMessage('Tapped parallelogram!'); }, disableReanimated: true, }); const containerTap = useTapGesture({ onActivate: () => { feedbackRef.current?.showMessage('Tapped container!'); }, disableReanimated: true, }); // onPress must be set to enable gesture recognition on svg // eslint-disable-next-line @typescript-eslint/no-empty-function const noop = () => { }; return ( <View style={commonStyles.centerView}> <InterceptingGestureDetector gesture={containerTap}> <Svg height="250" width="250" style={{ backgroundColor: COLORS.PURPLE }}> <VirtualGestureDetector gesture={circleElementTap}> <Circle cx="125" cy="125" r="125" fill={COLORS.NAVY} onPress={noop} /> </VirtualGestureDetector> <VirtualGestureDetector enableContextMenu={true} gesture={rectElementTap}> <Rect skewX="45" width="125" height="250" fill={COLORS.KINDA_BLUE} onPress={noop} /> </VirtualGestureDetector> </Svg> </InterceptingGestureDetector> <Feedback ref={feedbackRef} /> </View> ); } ``` </details> --------- Co-authored-by: Michał Bert <63123542+m-bert@users.noreply.github.com>
1 parent b8c72e2 commit 4285b4f

5 files changed

Lines changed: 54 additions & 15 deletions

File tree

packages/react-native-gesture-handler/src/v3/detectors/HostGestureDetector.web.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export interface VirtualChildrenWeb {
2020
viewTag: number;
2121
handlerTags: number[];
2222
viewRef: RefObject<Element | null>;
23+
userSelect?: UserSelect;
24+
touchAction?: TouchAction;
25+
enableContextMenu?: boolean;
2326
}
2427

2528
const EMPTY_HANDLERS = new Set<number>();
@@ -174,6 +177,14 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
174177
attachedVirtualHandlers.current.get(child.viewTag)!,
175178
ActionType.VIRTUAL_DETECTOR
176179
);
180+
181+
currentHandlerTags.forEach((tag) => {
182+
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
183+
userSelect: child.userSelect,
184+
touchAction: child.touchAction,
185+
enableContextMenu: child.enableContextMenu,
186+
});
187+
});
177188
});
178189
}, [props.virtualChildren]);
179190

packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@ import { tagMessage } from '../../../utils';
2222
import { useEnsureGestureHandlerRootView } from '../useEnsureGestureHandlerRootView';
2323
import { ReanimatedNativeDetector } from '../ReanimatedNativeDetector';
2424
import { Platform } from 'react-native';
25+
import {
26+
TouchAction,
27+
UserSelect,
28+
} from '../../../handlers/gestureHandlerCommon';
2529

26-
interface VirtualChildrenForNative {
30+
interface StrippedVirtualChildren {
2731
viewTag: number;
2832
handlerTags: number[];
29-
viewRef: unknown;
33+
viewRef?: unknown;
34+
userSelect?: UserSelect;
35+
touchAction?: TouchAction;
36+
enableContextMenu?: boolean;
3037
}
3138

3239
export function InterceptingGestureDetector<THandlerData, TConfig>({
@@ -41,13 +48,21 @@ export function InterceptingGestureDetector<THandlerData, TConfig>({
4148
const [virtualChildren, setVirtualChildren] = useState<Set<VirtualChild>>(
4249
() => new Set()
4350
);
44-
const virtualChildrenForNativeComponent: VirtualChildrenForNative[] = useMemo(
51+
const strippedVirtualChildren: StrippedVirtualChildren[] = useMemo(
4552
() =>
46-
Array.from(virtualChildren).map((child) => ({
47-
viewTag: child.viewTag,
48-
handlerTags: child.handlerTags,
49-
viewRef: child.viewRef,
50-
})),
53+
Platform.OS === 'web'
54+
? Array.from(virtualChildren).map((child) => ({
55+
viewTag: child.viewTag,
56+
handlerTags: child.handlerTags,
57+
viewRef: child.viewRef,
58+
userSelect: child.userSelect,
59+
touchAction: child.touchAction,
60+
enableContextMenu: child.enableContextMenu,
61+
}))
62+
: Array.from(virtualChildren).map((child) => ({
63+
viewTag: child.viewTag,
64+
handlerTags: child.handlerTags,
65+
})),
5166
[virtualChildren]
5267
);
5368
const [mode, setMode] = useState<InterceptingDetectorMode>(
@@ -261,7 +276,7 @@ export function InterceptingGestureDetector<THandlerData, TConfig>({
261276
}
262277
handlerTags={handlerTags}
263278
style={nativeDetectorStyles.detector}
264-
virtualChildren={virtualChildrenForNativeComponent}
279+
virtualChildren={strippedVirtualChildren}
265280
moduleId={globalThis._RNGH_MODULE_ID}>
266281
{children}
267282
</NativeDetectorComponent>

packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/VirtualDetector.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,24 @@ export function VirtualDetector<THandlerData, TConfig>(
7676
methods: props.gesture.detectorCallbacks as DetectorCallbacks<unknown>,
7777
// used by HostGestureDetector on web
7878
viewRef: Platform.OS === 'web' ? viewRef : undefined,
79+
userSelect: props.userSelect,
80+
touchAction: props.touchAction,
81+
enableContextMenu: props.enableContextMenu,
7982
};
80-
8183
register(virtualChild);
82-
8384
return () => {
8485
unregister(virtualChild);
8586
};
86-
}, [viewTag, props.gesture, register, unregister, setMode]);
87+
}, [
88+
viewTag,
89+
props.gesture,
90+
props.userSelect,
91+
props.touchAction,
92+
props.enableContextMenu,
93+
register,
94+
unregister,
95+
setMode,
96+
]);
8797

8898
configureRelations(props.gesture);
8999

packages/react-native-gesture-handler/src/v3/detectors/common.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@ export interface InterceptingGestureDetectorProps<THandlerData, TConfig>
2828
gesture?: Gesture<THandlerData, TConfig>;
2929
}
3030

31-
// TODO: Handle CommonGestureDetectorProps inside VirtualGestureDetector
32-
export interface VirtualDetectorProps<THandlerData, TConfig> {
33-
children?: React.ReactNode;
31+
export interface VirtualDetectorProps<THandlerData, TConfig>
32+
extends CommonGestureDetectorProps {
3433
gesture: Gesture<THandlerData, TConfig>;
3534
}
3635

packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
GestureUpdateEventWithHandlerData,
44
GestureHandlerEventWithHandlerData,
55
} from './EventTypes';
6+
import { TouchAction, UserSelect } from '../../handlers/gestureHandlerCommon';
67

78
export type DetectorCallbacks<THandlerData> = {
89
jsEventHandler:
@@ -24,4 +25,7 @@ export type VirtualChild = {
2425

2526
// only set on web
2627
viewRef: unknown;
28+
userSelect?: UserSelect;
29+
touchAction?: TouchAction;
30+
enableContextMenu?: boolean;
2731
};

0 commit comments

Comments
 (0)