react-native-gesture-handler 2.12.1 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. package/RNGestureHandler.podspec +0 -15
  2. package/android/build.gradle +5 -76
  3. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +16 -1
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +43 -18
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +120 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt +7 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt +5 -0
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +43 -16
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +21 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt +9 -1
  11. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt +10 -0
  12. package/ios/Handlers/RNHoverHandler.h +12 -0
  13. package/ios/Handlers/RNHoverHandler.m +152 -0
  14. package/ios/RNGestureHandlerButtonComponentView.mm +2 -0
  15. package/ios/RNGestureHandlerEvents.h +1 -0
  16. package/ios/RNGestureHandlerEvents.m +10 -0
  17. package/ios/RNGestureHandlerManager.mm +2 -0
  18. package/ios/RNManualActivationRecognizer.m +2 -1
  19. package/ios/RNRootViewGestureRecognizer.m +7 -2
  20. package/lib/commonjs/RNGestureHandlerModule.macos.js +3 -1
  21. package/lib/commonjs/RNGestureHandlerModule.macos.js.map +1 -1
  22. package/lib/commonjs/RNGestureHandlerModule.web.js +7 -2
  23. package/lib/commonjs/RNGestureHandlerModule.web.js.map +1 -1
  24. package/lib/commonjs/RNGestureHandlerModule.windows.js +3 -1
  25. package/lib/commonjs/RNGestureHandlerModule.windows.js.map +1 -1
  26. package/lib/commonjs/components/DrawerLayout.js +1 -0
  27. package/lib/commonjs/components/DrawerLayout.js.map +1 -1
  28. package/lib/commonjs/components/touchables/GenericTouchable.js +1 -2
  29. package/lib/commonjs/components/touchables/GenericTouchable.js.map +1 -1
  30. package/lib/commonjs/components/touchables/TouchableHighlight.js.map +1 -1
  31. package/lib/commonjs/components/touchables/TouchableNativeFeedback.android.js.map +1 -1
  32. package/lib/commonjs/components/touchables/TouchableOpacity.js.map +1 -1
  33. package/lib/commonjs/components/touchables/TouchableWithoutFeedback.js.map +1 -1
  34. package/lib/commonjs/components/touchables/index.js.map +1 -1
  35. package/lib/commonjs/handlers/createHandler.js +3 -3
  36. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  37. package/lib/commonjs/handlers/gestureHandlerCommon.js +1 -1
  38. package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
  39. package/lib/commonjs/handlers/gestures/GestureDetector.js +3 -1
  40. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  41. package/lib/commonjs/handlers/gestures/gesture.js +5 -0
  42. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  43. package/lib/commonjs/handlers/gestures/gestureObjects.js +5 -0
  44. package/lib/commonjs/handlers/gestures/gestureObjects.js.map +1 -1
  45. package/lib/commonjs/handlers/gestures/hoverGesture.js +74 -0
  46. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -0
  47. package/lib/commonjs/index.js +8 -0
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/web/handlers/FlingGestureHandler.js +0 -10
  50. package/lib/commonjs/web/handlers/FlingGestureHandler.js.map +1 -1
  51. package/lib/commonjs/web/handlers/GestureHandler.js +61 -88
  52. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  53. package/lib/commonjs/web/handlers/HoverGestureHandler.js +62 -0
  54. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -0
  55. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +6 -7
  56. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  57. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +12 -4
  58. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  59. package/lib/commonjs/web/handlers/PanGestureHandler.js +2 -7
  60. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  61. package/lib/commonjs/web/handlers/TapGestureHandler.js +0 -10
  62. package/lib/commonjs/web/handlers/TapGestureHandler.js.map +1 -1
  63. package/lib/commonjs/web/interfaces.js +1 -1
  64. package/lib/commonjs/web/interfaces.js.map +1 -1
  65. package/lib/commonjs/web/tools/EventManager.js +18 -4
  66. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  67. package/lib/commonjs/web/tools/GestureHandlerDelegate.js +6 -0
  68. package/lib/commonjs/web/tools/GestureHandlerDelegate.js.map +1 -0
  69. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js +5 -7
  70. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  71. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +118 -0
  72. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -0
  73. package/lib/commonjs/web/tools/PointerEventManager.js +38 -5
  74. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  75. package/lib/commonjs/web/tools/TouchEventManager.js +2 -2
  76. package/lib/commonjs/web/tools/TouchEventManager.js.map +1 -1
  77. package/lib/module/RNGestureHandlerModule.macos.js +2 -1
  78. package/lib/module/RNGestureHandlerModule.macos.js.map +1 -1
  79. package/lib/module/RNGestureHandlerModule.web.js +6 -3
  80. package/lib/module/RNGestureHandlerModule.web.js.map +1 -1
  81. package/lib/module/RNGestureHandlerModule.windows.js +2 -1
  82. package/lib/module/RNGestureHandlerModule.windows.js.map +1 -1
  83. package/lib/module/components/DrawerLayout.js +1 -0
  84. package/lib/module/components/DrawerLayout.js.map +1 -1
  85. package/lib/module/components/touchables/GenericTouchable.js +1 -2
  86. package/lib/module/components/touchables/GenericTouchable.js.map +1 -1
  87. package/lib/module/components/touchables/TouchableHighlight.js.map +1 -1
  88. package/lib/module/components/touchables/TouchableNativeFeedback.android.js.map +1 -1
  89. package/lib/module/components/touchables/TouchableOpacity.js.map +1 -1
  90. package/lib/module/components/touchables/TouchableWithoutFeedback.js.map +1 -1
  91. package/lib/module/components/touchables/index.js.map +1 -1
  92. package/lib/module/handlers/createHandler.js +3 -3
  93. package/lib/module/handlers/createHandler.js.map +1 -1
  94. package/lib/module/handlers/gestureHandlerCommon.js +1 -1
  95. package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
  96. package/lib/module/handlers/gestures/GestureDetector.js +2 -1
  97. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  98. package/lib/module/handlers/gestures/gesture.js +5 -0
  99. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  100. package/lib/module/handlers/gestures/gestureObjects.js +4 -0
  101. package/lib/module/handlers/gestures/gestureObjects.js.map +1 -1
  102. package/lib/module/handlers/gestures/hoverGesture.js +62 -0
  103. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -0
  104. package/lib/module/index.js +1 -0
  105. package/lib/module/index.js.map +1 -1
  106. package/lib/module/web/handlers/FlingGestureHandler.js +0 -10
  107. package/lib/module/web/handlers/FlingGestureHandler.js.map +1 -1
  108. package/lib/module/web/handlers/GestureHandler.js +61 -84
  109. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  110. package/lib/module/web/handlers/HoverGestureHandler.js +47 -0
  111. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -0
  112. package/lib/module/web/handlers/LongPressGestureHandler.js +5 -7
  113. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  114. package/lib/module/web/handlers/NativeViewGestureHandler.js +11 -4
  115. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  116. package/lib/module/web/handlers/PanGestureHandler.js +2 -7
  117. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  118. package/lib/module/web/handlers/TapGestureHandler.js +0 -10
  119. package/lib/module/web/handlers/TapGestureHandler.js.map +1 -1
  120. package/lib/module/web/interfaces.js +1 -1
  121. package/lib/module/web/interfaces.js.map +1 -1
  122. package/lib/module/web/tools/EventManager.js +18 -4
  123. package/lib/module/web/tools/EventManager.js.map +1 -1
  124. package/lib/module/web/tools/GestureHandlerDelegate.js +2 -0
  125. package/lib/module/web/tools/GestureHandlerDelegate.js.map +1 -0
  126. package/lib/module/web/tools/GestureHandlerOrchestrator.js +5 -6
  127. package/lib/module/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  128. package/lib/module/web/tools/GestureHandlerWebDelegate.js +102 -0
  129. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -0
  130. package/lib/module/web/tools/PointerEventManager.js +39 -6
  131. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  132. package/lib/module/web/tools/TouchEventManager.js +2 -2
  133. package/lib/module/web/tools/TouchEventManager.js.map +1 -1
  134. package/lib/typescript/RNGestureHandlerModule.macos.d.ts +1 -1
  135. package/lib/typescript/RNGestureHandlerModule.web.d.ts +3 -1
  136. package/lib/typescript/RNGestureHandlerModule.windows.d.ts +1 -1
  137. package/lib/typescript/components/DrawerLayout.d.ts +7 -1
  138. package/lib/typescript/components/touchables/GenericTouchable.d.ts +3 -2
  139. package/lib/typescript/components/touchables/TouchableHighlight.d.ts +4 -3
  140. package/lib/typescript/components/touchables/TouchableNativeFeedback.android.d.ts +3 -2
  141. package/lib/typescript/components/touchables/TouchableOpacity.d.ts +4 -5
  142. package/lib/typescript/components/touchables/TouchableWithoutFeedback.d.ts +1 -0
  143. package/lib/typescript/components/touchables/index.d.ts +3 -0
  144. package/lib/typescript/handlers/NativeViewGestureHandler.d.ts +1 -1
  145. package/lib/typescript/handlers/gestureHandlerCommon.d.ts +3 -1
  146. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -1
  147. package/lib/typescript/handlers/gestures/gestureObjects.d.ts +2 -0
  148. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +32 -0
  149. package/lib/typescript/index.d.ts +4 -0
  150. package/lib/typescript/web/handlers/FlingGestureHandler.d.ts +0 -6
  151. package/lib/typescript/web/handlers/GestureHandler.d.ts +12 -17
  152. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +10 -0
  153. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +0 -4
  154. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -1
  155. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +0 -4
  156. package/lib/typescript/web/handlers/TapGestureHandler.d.ts +0 -6
  157. package/lib/typescript/web/interfaces.d.ts +4 -3
  158. package/lib/typescript/web/tools/EventManager.d.ts +9 -5
  159. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +22 -0
  160. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +21 -0
  161. package/lib/typescript/web/tools/NodeManager.d.ts +2 -2
  162. package/lib/typescript/web/tools/PointerEventManager.d.ts +1 -1
  163. package/lib/typescript/web/tools/TouchEventManager.d.ts +1 -1
  164. package/package.json +2 -2
  165. package/src/RNGestureHandlerModule.macos.ts +5 -1
  166. package/src/RNGestureHandlerModule.web.ts +7 -1
  167. package/src/RNGestureHandlerModule.windows.ts +5 -1
  168. package/src/components/DrawerLayout.tsx +9 -0
  169. package/src/components/touchables/GenericTouchable.tsx +4 -4
  170. package/src/components/touchables/TouchableHighlight.tsx +6 -3
  171. package/src/components/touchables/TouchableNativeFeedback.android.tsx +5 -4
  172. package/src/components/touchables/TouchableOpacity.tsx +6 -7
  173. package/src/components/touchables/TouchableWithoutFeedback.tsx +3 -1
  174. package/src/components/touchables/index.ts +3 -0
  175. package/src/handlers/createHandler.tsx +4 -2
  176. package/src/handlers/gestureHandlerCommon.ts +39 -0
  177. package/src/handlers/gestures/GestureDetector.tsx +2 -0
  178. package/src/handlers/gestures/gesture.ts +6 -0
  179. package/src/handlers/gestures/gestureObjects.ts +5 -0
  180. package/src/handlers/gestures/hoverGesture.ts +83 -0
  181. package/src/index.ts +8 -0
  182. package/src/web/handlers/FlingGestureHandler.ts +0 -11
  183. package/src/web/handlers/GestureHandler.ts +68 -88
  184. package/src/web/handlers/HoverGestureHandler.ts +43 -0
  185. package/src/web/handlers/LongPressGestureHandler.ts +5 -7
  186. package/src/web/handlers/NativeViewGestureHandler.ts +11 -4
  187. package/src/web/handlers/PanGestureHandler.ts +1 -6
  188. package/src/web/handlers/TapGestureHandler.ts +0 -11
  189. package/src/web/interfaces.ts +4 -2
  190. package/src/web/tools/EventManager.ts +15 -7
  191. package/src/web/tools/GestureHandlerDelegate.ts +23 -0
  192. package/src/web/tools/GestureHandlerOrchestrator.ts +7 -6
  193. package/src/web/tools/GestureHandlerWebDelegate.ts +115 -0
  194. package/src/web/tools/PointerEventManager.ts +46 -16
  195. package/src/web/tools/TouchEventManager.ts +3 -3
@@ -2,21 +2,6 @@ require "json"
2
2
 
3
3
  fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
4
4
 
5
- isUserApp = File.exist?(File.join(__dir__, "..", "..", "node_modules", "react-native", "package.json"))
6
- if isUserApp
7
- libInstances = %x[find ../../ -name "package.json" | grep "/react-native-gesture-handler/package.json" | grep -v "/.yarn/"]
8
- libInstancesArray = libInstances.split("\n")
9
- if libInstancesArray.length() > 1
10
- parsedLocation = ''
11
- for location in libInstancesArray
12
- location['../../'] = '- '
13
- location['/package.json'] = ''
14
- parsedLocation += location + "\n"
15
- end
16
- raise "[Gesture Handler] Multiple versions of Gesture Handler were detected. Only one instance of react-native-gesture-handler can be installed in a project. You need to resolve the conflict manually. Check out the documentation: https://docs.swmansion.com/react-native-gesture-handler/docs/troubleshooting#multiple-versions-of-reanimated-were-detected \n\nConflict between: \n" + parsedLocation
17
- end
18
- end
19
-
20
5
  Pod::Spec.new do |s|
21
6
  # NPM package specification
22
7
  package = JSON.parse(File.read(File.join(File.dirname(__FILE__), "package.json")))
@@ -68,14 +68,6 @@ if (project == rootProject) {
68
68
  apply from: "spotless.gradle"
69
69
  }
70
70
 
71
- def shouldAssertNoMultipleInstances() {
72
- if (rootProject.hasProperty("disableMultipleInstancesCheck")) {
73
- return rootProject.property("disableMultipleInstancesCheck") != "true"
74
- } else {
75
- return true
76
- }
77
- }
78
-
79
71
  // Check whether Reanimated 2.3 or higher is installed alongside Gesture Handler
80
72
  def shouldUseCommonInterfaceFromReanimated() {
81
73
  def reanimated = rootProject.subprojects.find { it.name == 'react-native-reanimated' }
@@ -103,71 +95,12 @@ file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { react
103
95
  def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME")
104
96
  def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
105
97
 
106
-
107
- abstract class NoMultipleInstancesAssertionTask extends DefaultTask {
108
- @Inject abstract ObjectFactory getObjectFactory()
109
-
110
- @Input abstract Property<File> getProjectDirFile()
111
- @Input abstract Property<File> getRootDirFile()
112
- @Input abstract Property<Boolean> getShouldCheck()
113
-
114
- def findGestureHandlerInstancesForPath(String path) {
115
- return objectFactory.fileTree().from(path)
116
- .include("**/react-native-gesture-handler/package.json")
117
- .exclude("**/.yarn/**")
118
- .exclude({ Files.isSymbolicLink(it.getFile().toPath()) })
119
- .findAll()
120
- }
121
-
122
- @TaskAction
123
- def check() {
124
- if (shouldCheck.get()) {
125
- // Assert there are no multiple installations of Gesture Handler
126
- Set<File> files
127
-
128
- if (projectDirFile.get().parent.contains(rootDirFile.get().parent)) {
129
- // standard app
130
- files = findGestureHandlerInstancesForPath(rootDirFile.get().parent + "/node_modules")
131
- } else {
132
- // monorepo
133
- files = findGestureHandlerInstancesForPath(rootDirFile.get().parent + "/node_modules")
134
- files.addAll(
135
- findGestureHandlerInstancesForPath(projectDirFile.get().parentFile.parent)
136
- )
137
- }
138
-
139
- if (files.size() > 1) {
140
- String parsedLocation = files.stream().map({
141
- File file -> "- " + file.toString().replace("/package.json", "")
142
- }).collect().join("\n")
143
- String exceptionMessage = "\n[react-native-gesture-handler] Multiple versions of Gesture Handler " +
144
- "were detected. Only one instance of react-native-gesture-handler can be installed in a " +
145
- "project. You need to resolve the conflict manually. Check out the documentation: " +
146
- "https://docs.swmansion.com/react-native-gesture-handler/docs/troubleshooting" +
147
- "#multiple-instances-of-gesture-handler-were-detected \n\nConflict between: \n" +
148
- parsedLocation + "\n"
149
- throw new GradleException(exceptionMessage)
150
- }
151
- }
152
- }
153
- }
154
-
155
- tasks.register('assertNoMultipleInstances', NoMultipleInstancesAssertionTask) {
156
- shouldCheck = shouldAssertNoMultipleInstances()
157
- rootDirFile = rootDir
158
- projectDirFile = projectDir
159
- }
160
-
161
- tasks.preBuild {
162
- dependsOn assertNoMultipleInstances
163
- }
164
-
165
98
  repositories {
166
99
  mavenCentral()
167
100
  }
168
101
 
169
102
  android {
170
- compileSdkVersion safeExtGet("compileSdkVersion", 28)
103
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
171
104
  def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
172
105
  if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
173
106
  namespace "com.swmansion.gesturehandler"
@@ -189,8 +122,8 @@ android {
189
122
  }
190
123
 
191
124
  defaultConfig {
192
- minSdkVersion safeExtGet('minSdkVersion', 16)
193
- targetSdkVersion safeExtGet('targetSdkVersion', 28)
125
+ minSdkVersion safeExtGet('minSdkVersion', 21)
126
+ targetSdkVersion safeExtGet('targetSdkVersion', 33)
194
127
  versionCode 1
195
128
  versionName "1.0"
196
129
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
@@ -256,12 +189,8 @@ android {
256
189
  def kotlin_version = safeExtGet('kotlinVersion', project.properties['RNGH_kotlinVersion'])
257
190
 
258
191
  dependencies {
259
- //noinspection GradleDynamicVersion
260
- if (REACT_NATIVE_MINOR_VERSION >= 71) {
261
- implementation "com.facebook.react:react-android" // version substituted by RNGP
262
- } else {
263
- implementation 'com.facebook.react:react-native:+' // from node_modules
264
- }
192
+ implementation 'com.facebook.react:react-native:+' // from node_modules
193
+
265
194
 
266
195
  if (shouldUseCommonInterfaceFromReanimated()) {
267
196
  // Include Reanimated as dependency to load the common interface
@@ -371,7 +371,14 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
371
371
  lastAbsolutePositionY = GestureUtils.getLastPointerY(adaptedTransformedEvent, true)
372
372
  lastEventOffsetX = adaptedTransformedEvent.rawX - adaptedTransformedEvent.x
373
373
  lastEventOffsetY = adaptedTransformedEvent.rawY - adaptedTransformedEvent.y
374
- onHandle(adaptedTransformedEvent, adaptedSourceEvent)
374
+ if (sourceEvent.action == MotionEvent.ACTION_HOVER_ENTER ||
375
+ sourceEvent.action == MotionEvent.ACTION_HOVER_MOVE ||
376
+ sourceEvent.action == MotionEvent.ACTION_HOVER_EXIT
377
+ ) {
378
+ onHandleHover(adaptedTransformedEvent, adaptedSourceEvent)
379
+ } else {
380
+ onHandle(adaptedTransformedEvent, adaptedSourceEvent)
381
+ }
375
382
  if (adaptedTransformedEvent != transformedEvent) {
376
383
  adaptedTransformedEvent.recycle()
377
384
  }
@@ -675,6 +682,8 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
675
682
  moveToState(STATE_FAILED)
676
683
  }
677
684
 
685
+ protected open fun onHandleHover(event: MotionEvent, sourceEvent: MotionEvent) {}
686
+
678
687
  protected open fun onStateChange(newState: Int, previousState: Int) {}
679
688
  protected open fun onReset() {}
680
689
  protected open fun onCancel() {}
@@ -706,6 +715,12 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
706
715
  onReset()
707
716
  }
708
717
 
718
+ fun withMarkedAsInBounds(closure: () -> Unit) {
719
+ isWithinBounds = true
720
+ closure()
721
+ isWithinBounds = false
722
+ }
723
+
709
724
  fun setOnTouchEventListener(listener: OnTouchEventListener?): GestureHandler<*> {
710
725
  onTouchEventListener = listener
711
726
  return this
@@ -37,7 +37,7 @@ class GestureHandlerOrchestrator(
37
37
  fun onTouchEvent(event: MotionEvent): Boolean {
38
38
  isHandlingTouch = true
39
39
  val action = event.actionMasked
40
- if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
40
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN || action == MotionEvent.ACTION_HOVER_MOVE) {
41
41
  extractGestureHandlers(event)
42
42
  } else if (action == MotionEvent.ACTION_CANCEL) {
43
43
  cancelAll()
@@ -295,7 +295,7 @@ class GestureHandlerOrchestrator(
295
295
 
296
296
  // if event was of type UP or POINTER_UP we request handler to stop tracking now that
297
297
  // the event has been dispatched
298
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
298
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_HOVER_EXIT) {
299
299
  val pointerId = event.getPointerId(event.actionIndex)
300
300
  handler.stopTrackingPointer(pointerId)
301
301
  }
@@ -325,6 +325,8 @@ class GestureHandlerOrchestrator(
325
325
  return parent === wrapperView
326
326
  }
327
327
 
328
+ fun isAnyHandlerActive() = gestureHandlers.any { it?.state == GestureHandler.STATE_ACTIVE }
329
+
328
330
  /**
329
331
  * Transforms an event in the coordinates of wrapperView into the coordinate space of the received view.
330
332
  *
@@ -464,16 +466,24 @@ class GestureHandlerOrchestrator(
464
466
  return found
465
467
  }
466
468
 
467
- private fun recordViewHandlersForPointer(view: View, coords: FloatArray, pointerId: Int): Boolean {
469
+ private fun recordViewHandlersForPointer(view: View, coords: FloatArray, pointerId: Int, event: MotionEvent): Boolean {
468
470
  var found = false
469
471
  handlerRegistry.getHandlersForView(view)?.let {
470
472
  synchronized(it) {
471
473
  for (handler in it) {
472
- if (handler.isEnabled && handler.isWithinBounds(view, coords[0], coords[1])) {
473
- recordHandlerIfNotPresent(handler, view)
474
- handler.startTrackingPointer(pointerId)
475
- found = true
474
+ // skip disabled and out-of-bounds handlers
475
+ if (!handler.isEnabled || !handler.isWithinBounds(view, coords[0], coords[1])) {
476
+ continue
477
+ }
478
+
479
+ // we don't want to extract gestures other than hover when processing hover events
480
+ if (event.action in listOf(MotionEvent.ACTION_HOVER_EXIT, MotionEvent.ACTION_HOVER_ENTER, MotionEvent.ACTION_HOVER_MOVE) && handler !is HoverGestureHandler) {
481
+ continue
476
482
  }
483
+
484
+ recordHandlerIfNotPresent(handler, view)
485
+ handler.startTrackingPointer(pointerId)
486
+ found = true
477
487
  }
478
488
  }
479
489
  }
@@ -494,11 +504,11 @@ class GestureHandlerOrchestrator(
494
504
  val pointerId = event.getPointerId(actionIndex)
495
505
  tempCoords[0] = event.getX(actionIndex)
496
506
  tempCoords[1] = event.getY(actionIndex)
497
- traverseWithPointerEvents(wrapperView, tempCoords, pointerId)
498
- extractGestureHandlers(wrapperView, tempCoords, pointerId)
507
+ traverseWithPointerEvents(wrapperView, tempCoords, pointerId, event)
508
+ extractGestureHandlers(wrapperView, tempCoords, pointerId, event)
499
509
  }
500
510
 
501
- private fun extractGestureHandlers(viewGroup: ViewGroup, coords: FloatArray, pointerId: Int): Boolean {
511
+ private fun extractGestureHandlers(viewGroup: ViewGroup, coords: FloatArray, pointerId: Int, event: MotionEvent): Boolean {
502
512
  val childrenCount = viewGroup.childCount
503
513
  for (i in childrenCount - 1 downTo 0) {
504
514
  val child = viewConfigHelper.getChildInDrawingOrderAtIndex(viewGroup, i)
@@ -513,7 +523,7 @@ class GestureHandlerOrchestrator(
513
523
  if (!isClipping(child) || isTransformedTouchPointInView(coords[0], coords[1], child)) {
514
524
  // we only consider the view if touch is inside the view bounds or if the view's children
515
525
  // can render outside of the view bounds (overflow visible)
516
- found = traverseWithPointerEvents(child, coords, pointerId)
526
+ found = traverseWithPointerEvents(child, coords, pointerId, event)
517
527
  }
518
528
  coords[0] = restoreX
519
529
  coords[1] = restoreY
@@ -525,7 +535,7 @@ class GestureHandlerOrchestrator(
525
535
  return false
526
536
  }
527
537
 
528
- private fun traverseWithPointerEvents(view: View, coords: FloatArray, pointerId: Int): Boolean =
538
+ private fun traverseWithPointerEvents(view: View, coords: FloatArray, pointerId: Int, event: MotionEvent): Boolean =
529
539
  when (viewConfigHelper.getPointerEventsConfigForView(view)) {
530
540
  PointerEventsConfig.NONE -> {
531
541
  // This view and its children can't be the target
@@ -534,7 +544,7 @@ class GestureHandlerOrchestrator(
534
544
  PointerEventsConfig.BOX_ONLY -> {
535
545
  // This view is the target, its children don't matter
536
546
  (
537
- recordViewHandlersForPointer(view, coords, pointerId) ||
547
+ recordViewHandlersForPointer(view, coords, pointerId, event) ||
538
548
  shouldHandlerlessViewBecomeTouchTarget(view, coords)
539
549
  )
540
550
  }
@@ -542,10 +552,10 @@ class GestureHandlerOrchestrator(
542
552
  // This view can't be the target, but its children might
543
553
  when (view) {
544
554
  is ViewGroup -> {
545
- extractGestureHandlers(view, coords, pointerId).also { found ->
555
+ extractGestureHandlers(view, coords, pointerId, event).also { found ->
546
556
  // A child view is handling touch, also extract handlers attached to this view
547
557
  if (found) {
548
- recordViewHandlersForPointer(view, coords, pointerId)
558
+ recordViewHandlersForPointer(view, coords, pointerId, event)
549
559
  }
550
560
  }
551
561
  }
@@ -554,7 +564,7 @@ class GestureHandlerOrchestrator(
554
564
  // handlers attached to the text input, as it makes sense that gestures would work on a
555
565
  // non-editable TextInput.
556
566
  is EditText -> {
557
- recordViewHandlersForPointer(view, coords, pointerId)
567
+ recordViewHandlersForPointer(view, coords, pointerId, event)
558
568
  }
559
569
  else -> false
560
570
  }
@@ -562,11 +572,11 @@ class GestureHandlerOrchestrator(
562
572
  PointerEventsConfig.AUTO -> {
563
573
  // Either this view or one of its children is the target
564
574
  val found = if (view is ViewGroup) {
565
- extractGestureHandlers(view, coords, pointerId)
575
+ extractGestureHandlers(view, coords, pointerId, event)
566
576
  } else false
567
577
 
568
578
  (
569
- recordViewHandlersForPointer(view, coords, pointerId) ||
579
+ recordViewHandlersForPointer(view, coords, pointerId, event) ||
570
580
  found || shouldHandlerlessViewBecomeTouchTarget(view, coords)
571
581
  )
572
582
  }
@@ -580,6 +590,21 @@ class GestureHandlerOrchestrator(
580
590
  private fun isClipping(view: View) =
581
591
  view !is ViewGroup || viewConfigHelper.isViewClippingChildren(view)
582
592
 
593
+ fun activateNativeHandlersForView(view: View) {
594
+ handlerRegistry.getHandlersForView(view)?.forEach {
595
+ if (it !is NativeViewGestureHandler) {
596
+ return@forEach
597
+ }
598
+ this.recordHandlerIfNotPresent(it, view)
599
+
600
+ it.withMarkedAsInBounds {
601
+ it.begin()
602
+ it.activate()
603
+ it.end()
604
+ }
605
+ }
606
+ }
607
+
583
608
  companion object {
584
609
  // The limit doesn't necessarily need to exists, it was just simpler to implement it that way
585
610
  // it is also more allocation-wise efficient to have a fixed limit
@@ -0,0 +1,120 @@
1
+ package com.swmansion.gesturehandler.core
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import android.view.MotionEvent
6
+ import android.view.View
7
+ import android.view.ViewGroup
8
+ import com.swmansion.gesturehandler.react.RNViewConfigurationHelper
9
+
10
+ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
11
+ private var handler: Handler? = null
12
+ private var finishRunnable = Runnable { finish() }
13
+
14
+ private infix fun isAncestorOf(other: GestureHandler<*>): Boolean {
15
+ var current: View? = other.view
16
+
17
+ while (current != null) {
18
+ if (current == this.view) {
19
+ return true
20
+ }
21
+
22
+ current = current.parent as? View
23
+ }
24
+
25
+ return false
26
+ }
27
+
28
+ private fun isViewDisplayedOverAnother(view: View, other: View, rootView: View = view.rootView): Boolean? {
29
+ // traverse the tree starting on the root view, to see which view will be drawn first
30
+ if (rootView == other) {
31
+ return true
32
+ }
33
+
34
+ if (rootView == view) {
35
+ return false
36
+ }
37
+
38
+ if (rootView is ViewGroup) {
39
+ for (i in 0 until rootView.childCount) {
40
+ val child = viewConfigHelper.getChildInDrawingOrderAtIndex(rootView, i)
41
+ return isViewDisplayedOverAnother(view, other, child) ?: continue
42
+ }
43
+ }
44
+
45
+ return null
46
+ }
47
+
48
+ override fun shouldBeCancelledBy(handler: GestureHandler<*>): Boolean {
49
+ if (handler is HoverGestureHandler && !(handler isAncestorOf this)) {
50
+ return isViewDisplayedOverAnother(handler.view!!, this.view!!)!!
51
+ }
52
+
53
+ return super.shouldBeCancelledBy(handler)
54
+ }
55
+
56
+ override fun shouldRequireToWaitForFailure(handler: GestureHandler<*>): Boolean {
57
+ if (handler is HoverGestureHandler) {
58
+ if (!(this isAncestorOf handler) && !(handler isAncestorOf this)) {
59
+ isViewDisplayedOverAnother(this.view!!, handler.view!!)?.let {
60
+ return it
61
+ }
62
+ }
63
+ }
64
+
65
+ return super.shouldRequireToWaitForFailure(handler)
66
+ }
67
+
68
+ override fun shouldRecognizeSimultaneously(handler: GestureHandler<*>): Boolean {
69
+ if (handler is HoverGestureHandler && (this isAncestorOf handler || handler isAncestorOf this)) {
70
+ return true
71
+ }
72
+
73
+ return super.shouldRecognizeSimultaneously(handler)
74
+ }
75
+
76
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
77
+ if (event.action == MotionEvent.ACTION_DOWN) {
78
+ handler?.removeCallbacksAndMessages(null)
79
+ handler = null
80
+ } else if (event.action == MotionEvent.ACTION_UP) {
81
+ if (!isWithinBounds) {
82
+ finish()
83
+ }
84
+ }
85
+ }
86
+
87
+ override fun onHandleHover(event: MotionEvent, sourceEvent: MotionEvent) {
88
+ when {
89
+ event.action == MotionEvent.ACTION_HOVER_EXIT -> {
90
+ if (handler == null) {
91
+ handler = Handler(Looper.getMainLooper())
92
+ }
93
+
94
+ handler!!.postDelayed(finishRunnable, 4)
95
+ }
96
+
97
+ !isWithinBounds -> {
98
+ finish()
99
+ }
100
+
101
+ this.state == STATE_UNDETERMINED &&
102
+ (event.action == MotionEvent.ACTION_HOVER_MOVE || event.action == MotionEvent.ACTION_HOVER_ENTER) -> {
103
+ begin()
104
+ activate()
105
+ }
106
+ }
107
+ }
108
+
109
+ private fun finish() {
110
+ when (this.state) {
111
+ STATE_UNDETERMINED -> cancel()
112
+ STATE_BEGAN -> fail()
113
+ STATE_ACTIVE -> end()
114
+ }
115
+ }
116
+
117
+ companion object {
118
+ private val viewConfigHelper = RNViewConfigurationHelper()
119
+ }
120
+ }
@@ -6,6 +6,7 @@ import android.view.View
6
6
  import android.view.ViewConfiguration
7
7
  import android.view.ViewGroup
8
8
  import android.widget.ScrollView
9
+ import com.facebook.react.views.scroll.ReactScrollView
9
10
  import com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout
10
11
  import com.facebook.react.views.textinput.ReactEditText
11
12
 
@@ -75,6 +76,7 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
75
76
  is NativeViewGestureHandlerHook -> this.hook = view
76
77
  is ReactEditText -> this.hook = EditTextHook(this, view)
77
78
  is ReactSwipeRefreshLayout -> this.hook = SwipeRefreshLayoutHook(this, view)
79
+ is ReactScrollView -> this.hook = ScrollViewHook()
78
80
  }
79
81
  }
80
82
 
@@ -120,6 +122,7 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
120
122
  action = MotionEvent.ACTION_CANCEL
121
123
  }
122
124
  view!!.onTouchEvent(event)
125
+ event.recycle()
123
126
  }
124
127
 
125
128
  override fun onReset() {
@@ -247,4 +250,8 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
247
250
  // oh well ¯\_(ツ)_/¯
248
251
  }
249
252
  }
253
+
254
+ private class ScrollViewHook : NativeViewGestureHandlerHook {
255
+ override fun shouldCancelRootViewGestureHandlerIfNecessary() = true
256
+ }
250
257
  }
@@ -1,5 +1,7 @@
1
1
  package com.swmansion.gesturehandler.react
2
2
 
3
+ import android.content.Context
4
+ import android.view.accessibility.AccessibilityManager
3
5
  import com.facebook.react.bridge.ReactContext
4
6
  import com.facebook.react.modules.core.DeviceEventManagerModule
5
7
  import com.facebook.react.uimanager.UIManagerModule
@@ -9,3 +11,6 @@ val ReactContext.deviceEventEmitter: DeviceEventManagerModule.RCTDeviceEventEmit
9
11
 
10
12
  val ReactContext.UIManager: UIManagerModule
11
13
  get() = this.getNativeModule(UIManagerModule::class.java)!!
14
+
15
+ fun Context.isScreenReaderOn() =
16
+ (getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager).isEnabled
@@ -13,10 +13,12 @@ import android.graphics.drawable.ShapeDrawable
13
13
  import android.graphics.drawable.shapes.RectShape
14
14
  import android.os.Build
15
15
  import android.util.TypedValue
16
+ import android.view.KeyEvent
16
17
  import android.view.MotionEvent
17
18
  import android.view.View
18
19
  import android.view.View.OnClickListener
19
20
  import android.view.ViewGroup
21
+ import android.view.ViewParent
20
22
  import androidx.core.view.children
21
23
  import com.facebook.react.module.annotations.ReactModule
22
24
  import com.facebook.react.uimanager.PixelUtil
@@ -119,6 +121,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
119
121
  private var needBackgroundUpdate = false
120
122
  private var lastEventTime = -1L
121
123
  private var lastAction = -1
124
+ private var receivedKeyEvent = false
122
125
 
123
126
  var isTouched = false
124
127
 
@@ -128,6 +131,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
128
131
  isClickable = true
129
132
  isFocusable = true
130
133
  needBackgroundUpdate = true
134
+ clipChildren = false
131
135
  }
132
136
 
133
137
  private inline fun withBackgroundUpdate(block: () -> Unit) {
@@ -170,6 +174,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
170
174
  override fun onTouchEvent(event: MotionEvent): Boolean {
171
175
  if (event.action == MotionEvent.ACTION_CANCEL) {
172
176
  tryFreeingResponder()
177
+ return super.onTouchEvent(event)
173
178
  }
174
179
 
175
180
  val eventTime = event.eventTime
@@ -208,7 +213,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
208
213
  // Therefore it might be used as long as:
209
214
  // 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup
210
215
  // 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent
211
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && selectable is RippleDrawable) {
216
+ if (selectable is RippleDrawable) {
212
217
  val mask = PaintDrawable(Color.WHITE)
213
218
  mask.setCornerRadius(borderRadius)
214
219
  selectable.setDrawableByLayerId(android.R.id.mask, mask)
@@ -235,16 +240,8 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
235
240
  }
236
241
 
237
242
  private fun createSelectableDrawable(): Drawable? {
238
- // TODO: remove once support for RN 0.63 is dropped, since 0.64 minSdkVersion is 21
239
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
240
- context.theme.resolveAttribute(android.R.attr.selectableItemBackground, resolveOutValue, true)
241
- @Suppress("Deprecation")
242
- return resources.getDrawable(resolveOutValue.resourceId)
243
- }
244
-
245
- // Since Android 13, alpha channel in RippleDrawable is clamped between [128, 255]
246
- // see https://github.com/aosp-mirror/platform_frameworks_base/blob/c1bd0480261460584753508327ca8a0c6fc80758/graphics/java/android/graphics/drawable/RippleDrawable.java#L1012
247
- if (rippleColor == Color.TRANSPARENT && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
243
+ // don't create ripple drawable at all when it's not supposed to be visible
244
+ if (rippleColor == Color.TRANSPARENT) {
248
245
  return null
249
246
  }
250
247
 
@@ -333,13 +330,30 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
333
330
  return false
334
331
  }
335
332
 
333
+ override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
334
+ receivedKeyEvent = true
335
+ return super.onKeyUp(keyCode, event)
336
+ }
337
+
336
338
  override fun performClick(): Boolean {
337
339
  // don't preform click when a child button is pressed (mainly to prevent sound effect of
338
340
  // a parent button from playing)
339
- return if (!isChildTouched() && soundResponder == this) {
340
- tryFreeingResponder()
341
- soundResponder = null
342
- super.performClick()
341
+ return if (!isChildTouched()) {
342
+
343
+ if (context.isScreenReaderOn()) {
344
+ findGestureHandlerRootView()?.activateNativeHandlers(this)
345
+ } else if (receivedKeyEvent) {
346
+ findGestureHandlerRootView()?.activateNativeHandlers(this)
347
+ receivedKeyEvent = false
348
+ }
349
+
350
+ if (soundResponder === this) {
351
+ tryFreeingResponder()
352
+ soundResponder = null
353
+ super.performClick()
354
+ } else {
355
+ false
356
+ }
343
357
  } else {
344
358
  false
345
359
  }
@@ -356,7 +370,6 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
356
370
  soundResponder = this
357
371
  }
358
372
  }
359
-
360
373
  // button can be pressed alongside other button if both are non-exclusive and it doesn't have
361
374
  // any pressed children (to prevent pressing the parent when children is pressed).
362
375
  val canBePressedAlongsideOther = !exclusive && touchResponder?.exclusive != true && !isChildTouched()
@@ -378,6 +391,20 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
378
391
  // by default Viewgroup would pass hotspot change events
379
392
  }
380
393
 
394
+ private fun findGestureHandlerRootView(): RNGestureHandlerRootView? {
395
+ var parent: ViewParent? = this.parent
396
+ var gestureHandlerRootView: RNGestureHandlerRootView? = null
397
+
398
+ while (parent != null) {
399
+ if (parent is RNGestureHandlerRootView) {
400
+ gestureHandlerRootView = parent
401
+ }
402
+ parent = parent.parent
403
+ }
404
+
405
+ return gestureHandlerRootView
406
+ }
407
+
381
408
  companion object {
382
409
  var resolveOutValue = TypedValue()
383
410
  var touchResponder: ButtonViewGroup? = null
@@ -20,6 +20,7 @@ import com.swmansion.gesturehandler.BuildConfig
20
20
  import com.swmansion.gesturehandler.ReanimatedEventDispatcher
21
21
  import com.swmansion.gesturehandler.core.FlingGestureHandler
22
22
  import com.swmansion.gesturehandler.core.GestureHandler
23
+ import com.swmansion.gesturehandler.core.HoverGestureHandler
23
24
  import com.swmansion.gesturehandler.core.LongPressGestureHandler
24
25
  import com.swmansion.gesturehandler.core.ManualGestureHandler
25
26
  import com.swmansion.gesturehandler.core.NativeViewGestureHandler
@@ -337,6 +338,25 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
337
338
  }
338
339
  }
339
340
 
341
+ private class HoverGestureHandlerFactory : HandlerFactory<HoverGestureHandler>() {
342
+ override val type = HoverGestureHandler::class.java
343
+ override val name = "HoverGestureHandler"
344
+
345
+ override fun create(context: Context?): HoverGestureHandler {
346
+ return HoverGestureHandler()
347
+ }
348
+
349
+ override fun extractEventData(handler: HoverGestureHandler, eventData: WritableMap) {
350
+ super.extractEventData(handler, eventData)
351
+ with(eventData) {
352
+ putDouble("x", PixelUtil.toDIPFromPixel(handler.lastRelativePositionX).toDouble())
353
+ putDouble("y", PixelUtil.toDIPFromPixel(handler.lastRelativePositionY).toDouble())
354
+ putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowX).toDouble())
355
+ putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowY).toDouble())
356
+ }
357
+ }
358
+ }
359
+
340
360
  private val eventListener = object : OnTouchEventListener {
341
361
  override fun <T : GestureHandler<T>> onHandlerUpdate(handler: T, event: MotionEvent) {
342
362
  this@RNGestureHandlerModule.onHandlerUpdate(handler)
@@ -359,6 +379,7 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
359
379
  RotationGestureHandlerFactory(),
360
380
  FlingGestureHandlerFactory(),
361
381
  ManualGestureHandlerFactory(),
382
+ HoverGestureHandlerFactory(),
362
383
  )
363
384
  val registry: RNGestureHandlerRegistry = RNGestureHandlerRegistry()
364
385
  private val interactionManager = RNGestureHandlerInteractionManager()