This commit is contained in:
Eric Bailey
2025-06-22 17:19:14 -05:00
parent 996e550c0a
commit 2b23499a15
6 changed files with 83 additions and 55 deletions
+3 -3
View File
@@ -33,6 +33,7 @@ import {
ensureGeolocationResolved,
Provider as GeolocationProvider,
} from '#/state/geolocation'
import {GlobalGestureEventsProvider} from '#/state/global-gesture-events'
import {Provider as HomeBadgeProvider} from '#/state/home-badge'
import {Provider as InvitesStateProvider} from '#/state/invites'
import {Provider as LightboxStateProvider} from '#/state/lightbox'
@@ -73,7 +74,6 @@ import {Splash} from '#/Splash'
import {BottomSheetProvider} from '../modules/bottom-sheet'
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottomBarBorder'
import {GlobalGestureEvents} from '#/state/shell/GlobalGestureEvents'
SplashScreen.preventAutoHideAsync()
if (isIOS) {
@@ -155,13 +155,13 @@ function InnerApp() {
<HideBottomBarBorderProvider>
<GestureHandlerRootView
style={s.h100pct}>
<GlobalGestureEvents>
<GlobalGestureEventsProvider>
<IntentDialogProvider>
<TestCtrls />
<Shell />
<NuxDialogs />
</IntentDialogProvider>
</GlobalGestureEvents>
</GlobalGestureEventsProvider>
</GestureHandlerRootView>
</HideBottomBarBorderProvider>
</ServiceAccountManager>
+13 -13
View File
@@ -1,17 +1,17 @@
import {
createContext,
useCallback,
useContext,
useMemo,
useRef,
createContext,
useContext,
useState,
} from 'react'
import {View, Dimensions} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {Dimensions, View} from 'react-native'
import {Portal} from '#/components/Portal'
import {atoms as a, useTheme} from '#/alf'
import {useOnInteract} from '#/state/shell/GlobalGestureEvents'
import {useOnGesture} from '#/components/hooks/useOnGesture'
// import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {Portal} from '#/components/Portal'
import {TIP_SIZE} from '#/components/Tooltip/const'
type TooltipContextType = {
@@ -160,7 +160,7 @@ function Bubble({
>
}) {
const t = useTheme()
const insets = useSafeAreaInsets()
// const insets = useSafeAreaInsets()
const [bubbleMeasurements, setBubbleMeasurements] = useState<
| {
width: number
@@ -180,9 +180,9 @@ function Bubble({
}
const win = Dimensions.get('window')
const {width: ww, height: wh} = win
const maxTop = insets.top
const maxBottom = wh - insets.bottom
const {width: ww, height: _wh} = win
// const maxTop = insets.top
// const maxBottom = wh - insets.bottom
const {width: cw, height: ch} = bubbleMeasurements
const minLeft = a.px_xl.paddingLeft
const maxLeft = ww - minLeft
@@ -211,14 +211,14 @@ function Bubble({
tipTop,
tipLeft,
}
}, [targetMeasurements, bubbleMeasurements, insets])
}, [targetMeasurements, bubbleMeasurements])
const requestCloseWrapped = useCallback(() => {
setBubbleMeasurements(undefined)
requestClose()
}, [requestClose])
useOnInteract(
useOnGesture(
useCallback(
e => {
const {x, y} = e
@@ -243,7 +243,7 @@ function Bubble({
a.align_start,
{
width: 200,
opacity: !!bubbleMeasurements ? 1 : 0,
opacity: bubbleMeasurements ? 1 : 0,
top: coords.top,
left: coords.left,
},
@@ -0,0 +1,24 @@
import {useEffect} from 'react'
import {
type GlobalGestureEvents,
useGlobalGestureEvents,
} from '#/state/global-gesture-events'
/**
* Listen for global gesture events. Callback should be wrapped with
* `useCallback` or otherwise memoized to avoid unnecessary re-renders.
*/
export function useOnGesture(
onGestureCallback: (e: GlobalGestureEvents['begin']) => void,
) {
const ctx = useGlobalGestureEvents()
useEffect(() => {
ctx.register()
ctx.events.on('begin', onGestureCallback)
return () => {
ctx.unregister()
ctx.events.off('begin', onGestureCallback)
}
}, [ctx, onGestureCallback])
}
@@ -0,0 +1 @@
export function useOnGesture() {}
@@ -1,49 +1,56 @@
import {createContext, useContext, useMemo, useEffect, useRef, useState} from 'react'
import EventEmitter from 'eventemitter3'
import {createContext, useContext, useMemo, useRef, useState} from 'react'
import {
GestureDetector,
Gesture,
GestureStateChangeEvent,
GestureUpdateEvent,
PanGestureHandlerEventPayload,
GestureDetector,
type GestureStateChangeEvent,
type GestureUpdateEvent,
type PanGestureHandlerEventPayload,
} from 'react-native-gesture-handler'
import EventEmitter from 'eventemitter3'
const events = new EventEmitter<{
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 GlobalGestureEvents({
export function GlobalGestureEventsProvider({
children,
}: {
children: React.ReactNode
}): React.ReactElement {
}) {
const refCount = useRef(0)
const events = useMemo(() => new EventEmitter<GlobalGestureEvents>(), [])
const [enabled, setEnabled] = useState(false)
const ctx = useMemo(() => ({
register() {
refCount.current += 1
if (refCount.current === 1) {
setEnabled(true)
}
},
unregister() {
refCount.current -= 1
if (refCount.current === 0) {
setEnabled(false)
}
},
}), [setEnabled])
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)
@@ -68,19 +75,6 @@ export function GlobalGestureEvents({
)
}
export function useOnInteract(
onInteract: (
e: GestureStateChangeEvent<PanGestureHandlerEventPayload>,
) => void,
) {
const ctx = useContext(Context)
useEffect(() => {
ctx.register()
events.on('begin', onInteract)
return () => {
ctx.unregister()
events.off('begin', onInteract)
}
}, [ctx, onInteract])
export function useGlobalGestureEvents() {
return useContext(Context)
}
@@ -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.')
}