mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 17:52:49 +00:00
* fix(android): restore development builds after Expo upgrade Port the native touch-cancellation patch to the gesture-handler API while retaining drawing order and surviving native gestures. Match the bundled Skia font scanner and Unicode paragraph construction APIs. * test(e2e): hide the developer error toast instead of clicking it away The locator handler that dismissed #error-toast could match a toast that closed before its click; dispatchEvent then waited for the gone button until the test timed out. Hiding the toast with CSS keeps it off app actions with no race. * test(e2e): desktop browser-tabs hides developer toasts on its attached page * test(cli): keep the Hub deploy fixture alive on malformed requests An empty request body crashed the HTTP fixture outside its assertions. Return HTTP 400 for invalid JSON and exercise that request before the full validation and installation assertions.
286 lines
14 KiB
Diff
286 lines
14 KiB
Diff
diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
|
|
index 8d78aea..b84d19e 100644
|
|
--- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
|
|
+++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
|
|
@@ -2,11 +2,13 @@ package com.swmansion.gesturehandler.core
|
|
|
|
import android.graphics.Matrix
|
|
import android.graphics.PointF
|
|
+import android.util.SparseArray
|
|
import android.view.MotionEvent
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.widget.EditText
|
|
import com.facebook.react.uimanager.RootView
|
|
+import com.facebook.react.views.view.ReactViewGroup
|
|
import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper
|
|
import com.swmansion.gesturehandler.react.RNGestureHandlerRootView
|
|
import com.swmansion.gesturehandler.react.isHoverAction
|
|
@@ -28,6 +30,10 @@ class GestureHandlerOrchestrator(
|
|
private val awaitingHandlers = arrayListOf<GestureHandler>()
|
|
private val preparedHandlers = arrayListOf<GestureHandler>()
|
|
|
|
+ // Used by `cancelTouchesInInterceptedViews`.
|
|
+ private val viewsToCancel = arrayListOf<View>()
|
|
+ private val pointerDownPoints = SparseArray<PointF>()
|
|
+
|
|
// In `onHandlerStateChange` method we iterate through `awaitingHandlers`, but calling `tryActivate` may modify this list.
|
|
// To avoid `ConcurrentModificationException` we iterate through copy. There is one more problem though - if handler was
|
|
// removed from `awaitingHandlers`, it was still present in copy of original list. This hashset helps us identify which handlers
|
|
@@ -46,6 +52,7 @@ class GestureHandlerOrchestrator(
|
|
fun onTouchEvent(event: MotionEvent): Boolean {
|
|
isHandlingTouch = true
|
|
val action = event.actionMasked
|
|
+ trackPointerDownPoints(event)
|
|
if (action == MotionEvent.ACTION_DOWN ||
|
|
action == MotionEvent.ACTION_POINTER_DOWN ||
|
|
action == MotionEvent.ACTION_HOVER_MOVE
|
|
@@ -579,6 +586,115 @@ class GestureHandlerOrchestrator(
|
|
private fun shouldIgnoreSubtreeIfGestureHandlerRootView(view: View) =
|
|
view is RNGestureHandlerRootView && view != wrapperView && view.isRootViewEnabled()
|
|
|
|
+ private fun trackPointerDownPoints(event: MotionEvent) {
|
|
+ val index = event.actionIndex
|
|
+ when (event.actionMasked) {
|
|
+ MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN ->
|
|
+ pointerDownPoints.put(event.getPointerId(index), PointF(event.getX(index), event.getY(index)))
|
|
+ MotionEvent.ACTION_POINTER_UP ->
|
|
+ pointerDownPoints.remove(event.getPointerId(index))
|
|
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL ->
|
|
+ pointerDownPoints.clear()
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fun cancelTouchesInInterceptedViews(event: MotionEvent) {
|
|
+ viewsToCancel.clear()
|
|
+ for (i in 0 until pointerDownPoints.size()) {
|
|
+ val point = pointerDownPoints.valueAt(i)
|
|
+ tempCoords[0] = point.x
|
|
+ tempCoords[1] = point.y
|
|
+ collectViewsAtPoint(wrapperView, tempCoords, viewsToCancel)
|
|
+ }
|
|
+
|
|
+ if (viewsToCancel.isEmpty()) {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ val activeHandlers = gestureHandlers.filter { it.isActive }
|
|
+ val cancelEvent = MotionEvent.obtain(event).apply { action = MotionEvent.ACTION_CANCEL }
|
|
+
|
|
+ for (view in viewsToCancel) {
|
|
+ if (view === wrapperView || isViewDrivenByActiveNativeGesture(view, activeHandlers)) {
|
|
+ continue
|
|
+ }
|
|
+ view.onTouchEvent(cancelEvent)
|
|
+ }
|
|
+
|
|
+ cancelEvent.recycle()
|
|
+ viewsToCancel.clear()
|
|
+ }
|
|
+
|
|
+ // Whether the view's touch is still owned by a NativeViewGestureHandler that survived arbitration.
|
|
+ // Only those are fed through `onTouchEvent`, so only those break if cancelled. Other handlers are
|
|
+ // orchestrator-driven and unaffected.
|
|
+ private fun isViewDrivenByActiveNativeGesture(view: View, activeHandlers: List<GestureHandler>) =
|
|
+ handlerRegistry.getHandlersForView(view)?.let { handlers ->
|
|
+ synchronized(handlers) {
|
|
+ handlers.any { nativeGestureSurvivesArbitration(it, activeHandlers) }
|
|
+ }
|
|
+ } ?: false
|
|
+
|
|
+ // A native handler survives arbitration if it is active, or it does not conflict with any active handler.
|
|
+ private fun nativeGestureSurvivesArbitration(handler: GestureHandler, activeHandlers: List<GestureHandler>) =
|
|
+ handler is NativeViewGestureHandler &&
|
|
+ (handler.isActive || activeHandlers.none { shouldHandlerBeCancelledBy(handler, it) })
|
|
+
|
|
+ // Keep cancellation traversal in the same drawing order as Android touch dispatch.
|
|
+ private fun getChildInDrawingOrderAtIndex(parent: ViewGroup, index: Int): View =
|
|
+ if (parent is ReactViewGroup) {
|
|
+ parent.getChildAt(parent.getZIndexMappedChildIndex(index))
|
|
+ } else {
|
|
+ parent.getChildAt(index)
|
|
+ }
|
|
+
|
|
+ // Collects the view path under the point (topmost child first, like touch dispatch), leaf to root.
|
|
+ private fun collectViewsAtPoint(view: View, coords: FloatArray, out: MutableList<View>): Boolean {
|
|
+ val pointerEvents = viewConfigHelper.getPointerEventsConfigForView(view)
|
|
+ if (pointerEvents == PointerEventsConfig.NONE) {
|
|
+ return false
|
|
+ }
|
|
+
|
|
+ var found = false
|
|
+ if (view is ViewGroup && pointerEvents != PointerEventsConfig.BOX_ONLY) {
|
|
+ for (i in view.childCount - 1 downTo 0) {
|
|
+ val child = getChildInDrawingOrderAtIndex(view, i)
|
|
+ if (!canReceiveEvents(child)) {
|
|
+ continue
|
|
+ }
|
|
+ val childPoint = tempPoint
|
|
+ transformPointToChildViewCoords(coords[0], coords[1], view, child, childPoint)
|
|
+ if (isClipping(child) && !isTransformedTouchPointInView(childPoint.x, childPoint.y, child)) {
|
|
+ continue
|
|
+ }
|
|
+ val restoreX = coords[0]
|
|
+ val restoreY = coords[1]
|
|
+ coords[0] = childPoint.x
|
|
+ coords[1] = childPoint.y
|
|
+ found = collectViewsAtPoint(child, coords, out)
|
|
+ coords[0] = restoreX
|
|
+ coords[1] = restoreY
|
|
+
|
|
+ if (found) {
|
|
+ break
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // BOX_NONE views can't be the target themselves, only their children can.
|
|
+ val selfIsTarget = pointerEvents != PointerEventsConfig.BOX_NONE &&
|
|
+ isTransformedTouchPointInView(coords[0], coords[1], view)
|
|
+
|
|
+ if (found || selfIsTarget) {
|
|
+ // `out` may already contain this view when several pointers share part of their path.
|
|
+ if (!out.contains(view)) {
|
|
+ out.add(view)
|
|
+ }
|
|
+ return true
|
|
+ }
|
|
+ return false
|
|
+ }
|
|
+
|
|
private fun extractGestureHandlers(
|
|
viewGroup: ViewGroup,
|
|
coords: FloatArray,
|
|
diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
|
|
index 629c155..dc0790d 100644
|
|
--- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
|
|
+++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
|
|
@@ -19,6 +19,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
|
|
private val jsGestureHandler: GestureHandler?
|
|
val rootView: ViewGroup
|
|
private var shouldIntercept = false
|
|
+ private var wasIntercepting = false
|
|
private var passingTouch = false
|
|
|
|
init {
|
|
@@ -118,6 +119,14 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
|
|
passingTouch = true
|
|
orchestrator!!.onTouchEvent(event)
|
|
passingTouch = false
|
|
+
|
|
+ // On the transition into interception, cancel the native views the pointers landed on - the
|
|
+ // framework's ACTION_CANCEL never reaches them since RNGH ignores `onInterceptTouchEvent`.
|
|
+ if (shouldIntercept && !wasIntercepting) {
|
|
+ orchestrator!!.cancelTouchesInInterceptedViews(event)
|
|
+ }
|
|
+ wasIntercepting = shouldIntercept
|
|
+
|
|
return shouldIntercept
|
|
}
|
|
|
|
diff --git a/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js b/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js
|
|
index 96c5227..cbf1a88 100644
|
|
--- a/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js
|
|
+++ b/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js
|
|
@@ -58,7 +58,9 @@ class GestureHandler {
|
|
manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this));
|
|
manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this));
|
|
manager.setOnWheel(this.onWheel.bind(this));
|
|
- manager.registerListeners();
|
|
+ if (this.enabled) {
|
|
+ manager.registerListeners();
|
|
+ }
|
|
}
|
|
|
|
//
|
|
diff --git a/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js b/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js
|
|
index 76eb808..7c40526 100644
|
|
--- a/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js
|
|
+++ b/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js
|
|
@@ -58,7 +58,14 @@ class PointerEventManager extends _EventManager.default {
|
|
const adaptedEvent = this.mapEvent(event, _interfaces.EventTypes.UP);
|
|
const target = event.target;
|
|
if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
|
|
- target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ try {
|
|
+ if (target.hasPointerCapture(adaptedEvent.pointerId)) {
|
|
+ target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ }
|
|
+ } catch {
|
|
+ // Pointer capture is implicitly released after pointerup/pointercancel.
|
|
+ // Some browsers can report stale capture state during gesture teardown.
|
|
+ }
|
|
}
|
|
this.markAsOutOfBounds(adaptedEvent.pointerId);
|
|
this.trackedPointers.delete(adaptedEvent.pointerId);
|
|
diff --git a/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js b/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js
|
|
index 0791c66..2f41c77 100644
|
|
--- a/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js
|
|
+++ b/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js
|
|
@@ -52,7 +52,9 @@ export default class GestureHandler {
|
|
manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this));
|
|
manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this));
|
|
manager.setOnWheel(this.onWheel.bind(this));
|
|
- manager.registerListeners();
|
|
+ if (this.enabled) {
|
|
+ manager.registerListeners();
|
|
+ }
|
|
}
|
|
|
|
//
|
|
diff --git a/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js b/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js
|
|
index 6ce3b8f..8fe28bc 100644
|
|
--- a/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js
|
|
+++ b/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js
|
|
@@ -53,7 +53,14 @@ export default class PointerEventManager extends EventManager {
|
|
const adaptedEvent = this.mapEvent(event, EventTypes.UP);
|
|
const target = event.target;
|
|
if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
|
|
- target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ try {
|
|
+ if (target.hasPointerCapture(adaptedEvent.pointerId)) {
|
|
+ target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ }
|
|
+ } catch {
|
|
+ // Pointer capture is implicitly released after pointerup/pointercancel.
|
|
+ // Some browsers can report stale capture state during gesture teardown.
|
|
+ }
|
|
}
|
|
this.markAsOutOfBounds(adaptedEvent.pointerId);
|
|
this.trackedPointers.delete(adaptedEvent.pointerId);
|
|
diff --git a/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts b/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts
|
|
index ddb79a3..4e1274c 100644
|
|
--- a/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts
|
|
+++ b/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts
|
|
@@ -79,7 +79,9 @@ export default abstract class GestureHandler implements IGestureHandler {
|
|
manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this));
|
|
manager.setOnWheel(this.onWheel.bind(this));
|
|
|
|
- manager.registerListeners();
|
|
+ if (this.enabled) {
|
|
+ manager.registerListeners();
|
|
+ }
|
|
}
|
|
|
|
//
|
|
diff --git a/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts b/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts
|
|
index 18d3627..769b0fe 100644
|
|
--- a/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts
|
|
+++ b/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts
|
|
@@ -67,7 +67,14 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
|
|
const target = event.target as HTMLElement;
|
|
|
|
if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
|
|
- target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ try {
|
|
+ if (target.hasPointerCapture(adaptedEvent.pointerId)) {
|
|
+ target.releasePointerCapture(adaptedEvent.pointerId);
|
|
+ }
|
|
+ } catch {
|
|
+ // Pointer capture is implicitly released after pointerup/pointercancel.
|
|
+ // Some browsers can report stale capture state during gesture teardown.
|
|
+ }
|
|
}
|
|
|
|
this.markAsOutOfBounds(adaptedEvent.pointerId);
|