diff --git a/.changeset/fix-swipe-back-transition.md b/.changeset/fix-swipe-back-transition.md new file mode 100644 index 000000000..ba19f3b00 --- /dev/null +++ b/.changeset/fix-swipe-back-transition.md @@ -0,0 +1,5 @@ +--- +"@stackflow/react-ui-core": patch +--- + +Fix swipe back gesture during push/pop transitions by using capture phase event listeners to prevent touch events from reaching child elements during transitions diff --git a/extensions/react-ui-core/src/usePreventTouchDuringTransition.ts b/extensions/react-ui-core/src/usePreventTouchDuringTransition.ts index 599bd88f4..64947a438 100644 --- a/extensions/react-ui-core/src/usePreventTouchDuringTransition.ts +++ b/extensions/react-ui-core/src/usePreventTouchDuringTransition.ts @@ -18,20 +18,23 @@ export function usePreventTouchDuringTransition({ return; } - const onTouchStart = (e: TouchEvent) => { + const preventTouch = (e: TouchEvent) => { e.preventDefault(); + e.stopPropagation(); }; - const onTouchEnd = (e: TouchEvent) => { - e.preventDefault(); - }; - - $ref.addEventListener("touchstart", onTouchStart); - $ref.addEventListener("touchend", onTouchEnd); + // Use capture phase to prevent all touch events from reaching child elements + // during transitions (including edge swipe area) + $ref.addEventListener("touchstart", preventTouch, { capture: true }); + $ref.addEventListener("touchmove", preventTouch, { capture: true }); + $ref.addEventListener("touchend", preventTouch, { capture: true }); + $ref.addEventListener("touchcancel", preventTouch, { capture: true }); return () => { - $ref.removeEventListener("touchstart", onTouchStart); - $ref.removeEventListener("touchend", onTouchEnd); + $ref.removeEventListener("touchstart", preventTouch, { capture: true }); + $ref.removeEventListener("touchmove", preventTouch, { capture: true }); + $ref.removeEventListener("touchend", preventTouch, { capture: true }); + $ref.removeEventListener("touchcancel", preventTouch, { capture: true }); }; }, [stack?.globalTransitionState]); }