about summary refs log tree commit diff
path: root/src/state/global-gesture-events
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2025-06-24 22:03:23 -0500
committerGitHub <noreply@github.com>2025-06-24 22:03:23 -0500
commit4c1515169af81f5eb861e476d2bc07f17c8635fd (patch)
tree37be0de4769da65b3afde1cd1f890afecde14f3b /src/state/global-gesture-events
parentcd820709b611a0381222a34d2bc6ff49fa380452 (diff)
downloadvoidsky-4c1515169af81f5eb861e476d2bc07f17c8635fd.tar.zst
Tooltip (#8555)
* Working overlay, WIP

* Ok working with no overlay and global gesture handler

* Ok pretty good on native

* Cleanup

* Cleanup

* add animation

* add transform origin to animation

* Some a11y

* Improve colors

* Explicitly wrap gesture handler

* Add easier abstraction

* Web

* Fix animation

* Cleanup and remove provider

* Include demo for now

* Ok diff interface to avoid collapsed views

* Use dimensions hook

* Adjust overlap, clarify intent of consts

* Revert testing edits

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'src/state/global-gesture-events')
-rw-r--r--src/state/global-gesture-events/index.tsx83
-rw-r--r--src/state/global-gesture-events/index.web.tsx9
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.')
+}