mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-27 11:42:52 +00:00
Initially disabled gesture hosts still registered pointer and wheel listeners, while hover cards used window positions inside a workspace-local sheet portal. Respect initial gesture enablement and position cards relative to their measured floating host. Keep developer-toast dismissal independent of pointer input and replacement toast visibility so modal, hover, and focus checks retain their input state.
272 lines
13 KiB
Diff
272 lines
13 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..02e3ea6 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,6 +2,7 @@ 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
|
|
@@ -28,6 +29,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 +51,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 +585,107 @@ 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) })
|
|
+
|
|
+ // 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 = viewConfigHelper.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..e1909ff 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(ev)
|
|
+ }
|
|
+ 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);
|