Skip to content

Commit 46b7b24

Browse files
committed
fix: unvanish element-call, still janky tho
1 parent c553cab commit 46b7b24

4 files changed

Lines changed: 71 additions & 13 deletions

File tree

src/app/components/CallEmbedProvider.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
5555
left: 0,
5656
width: '100%',
5757
height: '50%',
58+
zIndex: 11,
5859
}}
5960
ref={callEmbedRef}
6061
/>

src/app/components/SwipeableChatWrapper.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ export function SwipeableChatWrapper({
2626
const isMobile = useIsMobile();
2727
const x = useMotionValue(0);
2828

29-
// On mobile, MobileRoomOverlay owns the right-swipe gesture so canSwipeRight
30-
// is always false. canSwipeLeft is only active if Members mode is on.
31-
// If neither direction is active, skip binding entirely, an idle useDrag
32-
// with rubberband still captures and rubber-bands touches, stealing clicks.
3329
const canSwipeRight = !isMobile && !!onOpenSidebar;
3430
const canSwipeLeft =
3531
settings.mobileGestures &&

src/app/components/SwipeableMessageWrapper.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,7 @@ function ActiveSwipeWrapper({
8686
rubberband: true,
8787
filterTaps: true,
8888
eventOptions: { passive: true },
89-
// Without this, useDrag calls setPointerCapture on pointerdown, stealing
90-
// the pointer from MobileRoomOverlay on rightward swipes, causing it to
91-
// always see mx=0 and snap back instead of navigating.
89+
// Without this, useDrag calls setPointerCapture on pointerdown, stealing the pointer from MobileRoomOverlay on rightward swipes, causing it to always see mx=0 and snap back instead of navigating.
9290
pointer: { capture: false },
9391
}
9492
);

src/app/pages/MobileRoomOverlay.tsx

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ReactNode, useEffect, useRef } from 'react';
1+
import { ReactNode, useCallback, useEffect, useRef } from 'react';
22
import { animate, motion, useMotionValue } from 'motion/react';
33
import { useDrag } from '@use-gesture/react';
44
import { useAtomValue } from 'jotai';
@@ -13,6 +13,7 @@ const SWIPE_DISTANCE = 80;
1313
const SWIPE_VELOCITY = 0.4;
1414
const SNAP_SPRING = { type: 'spring' as const, stiffness: 600, damping: 50, mass: 0.6 };
1515
const TRANSITION_SPRING = { type: 'spring' as const, stiffness: 380, damping: 36 };
16+
const CAPTURE_THRESHOLD = 8;
1617

1718
export function MobileRoomOverlay({ children }: { children: ReactNode }) {
1819
const settings = useAtomValue(settingsAtom);
@@ -25,10 +26,73 @@ export function MobileRoomOverlay({ children }: { children: ReactNode }) {
2526
animate(x, 0, TRANSITION_SPRING);
2627
}, [x]);
2728

28-
const navigateBack = () => {
29+
// Sync fixed call embed transform with overlay position
30+
useEffect(() => {
31+
const unsub = x.on('change', (val) => {
32+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
33+
const embed = document.querySelector('[data-call-embed-container]') as HTMLElement | null;
34+
if (embed) embed.style.transform = `translateX(${val}px)`;
35+
});
36+
return () => {
37+
unsub();
38+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
39+
const embed = document.querySelector('[data-call-embed-container]') as HTMLElement | null;
40+
if (embed) embed.style.transform = '';
41+
};
42+
}, [x]);
43+
44+
// Disable pointer events on the call embed during rightward swipes so
45+
// useDrag on the overlay can receive the gesture instead of the iframe
46+
useEffect(() => {
47+
if (!settings.mobileGestures) return undefined;
48+
49+
let startX = 0;
50+
let startY = 0;
51+
let disabled = false;
52+
53+
const getEmbed = () => document.querySelector('[data-call-embed-container]');
54+
55+
const onTouchStart = (e: TouchEvent) => {
56+
startX = e.touches[0]?.clientX ?? 0;
57+
startY = e.touches[0]?.clientY ?? 0;
58+
disabled = false;
59+
};
60+
61+
const onTouchMove = (e: TouchEvent) => {
62+
if (disabled) return;
63+
const dx = (e.touches[0]?.clientX ?? 0) - startX;
64+
const dy = (e.touches[0]?.clientY ?? 0) - startY;
65+
// Only disable for clearly rightward, non-vertical gestures
66+
if (dx > CAPTURE_THRESHOLD && Math.abs(dy) < Math.abs(dx) * 1.5) {
67+
const embed = getEmbed();
68+
if (embed) embed.style.pointerEvents = 'none';
69+
disabled = true;
70+
}
71+
};
72+
73+
const onTouchEnd = () => {
74+
if (disabled) {
75+
const embed = getEmbed();
76+
if (embed) embed.style.pointerEvents = '';
77+
disabled = false;
78+
}
79+
};
80+
81+
window.addEventListener('touchstart', onTouchStart, { passive: true });
82+
window.addEventListener('touchmove', onTouchMove, { passive: true });
83+
window.addEventListener('touchend', onTouchEnd, { passive: true });
84+
window.addEventListener('touchcancel', onTouchEnd, { passive: true });
85+
86+
return () => {
87+
window.removeEventListener('touchstart', onTouchStart);
88+
window.removeEventListener('touchmove', onTouchMove);
89+
window.removeEventListener('touchend', onTouchEnd);
90+
window.removeEventListener('touchcancel', onTouchEnd);
91+
};
92+
}, [settings.mobileGestures]);
93+
94+
const navigateBack = useCallback(() => {
2995
log.log('navigateBack — disabling pointer events, starting exit animation');
30-
// Disable hit-testing immediately so the nav beneath becomes interactive
31-
// before the animation completes and the component unmounts.
3296
if (divRef.current) divRef.current.style.pointerEvents = 'none';
3397
animate(x, window.innerWidth, {
3498
...TRANSITION_SPRING,
@@ -37,12 +101,11 @@ export function MobileRoomOverlay({ children }: { children: ReactNode }) {
37101
goBack();
38102
},
39103
});
40-
};
104+
}, [x, goBack]);
41105

42106
const bind = useDrag(
43107
({ active, movement: [mx], velocity: [vx], direction: [dx] }) => {
44108
if (!settings.mobileGestures || !mobileOrTablet()) return;
45-
46109
if (active) {
47110
x.set(Math.max(0, mx));
48111
} else {

0 commit comments

Comments
 (0)