Skip to content

Commit 6599d06

Browse files
authored
[Web] Adapt NativeViewGestureHandler to NativeDetector (#3653)
## Description Following #3638 this PR brings support for `NativeViewGestureHandler` into `NativeDetector` for web. It does so, by attaching handler into child instead of detector. ## Test plan Tested on the following code ```ts import * as React from 'react'; import { StyleSheet, Text, View, ScrollView, Button } from 'react-native'; import { GestureHandlerRootView, NativeDetector, useGesture, } from 'react-native-gesture-handler'; export default function App() { const items = Array.from({ length: 5 }, (_, index) => `Item ${index + 1}`); const [enabled, setEnabled] = React.useState(true); const gesture = useGesture('NativeViewGestureHandler', { onBegin: (e) => { console.log('onBegin', e); }, onStart: (e) => { console.log('onStart', e); } }); const SV1 = () => ( <ScrollView style={styles.scrollView1}> {items.map((item, index) => ( <View key={index} style={styles.item}> <Text style={styles.text}>{item}</Text> </View> ))} </ScrollView> ); const SV2 = () => ( <ScrollView style={styles.scrollView2}> {items.map((item, index) => ( <View key={index} style={styles.item}> <Text style={styles.text}>{item}</Text> </View> ))} </ScrollView> ); return ( <GestureHandlerRootView style={{ flex: 1, backgroundColor: 'white', paddingTop: 8 }}> <Button title="Swap the child" onPress={() => { setEnabled(!enabled); }} /> <NativeDetector gesture={gesture}> {enabled ? <SV1 /> : <SV2 />} </NativeDetector > </GestureHandlerRootView > ); } const styles = StyleSheet.create({ scrollView1: { backgroundColor: 'pink', marginHorizontal: 20, }, scrollView2: { backgroundColor: 'lightblue', marginHorizontal: 20, }, item: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', padding: 20, margin: 2, backgroundColor: 'white', borderRadius: 10, }, text: { fontSize: 20, color: 'black', }, }); ```
1 parent 02e1317 commit 6599d06

File tree

4 files changed

+47
-11
lines changed

4 files changed

+47
-11
lines changed

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

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { useEffect, useRef } from 'react';
2-
import { View } from 'react-native';
1+
import { Ref, useEffect, useRef } from 'react';
32
import RNGestureHandlerModule from '../RNGestureHandlerModule.web';
43
import { ActionType } from '../ActionType';
54
import { PropsRef } from '../web/interfaces';
5+
import { View } from 'react-native';
6+
import { tagMessage } from '../utils';
67

78
export interface GestureHandlerDetectorProps extends PropsRef {
89
handlerTags: number[];
@@ -13,13 +14,16 @@ export interface GestureHandlerDetectorProps extends PropsRef {
1314
const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
1415
const { handlerTags, children } = props;
1516

16-
const viewRef = useRef(null);
17+
const viewRef = useRef<Element>(null);
1718
const propsRef = useRef<PropsRef>(props);
1819
const attachedHandlerTags = useRef<Set<number>>(new Set<number>());
20+
const attachedNativeHandlerTags = useRef<Set<number>>(new Set<number>());
1921

2022
const detachHandlers = (oldHandlerTags: Set<number>) => {
2123
oldHandlerTags.forEach((tag) => {
2224
RNGestureHandlerModule.detachGestureHandler(tag);
25+
attachedNativeHandlerTags.current.delete(tag);
26+
attachedHandlerTags.current.delete(tag);
2327
});
2428
};
2529

@@ -33,19 +37,42 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
3337
detachHandlers(oldHandlerTags);
3438

3539
newHandlerTags.forEach((tag) => {
36-
RNGestureHandlerModule.attachGestureHandler(
37-
tag,
38-
viewRef.current,
39-
ActionType.NATIVE_DETECTOR,
40-
propsRef
41-
);
40+
if (
41+
RNGestureHandlerModule.getGestureHandlerNode(
42+
tag
43+
).shouldAttachGestureToChildView()
44+
) {
45+
if (!viewRef.current?.firstChild) {
46+
throw new Error(
47+
tagMessage('Detector expected to have a child element')
48+
);
49+
}
50+
RNGestureHandlerModule.attachGestureHandler(
51+
tag,
52+
viewRef.current.firstChild,
53+
ActionType.NATIVE_DETECTOR,
54+
propsRef
55+
);
56+
attachedNativeHandlerTags.current.add(tag);
57+
} else {
58+
RNGestureHandlerModule.attachGestureHandler(
59+
tag,
60+
viewRef.current,
61+
ActionType.NATIVE_DETECTOR,
62+
propsRef
63+
);
64+
}
4265
});
4366
attachedHandlerTags.current = currentHandlerTags;
4467
};
4568

69+
useEffect(() => {
70+
detachHandlers(attachedNativeHandlerTags.current);
71+
}, [children]);
72+
4673
useEffect(() => {
4774
attachHandlers(new Set(handlerTags));
48-
}, [handlerTags]);
75+
}, [handlerTags, children]);
4976

5077
useEffect(() => {
5178
return () => {
@@ -54,7 +81,7 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
5481
}, []);
5582

5683
return (
57-
<View style={{ display: 'contents' }} ref={viewRef}>
84+
<View style={{ display: 'contents' }} ref={viewRef as Ref<View>}>
5885
{children}
5986
</View>
6087
);

packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ export default abstract class GestureHandler implements IGestureHandler {
275275
);
276276
}
277277

278+
public shouldAttachGestureToChildView(): boolean {
279+
return false;
280+
}
281+
278282
//
279283
// Event actions
280284
//

packages/react-native-gesture-handler/src/web/handlers/IGestureHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default interface IGestureHandler {
4141
shouldRequireToWaitForFailure: (handler: IGestureHandler) => boolean;
4242
shouldRecognizeSimultaneously: (handler: IGestureHandler) => boolean;
4343
shouldBeCancelledByOther: (handler: IGestureHandler) => boolean;
44+
shouldAttachGestureToChildView: () => boolean;
4445

4546
sendEvent: (newState: State, oldState: State) => void;
4647

packages/react-native-gesture-handler/src/web/handlers/NativeViewGestureHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ export default class NativeViewGestureHandler extends GestureHandler {
170170
return !this.disallowInterruption;
171171
}
172172

173+
public override shouldAttachGestureToChildView(): boolean {
174+
return true;
175+
}
176+
173177
public disallowsInterruption(): boolean {
174178
return this.disallowInterruption;
175179
}

0 commit comments

Comments
 (0)