diff options
Diffstat (limited to 'src/state/global-gesture-events')
-rw-r--r-- | src/state/global-gesture-events/index.tsx | 83 | ||||
-rw-r--r-- | src/state/global-gesture-events/index.web.tsx | 9 |
2 files changed, 92 insertions, 0 deletions
diff --git a/src/state/global-gesture-events/index.tsx b/src/state/global-gesture-events/index.tsx new file mode 100644 index 000000000..f8d87a8f9 --- /dev/null +++ b/src/state/global-gesture-events/index.tsx @@ -0,0 +1,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) +} diff --git a/src/state/global-gesture-events/index.web.tsx b/src/state/global-gesture-events/index.web.tsx new file mode 100644 index 000000000..5d6d53369 --- /dev/null +++ b/src/state/global-gesture-events/index.web.tsx @@ -0,0 +1,9 @@ +export function GlobalGestureEventsProvider(_props: { + children: React.ReactNode +}) { + throw new Error('GlobalGestureEventsProvider is not supported on web.') +} + +export function useGlobalGestureEvents() { + throw new Error('useGlobalGestureEvents is not supported on web.') +} |