refactor: enhance mobile swipe gesture handling and improve outlet behavior on compact routes
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
import React from 'react';
|
||||
import { Outlet, useLocation } from 'react-router-dom';
|
||||
import { useCompactNav } from '../hooks/useCompactNav';
|
||||
import { useCompactNav, useIsCompactListRoute } from '../hooks/useCompactNav';
|
||||
import { MobileSwipeGestureHost } from './mobile/MobileSwipeGestureHost';
|
||||
|
||||
/**
|
||||
* Wrapper for Outlet that adds route-based animation
|
||||
* Forces remount on route change by using location as key
|
||||
* Outlet wrapper for route remounts + compact swipe-back chrome.
|
||||
*
|
||||
* On compact list routes the parent PageRoot already omits children. If this
|
||||
* outlet is still mounted (stale stack / empty SpaceIndexRedirect), render
|
||||
* nothing so an empty swipe shell cannot sit above the channel list and eat taps.
|
||||
*/
|
||||
export function AnimatedOutlet() {
|
||||
const location = useLocation();
|
||||
const compact = useCompactNav();
|
||||
const isListRoute = useIsCompactListRoute();
|
||||
|
||||
if (compact && isListRoute) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MobileSwipeGestureHost>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { ReactNode, useCallback, useEffect, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useCompactNav } from '../../hooks/useCompactNav';
|
||||
import { useBackRoute } from '../../hooks/useBackRoute';
|
||||
import { startReplyToEvent } from '../../features/room/replyToMessage';
|
||||
@@ -93,6 +94,7 @@ const resetElementTransform = (el: HTMLElement | null) => {
|
||||
|
||||
export function MobileSwipeGestureHost({ children }: MobileSwipeGestureHostProps) {
|
||||
const compact = useCompactNav();
|
||||
const { pathname } = useLocation();
|
||||
const { canGoBack, goBack } = useBackRoute();
|
||||
const backEnabled = compact && canGoBack;
|
||||
const replyEnabled = compact;
|
||||
@@ -350,7 +352,7 @@ export function MobileSwipeGestureHost({ children }: MobileSwipeGestureHostProps
|
||||
|
||||
useEffect(() => {
|
||||
resetGesture();
|
||||
}, [canGoBack, resetGesture]);
|
||||
}, [canGoBack, pathname, resetGesture]);
|
||||
|
||||
if (!compact) {
|
||||
return <>{children}</>;
|
||||
|
||||
@@ -36,7 +36,10 @@ export const CompactNavUnderlay = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
zIndex: 0,
|
||||
pointerEvents: 'none',
|
||||
// Keep underlay tappable if the detail layer is empty/transparent
|
||||
// (e.g. space index after leaving DMs). Opaque detail content still
|
||||
// sits above and receives taps first.
|
||||
pointerEvents: 'auto',
|
||||
});
|
||||
|
||||
export const CompactDetailLayer = style({
|
||||
@@ -45,6 +48,20 @@ export const CompactDetailLayer = style({
|
||||
minWidth: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
// Pass through taps when outlet content is null/empty; real pages
|
||||
// re-enable pointer events on their root via the child selector.
|
||||
pointerEvents: 'none',
|
||||
selectors: {
|
||||
'& > *': {
|
||||
pointerEvents: 'auto',
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: color.Background.Container,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const SwipeToReplyLayer = style({
|
||||
|
||||
@@ -18,6 +18,9 @@ export function PageRoot({ nav, children }: PageRootProps) {
|
||||
const showCompactMaster = useShowCompactMasterView();
|
||||
const compact = screenSize === ScreenSize.Mobile;
|
||||
|
||||
// Master list routes: only the channel/space list is interactive.
|
||||
// Never mount the detail/underlay stack here — an empty detail layer would
|
||||
// sit above the list with pointer-events and freeze taps (DM → space bug).
|
||||
if (compact && showCompactMaster) {
|
||||
return (
|
||||
<Box grow="Yes" className={ContainerColor({ variant: 'Background' })}>
|
||||
|
||||
Reference in New Issue
Block a user