1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
import {createContext, useContext, useMemo, useRef, useState} from 'react'
import {View} from 'react-native'
import {
Gesture,
GestureDetector,
type GestureStateChangeEvent,
type GestureUpdateEvent,
type PanGestureHandlerEventPayload,
} from 'react-native-gesture-handler'
import EventEmitter from 'eventemitter3'
export type GlobalGestureEvents = {
begin: GestureStateChangeEvent<PanGestureHandlerEventPayload>
update: GestureUpdateEvent<PanGestureHandlerEventPayload>
end: GestureStateChangeEvent<PanGestureHandlerEventPayload>
finalize: GestureStateChangeEvent<PanGestureHandlerEventPayload>
}
const Context = createContext<{
events: EventEmitter<GlobalGestureEvents>
register: () => void
unregister: () => void
}>({
events: new EventEmitter<GlobalGestureEvents>(),
register: () => {},
unregister: () => {},
})
export function GlobalGestureEventsProvider({
children,
}: {
children: React.ReactNode
}) {
const refCount = useRef(0)
const events = useMemo(() => new EventEmitter<GlobalGestureEvents>(), [])
const [enabled, setEnabled] = useState(false)
const ctx = useMemo(
() => ({
events,
register() {
refCount.current += 1
if (refCount.current === 1) {
setEnabled(true)
}
},
unregister() {
refCount.current -= 1
if (refCount.current === 0) {
setEnabled(false)
}
},
}),
[events, setEnabled],
)
const gesture = Gesture.Pan()
.runOnJS(true)
.enabled(enabled)
.simultaneousWithExternalGesture()
.onBegin(e => {
events.emit('begin', e)
})
.onUpdate(e => {
events.emit('update', e)
})
.onEnd(e => {
events.emit('end', e)
})
.onFinalize(e => {
events.emit('finalize', e)
})
return (
<Context.Provider value={ctx}>
<GestureDetector gesture={gesture}>
<View collapsable={false}>{children}</View>
</GestureDetector>
</Context.Provider>
)
}
export function useGlobalGestureEvents() {
return useContext(Context)
}
|