Fix right-swipe still triggering browser back navigation

Non-passive touchmove listener with preventDefault() blocks Chromium's
  compositor-level back/forward swipe gesture. Once horizontal movement
  is detected, the gesture is locked and all further touchmove events
  are prevented for that swipe. Removed touch-action: pan-y which was
  insufficient on its own.
This commit is contained in:
maziggy
2026-03-26 10:50:10 +01:00
parent f6d760bb3e
commit bebfc01167
3 changed files with 78 additions and 56 deletions
@@ -142,15 +142,20 @@ export function SpoolBuddyLayout() {
// Swipe left/right to cycle through online printers
const touchStartRef = useRef<{ x: number; y: number } | null>(null);
const swipeLockedRef = useRef(false);
const SWIPE_THRESHOLD = 50;
const rootRef = useRef<HTMLDivElement>(null);
const handleTouchStart = useCallback((e: React.TouchEvent) => {
touchStartRef.current = { x: e.touches[0].clientX, y: e.touches[0].clientY };
swipeLockedRef.current = false;
}, []);
const handleTouchEnd = useCallback((e: React.TouchEvent) => {
if (!touchStartRef.current || onlinePrinters.length < 2) return;
const dx = e.changedTouches[0].clientX - touchStartRef.current.x;
const dy = e.changedTouches[0].clientY - touchStartRef.current.y;
touchStartRef.current = null;
swipeLockedRef.current = false;
if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dy) > Math.abs(dx)) return;
const currentIdx = onlinePrinters.findIndex((p: Printer) => p.id === selectedPrinterId);
const nextIdx = dx < 0
@@ -159,6 +164,22 @@ export function SpoolBuddyLayout() {
setSelectedPrinterId(onlinePrinters[nextIdx].id);
}, [onlinePrinters, selectedPrinterId, setSelectedPrinterId]);
// Block browser back/forward swipe gesture with non-passive touchmove listener
useEffect(() => {
const el = rootRef.current;
if (!el) return;
const onTouchMove = (e: TouchEvent) => {
if (!touchStartRef.current) return;
const dx = Math.abs(e.touches[0].clientX - touchStartRef.current.x);
const dy = Math.abs(e.touches[0].clientY - touchStartRef.current.y);
// Once locked as horizontal, prevent default for the rest of this gesture
if (swipeLockedRef.current) { e.preventDefault(); return; }
if (dx > 10 && dx > dy) { swipeLockedRef.current = true; e.preventDefault(); }
};
el.addEventListener('touchmove', onTouchMove, { passive: false });
return () => el.removeEventListener('touchmove', onTouchMove);
}, []);
// CSS brightness filter (software dimming)
const brightnessStyle = displayBrightness < 100
? { filter: `brightness(${displayBrightness / 100})` } as const
@@ -167,8 +188,9 @@ export function SpoolBuddyLayout() {
return (
<>
<div
ref={rootRef}
className="w-screen h-screen bg-bambu-dark text-white flex flex-col overflow-hidden"
style={{ ...brightnessStyle, overscrollBehaviorX: 'none', touchAction: 'pan-y' }}
style={{ ...brightnessStyle, overscrollBehaviorX: 'none' }}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
>
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -23,7 +23,7 @@
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-DIWh1_Mq.js"></script>
<script type="module" crossorigin src="/assets/index-B2-uBp6-.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CZLTApPU.css">
</head>
<body>