react-native-gesture-handler 3.0.0-beta.4 → 3.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +12 -4
- package/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt +6 -2
- package/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt +21 -0
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +113 -49
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +75 -98
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +7 -10
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.kt +64 -2
- package/apple/RNGestureHandler.mm +50 -27
- package/apple/RNGestureHandlerButton.h +4 -2
- package/apple/RNGestureHandlerButton.mm +106 -27
- package/apple/RNGestureHandlerButtonComponentView.mm +17 -2
- package/apple/RNGestureHandlerDetector.mm +99 -75
- package/apple/RNGestureHandlerModule.mm +11 -14
- package/apple/RNGestureHandlerRegistry.h +14 -0
- package/apple/RNGestureHandlerRegistry.m +56 -0
- package/lib/module/RNGestureHandlerModule.web.js +5 -1
- package/lib/module/RNGestureHandlerModule.web.js.map +1 -1
- package/lib/module/components/GestureButtons.js +16 -5
- package/lib/module/components/GestureButtons.js.map +1 -1
- package/lib/module/components/GestureHandlerButton.js.map +1 -1
- package/lib/module/components/GestureHandlerButton.web.js +63 -23
- package/lib/module/components/GestureHandlerButton.web.js.map +1 -1
- package/lib/module/components/Pressable/Pressable.js +1 -0
- package/lib/module/components/Pressable/Pressable.js.map +1 -1
- package/lib/module/components/ReanimatedDrawerLayout.js.map +1 -1
- package/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js +38 -5
- package/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js.map +1 -1
- package/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js +1 -2
- package/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js.map +1 -1
- package/lib/module/handlers/gestures/GestureDetector/utils.js +0 -47
- package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
- package/lib/module/handlers/gestures/reanimatedWrapper.js +14 -2
- package/lib/module/handlers/gestures/reanimatedWrapper.js.map +1 -1
- package/lib/module/mocks/module.js +3 -2
- package/lib/module/mocks/module.js.map +1 -1
- package/lib/module/specs/NativeRNGestureHandlerModule.js.map +1 -1
- package/lib/module/specs/RNGestureHandlerButtonNativeComponent.ts +28 -13
- package/lib/module/v3/NativeProxy.js +5 -3
- package/lib/module/v3/NativeProxy.js.map +1 -1
- package/lib/module/v3/NativeProxy.web.js +2 -2
- package/lib/module/v3/NativeProxy.web.js.map +1 -1
- package/lib/module/v3/components/GestureButtons.js +8 -3
- package/lib/module/v3/components/GestureButtons.js.map +1 -1
- package/lib/module/v3/components/Touchable/Touchable.js +53 -4
- package/lib/module/v3/components/Touchable/Touchable.js.map +1 -1
- package/lib/module/v3/detectors/HostGestureDetector.web.js +178 -59
- package/lib/module/v3/detectors/HostGestureDetector.web.js.map +1 -1
- package/lib/module/v3/detectors/NativeDetector.js +3 -2
- package/lib/module/v3/detectors/NativeDetector.js.map +1 -1
- package/lib/module/v3/detectors/VirtualDetector/InterceptingGestureDetector.js +3 -4
- package/lib/module/v3/detectors/VirtualDetector/InterceptingGestureDetector.js.map +1 -1
- package/lib/module/v3/detectors/VirtualDetector/VirtualDetector.js +2 -2
- package/lib/module/v3/detectors/VirtualDetector/VirtualDetector.js.map +1 -1
- package/lib/module/v3/detectors/useGestureRelationsUpdater.js +23 -0
- package/lib/module/v3/detectors/useGestureRelationsUpdater.js.map +1 -0
- package/lib/module/v3/detectors/utils.js +10 -8
- package/lib/module/v3/detectors/utils.js.map +1 -1
- package/lib/module/v3/hooks/useGesture.js +3 -18
- package/lib/module/v3/hooks/useGesture.js.map +1 -1
- package/lib/module/v3/hooks/utils/configUtils.js +1 -3
- package/lib/module/v3/hooks/utils/configUtils.js.map +1 -1
- package/lib/module/v3/hooks/utils/eventHandlersUtils.js +31 -29
- package/lib/module/v3/hooks/utils/eventHandlersUtils.js.map +1 -1
- package/lib/module/v3/hooks/utils/reanimatedUtils.js +8 -2
- package/lib/module/v3/hooks/utils/reanimatedUtils.js.map +1 -1
- package/lib/module/web/tools/NodeManager.js +44 -0
- package/lib/module/web/tools/NodeManager.js.map +1 -1
- package/lib/typescript/RNGestureHandlerModule.web.d.ts +1 -1
- package/lib/typescript/RNGestureHandlerModule.web.d.ts.map +1 -1
- package/lib/typescript/components/GestureButtons.d.ts +14 -6
- package/lib/typescript/components/GestureButtons.d.ts.map +1 -1
- package/lib/typescript/components/GestureHandlerButton.d.ts +62 -8
- package/lib/typescript/components/GestureHandlerButton.d.ts.map +1 -1
- package/lib/typescript/components/GestureHandlerButton.web.d.ts +10 -3
- package/lib/typescript/components/GestureHandlerButton.web.d.ts.map +1 -1
- package/lib/typescript/components/Pressable/Pressable.d.ts.map +1 -1
- package/lib/typescript/components/Pressable/PressableProps.d.ts +1 -1
- package/lib/typescript/components/Pressable/PressableProps.d.ts.map +1 -1
- package/lib/typescript/components/ReanimatedDrawerLayout.d.ts +16 -14
- package/lib/typescript/components/ReanimatedDrawerLayout.d.ts.map +1 -1
- package/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeable.d.ts +2 -1
- package/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeable.d.ts.map +1 -1
- package/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts +30 -34
- package/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/GestureDetector/useDetectorUpdater.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/GestureDetector/utils.d.ts +0 -1
- package/lib/typescript/handlers/gestures/GestureDetector/utils.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/reanimatedWrapper.d.ts.map +1 -1
- package/lib/typescript/mocks/module.d.ts +1 -1
- package/lib/typescript/mocks/module.d.ts.map +1 -1
- package/lib/typescript/specs/NativeRNGestureHandlerModule.d.ts +2 -2
- package/lib/typescript/specs/NativeRNGestureHandlerModule.d.ts.map +1 -1
- package/lib/typescript/specs/RNGestureHandlerButtonNativeComponent.d.ts +19 -11
- package/lib/typescript/specs/RNGestureHandlerButtonNativeComponent.d.ts.map +1 -1
- package/lib/typescript/v3/NativeProxy.d.ts +1 -1
- package/lib/typescript/v3/NativeProxy.d.ts.map +1 -1
- package/lib/typescript/v3/NativeProxy.web.d.ts +1 -1
- package/lib/typescript/v3/NativeProxy.web.d.ts.map +1 -1
- package/lib/typescript/v3/components/GestureButtons.d.ts +1 -38
- package/lib/typescript/v3/components/GestureButtons.d.ts.map +1 -1
- package/lib/typescript/v3/components/GestureButtonsProps.d.ts +1 -1
- package/lib/typescript/v3/components/GestureButtonsProps.d.ts.map +1 -1
- package/lib/typescript/v3/components/Touchable/Touchable.d.ts.map +1 -1
- package/lib/typescript/v3/components/Touchable/TouchableProps.d.ts +39 -1
- package/lib/typescript/v3/components/Touchable/TouchableProps.d.ts.map +1 -1
- package/lib/typescript/v3/detectors/HostGestureDetector.web.d.ts.map +1 -1
- package/lib/typescript/v3/detectors/NativeDetector.d.ts.map +1 -1
- package/lib/typescript/v3/detectors/VirtualDetector/InterceptingGestureDetector.d.ts.map +1 -1
- package/lib/typescript/v3/detectors/useGestureRelationsUpdater.d.ts +3 -0
- package/lib/typescript/v3/detectors/useGestureRelationsUpdater.d.ts.map +1 -0
- package/lib/typescript/v3/detectors/utils.d.ts +3 -3
- package/lib/typescript/v3/detectors/utils.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/useGesture.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/configUtils.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/eventHandlersUtils.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/reanimatedUtils.d.ts +1 -0
- package/lib/typescript/v3/hooks/utils/reanimatedUtils.d.ts.map +1 -1
- package/lib/typescript/web/tools/NodeManager.d.ts +7 -0
- package/lib/typescript/web/tools/NodeManager.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/RNGestureHandlerModule.web.ts +5 -1
- package/src/components/GestureButtons.tsx +23 -7
- package/src/components/GestureHandlerButton.tsx +70 -8
- package/src/components/GestureHandlerButton.web.tsx +97 -29
- package/src/components/Pressable/Pressable.tsx +1 -0
- package/src/components/Pressable/PressableProps.tsx +2 -1
- package/src/components/ReanimatedDrawerLayout.tsx +27 -23
- package/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx +51 -5
- package/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts +31 -39
- package/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts +1 -2
- package/src/handlers/gestures/GestureDetector/utils.ts +0 -52
- package/src/handlers/gestures/reanimatedWrapper.ts +20 -2
- package/src/mocks/module.tsx +4 -2
- package/src/specs/NativeRNGestureHandlerModule.ts +2 -4
- package/src/specs/RNGestureHandlerButtonNativeComponent.ts +28 -13
- package/src/v3/NativeProxy.ts +9 -7
- package/src/v3/NativeProxy.web.ts +2 -2
- package/src/v3/components/GestureButtons.tsx +13 -5
- package/src/v3/components/GestureButtonsProps.ts +1 -0
- package/src/v3/components/Touchable/Touchable.tsx +65 -4
- package/src/v3/components/Touchable/TouchableProps.ts +49 -1
- package/src/v3/detectors/HostGestureDetector.web.tsx +265 -108
- package/src/v3/detectors/NativeDetector.tsx +3 -2
- package/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +3 -4
- package/src/v3/detectors/VirtualDetector/VirtualDetector.tsx +2 -2
- package/src/v3/detectors/useGestureRelationsUpdater.ts +30 -0
- package/src/v3/detectors/utils.ts +28 -12
- package/src/v3/hooks/useGesture.ts +4 -14
- package/src/v3/hooks/utils/configUtils.ts +2 -3
- package/src/v3/hooks/utils/eventHandlersUtils.ts +43 -32
- package/src/v3/hooks/utils/reanimatedUtils.ts +10 -10
- package/src/web/tools/NodeManager.ts +57 -0
- package/lib/module/RNRenderer.js +0 -6
- package/lib/module/RNRenderer.js.map +0 -1
- package/lib/module/RNRenderer.web.js +0 -6
- package/lib/module/RNRenderer.web.js.map +0 -1
- package/lib/typescript/RNRenderer.d.ts +0 -2
- package/lib/typescript/RNRenderer.d.ts.map +0 -1
- package/lib/typescript/RNRenderer.web.d.ts +0 -4
- package/lib/typescript/RNRenderer.web.d.ts.map +0 -1
- package/src/RNRenderer.ts +0 -3
- package/src/RNRenderer.web.ts +0 -3
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
import RNGestureHandlerModule from '../../RNGestureHandlerModule.web';
|
|
11
11
|
import { tagMessage } from '../../utils';
|
|
12
12
|
import { type PropsRef } from '../../web/interfaces';
|
|
13
|
+
import NodeManager from '../../web/tools/NodeManager';
|
|
13
14
|
import { useNativeGestureRole } from './useNativeGestureRole';
|
|
14
15
|
|
|
15
16
|
export interface GestureHandlerDetectorProps extends PropsRef {
|
|
@@ -31,7 +32,193 @@ export interface VirtualChildrenWeb {
|
|
|
31
32
|
enableContextMenu?: boolean | undefined;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
// Bundles all per-instance state passed to the standalone helpers below. Holding everything in
|
|
36
|
+
// one stable object keeps the helpers pure (no closures over component-render-scoped values),
|
|
37
|
+
// which means the useEffects don't need them in their deps lists.
|
|
38
|
+
type DetectorRefs = {
|
|
39
|
+
owner: object;
|
|
40
|
+
viewRef: RefObject<Element | null>;
|
|
41
|
+
propsRef: RefObject<GestureHandlerDetectorProps>;
|
|
42
|
+
// Tags observed for the detector view (top-level).
|
|
43
|
+
subscribedHandlers: Set<number>;
|
|
44
|
+
// Flat set of tags currently bound to *some* element (top-level or virtual). Mirrors iOS
|
|
45
|
+
// `_attachedHandlers` / Android `attachedHandlers`.
|
|
46
|
+
attachedHandlers: Set<number>;
|
|
47
|
+
// Tags whose handler asked to attach to the detector's child element rather than the detector
|
|
48
|
+
// itself (`shouldAttachGestureToChildView`). Kept here so we can (re)bind them as subviews
|
|
49
|
+
// appear.
|
|
50
|
+
nativeHandlers: Set<number>;
|
|
51
|
+
// For each virtual child's viewTag, the set of currently-observed handler tags.
|
|
52
|
+
subscribedVirtualHandlers: Map<number, Set<number>>;
|
|
53
|
+
// Latest snapshot of virtual children keyed by viewTag. The ready callback reads this so
|
|
54
|
+
// re-fires after a child's per-DOM props change use the up-to-date values.
|
|
55
|
+
virtualChildren: Map<number, VirtualChildrenWeb>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Invoked from `NodeManager.observeHandler` once the handler is known to exist. Branches on
|
|
59
|
+
// handler kind + actionType to pick the right binding flow. May be called multiple times for
|
|
60
|
+
// the same tag (handler re-registration), so each branch must be idempotent.
|
|
61
|
+
function attachReadyHandler(
|
|
62
|
+
refs: DetectorRefs,
|
|
63
|
+
tag: number,
|
|
64
|
+
actionType: ActionType,
|
|
65
|
+
virtualViewTag?: number
|
|
66
|
+
) {
|
|
67
|
+
const handler = RNGestureHandlerModule.getGestureHandlerNode(tag);
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
actionType === ActionType.NATIVE_DETECTOR &&
|
|
71
|
+
handler.shouldAttachGestureToChildView()
|
|
72
|
+
) {
|
|
73
|
+
refs.nativeHandlers.add(tag);
|
|
74
|
+
if (
|
|
75
|
+
refs.viewRef.current != null &&
|
|
76
|
+
refs.viewRef.current.childElementCount > 0
|
|
77
|
+
) {
|
|
78
|
+
tryAttachNativeHandlersToChildView(refs);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (actionType === ActionType.VIRTUAL_DETECTOR) {
|
|
84
|
+
const child =
|
|
85
|
+
virtualViewTag != null
|
|
86
|
+
? refs.virtualChildren.get(virtualViewTag)
|
|
87
|
+
: undefined;
|
|
88
|
+
if (child == null || child.viewRef.current == null) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!refs.attachedHandlers.has(tag)) {
|
|
93
|
+
RNGestureHandlerModule.attachGestureHandler(
|
|
94
|
+
tag,
|
|
95
|
+
child.viewRef.current,
|
|
96
|
+
actionType,
|
|
97
|
+
refs.propsRef
|
|
98
|
+
);
|
|
99
|
+
refs.attachedHandlers.add(tag);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
103
|
+
userSelect: child.userSelect,
|
|
104
|
+
touchAction: child.touchAction,
|
|
105
|
+
enableContextMenu: child.enableContextMenu,
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (refs.viewRef.current == null) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!refs.attachedHandlers.has(tag)) {
|
|
115
|
+
RNGestureHandlerModule.attachGestureHandler(
|
|
116
|
+
tag,
|
|
117
|
+
refs.viewRef.current,
|
|
118
|
+
actionType,
|
|
119
|
+
refs.propsRef
|
|
120
|
+
);
|
|
121
|
+
refs.attachedHandlers.add(tag);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
125
|
+
userSelect: refs.propsRef.current.userSelect,
|
|
126
|
+
touchAction: refs.propsRef.current.touchAction,
|
|
127
|
+
enableContextMenu: refs.propsRef.current.enableContextMenu,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function tryAttachNativeHandlersToChildView(refs: DetectorRefs) {
|
|
132
|
+
if (refs.nativeHandlers.size === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const view = refs.viewRef.current;
|
|
137
|
+
if (view == null) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (view.childElementCount > 1) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
tagMessage(
|
|
144
|
+
'Cannot have more than one child view when native gesture handlers are attached to the detector'
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const target = view.firstElementChild;
|
|
150
|
+
if (target == null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
for (const tag of refs.nativeHandlers) {
|
|
155
|
+
// A tag may be in `nativeHandlers` from an earlier ready callback but the underlying
|
|
156
|
+
// handler may have been dropped since. Skip — a re-registration fires the observation again.
|
|
157
|
+
if (!NodeManager.hasHandler(tag)) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (refs.attachedHandlers.has(tag)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
RNGestureHandlerModule.attachGestureHandler(
|
|
164
|
+
tag,
|
|
165
|
+
target,
|
|
166
|
+
ActionType.NATIVE_DETECTOR,
|
|
167
|
+
refs.propsRef
|
|
168
|
+
);
|
|
169
|
+
refs.attachedHandlers.add(tag);
|
|
170
|
+
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
171
|
+
userSelect: refs.propsRef.current.userSelect,
|
|
172
|
+
touchAction: refs.propsRef.current.touchAction,
|
|
173
|
+
enableContextMenu: refs.propsRef.current.enableContextMenu,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Reconcile `subscribedSet` against `currentTags`: observe new tags, cancel observation and
|
|
179
|
+
// detach for tags no longer present. The ready callback set up here is responsible for actually
|
|
180
|
+
// binding the handler once it exists.
|
|
181
|
+
function syncSubscriptions(
|
|
182
|
+
refs: DetectorRefs,
|
|
183
|
+
currentTags: Iterable<number>,
|
|
184
|
+
subscribedSet: Set<number>,
|
|
185
|
+
actionType: ActionType,
|
|
186
|
+
virtualViewTag?: number
|
|
187
|
+
) {
|
|
188
|
+
const toUnsubscribe = new Set(subscribedSet);
|
|
189
|
+
for (const tag of currentTags) {
|
|
190
|
+
toUnsubscribe.delete(tag);
|
|
191
|
+
if (subscribedSet.has(tag)) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
NodeManager.observeHandler(tag, refs.owner, () => {
|
|
195
|
+
attachReadyHandler(refs, tag, actionType, virtualViewTag);
|
|
196
|
+
});
|
|
197
|
+
subscribedSet.add(tag);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const tag of toUnsubscribe) {
|
|
201
|
+
NodeManager.cancelObservation(tag, refs.owner);
|
|
202
|
+
if (refs.attachedHandlers.has(tag)) {
|
|
203
|
+
RNGestureHandlerModule.detachGestureHandler(tag);
|
|
204
|
+
refs.attachedHandlers.delete(tag);
|
|
205
|
+
}
|
|
206
|
+
subscribedSet.delete(tag);
|
|
207
|
+
refs.nativeHandlers.delete(tag);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function teardown(refs: DetectorRefs) {
|
|
212
|
+
NodeManager.cancelAllObservationsForOwner(refs.owner);
|
|
213
|
+
for (const tag of refs.attachedHandlers) {
|
|
214
|
+
RNGestureHandlerModule.detachGestureHandler(tag);
|
|
215
|
+
}
|
|
216
|
+
refs.attachedHandlers.clear();
|
|
217
|
+
refs.subscribedHandlers.clear();
|
|
218
|
+
refs.nativeHandlers.clear();
|
|
219
|
+
refs.subscribedVirtualHandlers.clear();
|
|
220
|
+
refs.virtualChildren.clear();
|
|
221
|
+
}
|
|
35
222
|
|
|
36
223
|
const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
|
|
37
224
|
const { handlerTags, children } = props;
|
|
@@ -40,72 +227,28 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
|
|
|
40
227
|
|
|
41
228
|
const viewRef = useRef<Element>(null);
|
|
42
229
|
const propsRef = useRef<GestureHandlerDetectorProps>(props);
|
|
43
|
-
const attachedHandlers = useRef<Set<number>>(new Set<number>());
|
|
44
|
-
const attachedNativeHandlers = useRef<Set<number>>(new Set<number>());
|
|
45
|
-
const attachedVirtualHandlers = useRef<Map<number, Set<number>>>(new Map());
|
|
46
|
-
|
|
47
|
-
const detachHandlers = (
|
|
48
|
-
currentHandlerTags: Set<number>,
|
|
49
|
-
attachedHandlerTags: Set<number>
|
|
50
|
-
) => {
|
|
51
|
-
const oldHandlerTags = attachedHandlerTags.difference(currentHandlerTags);
|
|
52
|
-
oldHandlerTags.forEach((tag) => {
|
|
53
|
-
RNGestureHandlerModule.detachGestureHandler(tag);
|
|
54
|
-
attachedHandlerTags.delete(tag);
|
|
55
|
-
});
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const attachHandlers = (
|
|
59
|
-
viewRef: RefObject<Element | null>,
|
|
60
|
-
propsRef: RefObject<GestureHandlerDetectorProps>,
|
|
61
|
-
currentHandlerTags: Set<number>,
|
|
62
|
-
attachedHandlerTags: Set<number>,
|
|
63
|
-
actionType: ActionType
|
|
64
|
-
) => {
|
|
65
|
-
const newHandlerTags = currentHandlerTags.difference(attachedHandlerTags);
|
|
66
|
-
|
|
67
|
-
newHandlerTags.forEach((tag) => {
|
|
68
|
-
if (
|
|
69
|
-
RNGestureHandlerModule.getGestureHandlerNode(
|
|
70
|
-
tag
|
|
71
|
-
).shouldAttachGestureToChildView() &&
|
|
72
|
-
actionType === ActionType.NATIVE_DETECTOR
|
|
73
|
-
) {
|
|
74
|
-
if (viewRef.current!.childElementCount > 1) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
tagMessage(
|
|
77
|
-
'Cannot have more than one child view when native gesture handlers are attached to the detector'
|
|
78
|
-
)
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
230
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
attachedHandlerTags.add(tag);
|
|
98
|
-
|
|
99
|
-
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
100
|
-
userSelect: props.userSelect,
|
|
101
|
-
touchAction: props.touchAction,
|
|
102
|
-
enableContextMenu: props.enableContextMenu,
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
};
|
|
231
|
+
// Stable per-instance state
|
|
232
|
+
const refsRef = useRef<DetectorRefs | null>(null);
|
|
233
|
+
if (refsRef.current === null) {
|
|
234
|
+
refsRef.current = {
|
|
235
|
+
owner: {},
|
|
236
|
+
viewRef,
|
|
237
|
+
propsRef,
|
|
238
|
+
subscribedHandlers: new Set<number>(),
|
|
239
|
+
attachedHandlers: new Set<number>(),
|
|
240
|
+
nativeHandlers: new Set<number>(),
|
|
241
|
+
subscribedVirtualHandlers: new Map<number, Set<number>>(),
|
|
242
|
+
virtualChildren: new Map<number, VirtualChildrenWeb>(),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const refs = refsRef.current;
|
|
106
246
|
|
|
107
247
|
useNativeGestureRole(viewRef, children);
|
|
108
248
|
|
|
249
|
+
// Keep propsRef in sync and re-apply detector-level DOM props to top-level attached handlers
|
|
250
|
+
// when they change. Virtual children get their own (potentially different) DOM props applied
|
|
251
|
+
// in the virtualChildren effect below, so we only touch top-level subscribers here.
|
|
109
252
|
useEffect(() => {
|
|
110
253
|
const shouldUpdateDOMProps =
|
|
111
254
|
propsRef.current.userSelect !== props.userSelect ||
|
|
@@ -115,7 +258,17 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
|
|
|
115
258
|
propsRef.current = props;
|
|
116
259
|
|
|
117
260
|
if (shouldUpdateDOMProps) {
|
|
118
|
-
|
|
261
|
+
// attachedHandlers ⊆ subscribedHandlers ⋃ subscribedVirtualHandlers, we want to ignore the
|
|
262
|
+
// handlers attached by the virtual detectors not to overwrite their DOM props.
|
|
263
|
+
const claimedByVirtual = Array.from(
|
|
264
|
+
refs.subscribedVirtualHandlers.values()
|
|
265
|
+
).reduce((acc, current) => acc.union(current), new Set<number>());
|
|
266
|
+
|
|
267
|
+
const handlersToUpdate = refs.subscribedHandlers
|
|
268
|
+
.intersection(refs.attachedHandlers)
|
|
269
|
+
.difference(claimedByVirtual);
|
|
270
|
+
|
|
271
|
+
for (const tag of handlersToUpdate) {
|
|
119
272
|
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
120
273
|
userSelect: props.userSelect,
|
|
121
274
|
touchAction: props.touchAction,
|
|
@@ -123,38 +276,38 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
|
|
|
123
276
|
});
|
|
124
277
|
}
|
|
125
278
|
}
|
|
126
|
-
}, [props]);
|
|
279
|
+
}, [props, refs]);
|
|
127
280
|
|
|
128
281
|
useEffect(() => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
attachHandlers(
|
|
132
|
-
viewRef,
|
|
133
|
-
propsRef,
|
|
282
|
+
syncSubscriptions(
|
|
283
|
+
refs,
|
|
134
284
|
handlerTagsSet,
|
|
135
|
-
|
|
285
|
+
refs.subscribedHandlers,
|
|
136
286
|
ActionType.NATIVE_DETECTOR
|
|
137
287
|
);
|
|
138
|
-
|
|
139
|
-
detachHandlers(EMPTY_HANDLERS, attachedHandlers.current);
|
|
140
|
-
attachedVirtualHandlers?.current.forEach((childHandlerTags) => {
|
|
141
|
-
detachHandlers(EMPTY_HANDLERS, childHandlerTags);
|
|
142
|
-
});
|
|
143
|
-
};
|
|
144
|
-
}, [handlerTagsSet, viewRef]);
|
|
288
|
+
}, [handlerTagsSet, refs]);
|
|
145
289
|
|
|
146
290
|
useEffect(() => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
)
|
|
291
|
+
// Refresh the snapshot used by the ready callback so re-fires read current child props.
|
|
292
|
+
refs.virtualChildren.clear();
|
|
293
|
+
props.virtualChildren?.forEach((child) => {
|
|
294
|
+
refs.virtualChildren.set(child.viewTag, child);
|
|
295
|
+
});
|
|
150
296
|
|
|
297
|
+
const virtualChildrenToDetach = new Set(
|
|
298
|
+
refs.subscribedVirtualHandlers.keys()
|
|
299
|
+
);
|
|
151
300
|
props.virtualChildren?.forEach((child) => {
|
|
152
301
|
virtualChildrenToDetach.delete(child.viewTag);
|
|
153
302
|
});
|
|
154
303
|
|
|
155
|
-
virtualChildrenToDetach
|
|
156
|
-
|
|
157
|
-
|
|
304
|
+
for (const viewTag of virtualChildrenToDetach) {
|
|
305
|
+
const tags = refs.subscribedVirtualHandlers.get(viewTag);
|
|
306
|
+
if (tags != null) {
|
|
307
|
+
syncSubscriptions(refs, [], tags, ActionType.VIRTUAL_DETECTOR, viewTag);
|
|
308
|
+
}
|
|
309
|
+
refs.subscribedVirtualHandlers.delete(viewTag);
|
|
310
|
+
}
|
|
158
311
|
|
|
159
312
|
props.virtualChildren?.forEach((child) => {
|
|
160
313
|
if (child.viewRef.current == null) {
|
|
@@ -162,33 +315,37 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => {
|
|
|
162
315
|
// switches its component based on whether animated/reanimated events should run.
|
|
163
316
|
return;
|
|
164
317
|
}
|
|
165
|
-
if (!attachedVirtualHandlers.current.has(child.viewTag)) {
|
|
166
|
-
attachedVirtualHandlers.current.set(child.viewTag, new Set());
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const currentHandlerTags = new Set(child.handlerTags);
|
|
170
|
-
detachHandlers(
|
|
171
|
-
currentHandlerTags,
|
|
172
|
-
attachedVirtualHandlers.current.get(child.viewTag)!
|
|
173
|
-
);
|
|
174
318
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
319
|
+
let subs = refs.subscribedVirtualHandlers.get(child.viewTag);
|
|
320
|
+
if (subs == null) {
|
|
321
|
+
subs = new Set();
|
|
322
|
+
refs.subscribedVirtualHandlers.set(child.viewTag, subs);
|
|
323
|
+
}
|
|
324
|
+
syncSubscriptions(
|
|
325
|
+
refs,
|
|
326
|
+
child.handlerTags,
|
|
327
|
+
subs,
|
|
328
|
+
ActionType.VIRTUAL_DETECTOR,
|
|
329
|
+
child.viewTag
|
|
181
330
|
);
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
331
|
+
// Re-apply per-child DOM props on every run. Already-attached tags need this when only
|
|
332
|
+
// the child's props change; tags attached via a sync-fired observer already had it
|
|
333
|
+
// applied in `attachReadyHandler`, so this is a no-op for them.
|
|
334
|
+
for (const tag of subs) {
|
|
335
|
+
if (refs.attachedHandlers.has(tag)) {
|
|
336
|
+
RNGestureHandlerModule.updateGestureHandlerConfig(tag, {
|
|
337
|
+
userSelect: child.userSelect,
|
|
338
|
+
touchAction: child.touchAction,
|
|
339
|
+
enableContextMenu: child.enableContextMenu,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
190
343
|
});
|
|
191
|
-
}, [props.virtualChildren]);
|
|
344
|
+
}, [props.virtualChildren, refs]);
|
|
345
|
+
|
|
346
|
+
useEffect(() => {
|
|
347
|
+
return () => teardown(refs);
|
|
348
|
+
}, [refs]);
|
|
192
349
|
|
|
193
350
|
return (
|
|
194
351
|
<View style={{ display: 'contents' }} ref={viewRef as Ref<View>}>
|
|
@@ -6,7 +6,8 @@ import type { NativeDetectorProps } from './common';
|
|
|
6
6
|
import { AnimatedNativeDetector, nativeDetectorStyles } from './common';
|
|
7
7
|
import HostGestureDetector from './HostGestureDetector';
|
|
8
8
|
import { ReanimatedNativeDetector } from './ReanimatedNativeDetector';
|
|
9
|
-
import {
|
|
9
|
+
import { useGestureRelationsUpdater } from './useGestureRelationsUpdater';
|
|
10
|
+
import { ensureNativeDetectorComponent } from './utils';
|
|
10
11
|
|
|
11
12
|
export function NativeDetector<
|
|
12
13
|
TConfig,
|
|
@@ -26,7 +27,7 @@ export function NativeDetector<
|
|
|
26
27
|
: HostGestureDetector;
|
|
27
28
|
|
|
28
29
|
ensureNativeDetectorComponent(NativeDetectorComponent);
|
|
29
|
-
|
|
30
|
+
useGestureRelationsUpdater(gesture);
|
|
30
31
|
|
|
31
32
|
const handlerTags = useMemo(() => {
|
|
32
33
|
return isComposedGesture(gesture)
|
|
@@ -18,7 +18,8 @@ import { AnimatedNativeDetector, nativeDetectorStyles } from '../common';
|
|
|
18
18
|
import HostGestureDetector from '../HostGestureDetector';
|
|
19
19
|
import { ReanimatedNativeDetector } from '../ReanimatedNativeDetector';
|
|
20
20
|
import { useEnsureGestureHandlerRootView } from '../useEnsureGestureHandlerRootView';
|
|
21
|
-
import {
|
|
21
|
+
import { useGestureRelationsUpdater } from '../useGestureRelationsUpdater';
|
|
22
|
+
import { ensureNativeDetectorComponent } from '../utils';
|
|
22
23
|
import type { InterceptingDetectorContextValue } from './useInterceptingDetectorContext';
|
|
23
24
|
import {
|
|
24
25
|
InterceptingDetectorContext,
|
|
@@ -221,9 +222,7 @@ export function InterceptingGestureDetector<
|
|
|
221
222
|
|
|
222
223
|
ensureNativeDetectorComponent(NativeDetectorComponent);
|
|
223
224
|
|
|
224
|
-
|
|
225
|
-
configureRelations(gesture);
|
|
226
|
-
}
|
|
225
|
+
useGestureRelationsUpdater(gesture);
|
|
227
226
|
|
|
228
227
|
const handlerTags = useMemo(() => {
|
|
229
228
|
if (gesture) {
|
|
@@ -6,8 +6,8 @@ import { tagMessage } from '../../../utils';
|
|
|
6
6
|
import { isComposedGesture } from '../../hooks/utils/relationUtils';
|
|
7
7
|
import type { DetectorCallbacks, VirtualChild } from '../../types';
|
|
8
8
|
import type { VirtualDetectorProps } from '../common';
|
|
9
|
+
import { useGestureRelationsUpdater } from '../useGestureRelationsUpdater';
|
|
9
10
|
import { useNativeGestureRole } from '../useNativeGestureRole';
|
|
10
|
-
import { configureRelations } from '../utils';
|
|
11
11
|
import {
|
|
12
12
|
InterceptingDetectorMode,
|
|
13
13
|
useInterceptingDetectorContext,
|
|
@@ -104,7 +104,7 @@ export function VirtualDetector<
|
|
|
104
104
|
setMode,
|
|
105
105
|
]);
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
useGestureRelationsUpdater(props.gesture);
|
|
108
108
|
|
|
109
109
|
return <Wrap ref={handleRef}>{props.children}</Wrap>;
|
|
110
110
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { NativeProxy } from '../NativeProxy';
|
|
4
|
+
import type { Gesture } from '../types';
|
|
5
|
+
import { configureRelations } from './utils';
|
|
6
|
+
|
|
7
|
+
export function useGestureRelationsUpdater<TConfig, THandlerData>(
|
|
8
|
+
gesture?: Gesture<TConfig, THandlerData>
|
|
9
|
+
) {
|
|
10
|
+
const relations = useMemo(
|
|
11
|
+
() => (gesture ? configureRelations(gesture) : null),
|
|
12
|
+
[gesture]
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!relations) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// React runs effects bottom-up, we need to ensure that relations are applied after all effects
|
|
21
|
+
// in the tree have run, so we defer to the next frame.
|
|
22
|
+
const frame = requestAnimationFrame(() => {
|
|
23
|
+
relations.forEach((rel, handlerTag) => {
|
|
24
|
+
NativeProxy.configureRelations(handlerTag, rel);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return () => cancelAnimationFrame(frame);
|
|
29
|
+
}, [relations]);
|
|
30
|
+
}
|
|
@@ -9,25 +9,26 @@ import {
|
|
|
9
9
|
isComposedGesture,
|
|
10
10
|
prepareRelations,
|
|
11
11
|
} from '../hooks/utils/relationUtils';
|
|
12
|
-
import {
|
|
13
|
-
import type { Gesture } from '../types';
|
|
12
|
+
import type { Gesture, GestureRelations } from '../types';
|
|
14
13
|
import { ComposedGestureName } from '../types';
|
|
15
14
|
|
|
16
15
|
// The tree consists of ComposedGestures and NativeGestures. NativeGestures are always leaf nodes.
|
|
17
16
|
export const traverseAndConfigureRelations = (
|
|
18
17
|
node: Gesture,
|
|
18
|
+
relationsByTag: Map<number, GestureRelations>,
|
|
19
19
|
simultaneousHandlers: Set<number>,
|
|
20
20
|
waitFor: number[] = []
|
|
21
21
|
) => {
|
|
22
22
|
// If we are in the leaf node, we want to fill gesture relations arrays with current
|
|
23
|
-
// waitFor and simultaneousHandlers. We also want to
|
|
23
|
+
// waitFor and simultaneousHandlers. We also want to record the resulting relations for
|
|
24
|
+
// this handler so the caller can push them to the native side.
|
|
24
25
|
if (!isComposedGesture(node)) {
|
|
25
26
|
node.gestureRelations = prepareRelations(node.config, node.handlerTag);
|
|
26
27
|
|
|
27
28
|
node.gestureRelations.simultaneousHandlers.push(...simultaneousHandlers);
|
|
28
29
|
node.gestureRelations.waitFor.push(...waitFor);
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
relationsByTag.set(node.handlerTag, {
|
|
31
32
|
waitFor: node.gestureRelations.waitFor,
|
|
32
33
|
simultaneousHandlers: node.gestureRelations.simultaneousHandlers,
|
|
33
34
|
blocksHandlers: node.gestureRelations.blocksHandlers,
|
|
@@ -73,7 +74,12 @@ export const traverseAndConfigureRelations = (
|
|
|
73
74
|
const length = waitFor.length;
|
|
74
75
|
|
|
75
76
|
// We traverse the child, passing the current `waitFor` and `simultaneousHandlers`.
|
|
76
|
-
traverseAndConfigureRelations(
|
|
77
|
+
traverseAndConfigureRelations(
|
|
78
|
+
child,
|
|
79
|
+
relationsByTag,
|
|
80
|
+
simultaneousHandlers,
|
|
81
|
+
waitFor
|
|
82
|
+
);
|
|
77
83
|
|
|
78
84
|
// After traversing the child, we need to update `waitFor` and `simultaneousHandlers`
|
|
79
85
|
|
|
@@ -122,7 +128,12 @@ export const traverseAndConfigureRelations = (
|
|
|
122
128
|
// We don't want to mark gesture as simultaneous with itself, so we remove its tag from the set.
|
|
123
129
|
const hasRemovedTag = simultaneousHandlers.delete(child.handlerTag);
|
|
124
130
|
|
|
125
|
-
traverseAndConfigureRelations(
|
|
131
|
+
traverseAndConfigureRelations(
|
|
132
|
+
child,
|
|
133
|
+
relationsByTag,
|
|
134
|
+
simultaneousHandlers,
|
|
135
|
+
waitFor
|
|
136
|
+
);
|
|
126
137
|
|
|
127
138
|
if (hasRemovedTag) {
|
|
128
139
|
simultaneousHandlers.add(child.handlerTag);
|
|
@@ -138,7 +149,9 @@ export const traverseAndConfigureRelations = (
|
|
|
138
149
|
|
|
139
150
|
export function configureRelations<TConfig, THandlerData>(
|
|
140
151
|
gesture: Gesture<TConfig, THandlerData>
|
|
141
|
-
) {
|
|
152
|
+
): Map<number, GestureRelations> {
|
|
153
|
+
const relationsByTag = new Map<number, GestureRelations>();
|
|
154
|
+
|
|
142
155
|
if (isComposedGesture(gesture)) {
|
|
143
156
|
const simultaneousHandlers = new Set<number>(
|
|
144
157
|
gesture.externalSimultaneousHandlers
|
|
@@ -151,13 +164,16 @@ export function configureRelations<TConfig, THandlerData>(
|
|
|
151
164
|
);
|
|
152
165
|
}
|
|
153
166
|
|
|
154
|
-
traverseAndConfigureRelations(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
gesture.gestureRelations
|
|
167
|
+
traverseAndConfigureRelations(
|
|
168
|
+
gesture,
|
|
169
|
+
relationsByTag,
|
|
170
|
+
simultaneousHandlers
|
|
159
171
|
);
|
|
172
|
+
} else {
|
|
173
|
+
relationsByTag.set(gesture.handlerTag, gesture.gestureRelations);
|
|
160
174
|
}
|
|
175
|
+
|
|
176
|
+
return relationsByTag;
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
export function ensureNativeDetectorComponent(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { getNextHandlerTag } from '../../handlers/getNextHandlerTag';
|
|
4
4
|
import {
|
|
@@ -61,15 +61,6 @@ export function useGesture<
|
|
|
61
61
|
[handlerTag, config.simultaneousWith, config.requireToFail, config.block]
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
-
const currentGestureRef = useRef({ type: '', handlerTag: -1 });
|
|
65
|
-
if (
|
|
66
|
-
currentGestureRef.current.handlerTag !== handlerTag ||
|
|
67
|
-
currentGestureRef.current.type !== (type as string)
|
|
68
|
-
) {
|
|
69
|
-
currentGestureRef.current = { type, handlerTag };
|
|
70
|
-
NativeProxy.createGestureHandler(type, handlerTag, {});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
64
|
const gesture = useMemo(
|
|
74
65
|
() => ({
|
|
75
66
|
handlerTag,
|
|
@@ -94,11 +85,10 @@ export function useGesture<
|
|
|
94
85
|
);
|
|
95
86
|
|
|
96
87
|
useEffect(() => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
currentGestureRef.current = { type: '', handlerTag: -1 };
|
|
100
|
-
}
|
|
88
|
+
NativeProxy.createGestureHandler(type, handlerTag, {});
|
|
89
|
+
scheduleFlushOperations();
|
|
101
90
|
|
|
91
|
+
return () => {
|
|
102
92
|
NativeProxy.dropGestureHandler(handlerTag);
|
|
103
93
|
scheduleFlushOperations();
|
|
104
94
|
};
|
|
@@ -87,9 +87,8 @@ export function prepareConfigForNativeSide<
|
|
|
87
87
|
for (const [key, value] of Object.entries(config)) {
|
|
88
88
|
// @ts-ignore That's the point, we want to see if key exists in the whitelists
|
|
89
89
|
if (allowedNativeProps.has(key) || handlerPropsWhiteList.has(key)) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
90
|
+
(filteredConfig as Record<string, unknown>)[key] =
|
|
91
|
+
Reanimated?.isSharedValue(value) ? value.value : value;
|
|
93
92
|
} else if (PropsToFilter.has(key)) {
|
|
94
93
|
continue;
|
|
95
94
|
} else {
|