react-native-gesture-handler 2.19.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/android/build.gradle +7 -12
  2. package/android/fabric/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  3. package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +11 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
  11. package/android/src/main/jni/CMakeLists.txt +18 -9
  12. package/apple/Handlers/RNLongPressHandler.m +2 -0
  13. package/apple/Handlers/RNPanHandler.m +57 -7
  14. package/apple/Handlers/RNRotationHandler.m +1 -1
  15. package/apple/RNGHStylusData.h +77 -0
  16. package/apple/RNGHStylusData.m +37 -0
  17. package/apple/RNGestureHandlerButtonComponentView.mm +35 -0
  18. package/apple/RNGestureHandlerEvents.h +3 -1
  19. package/apple/RNGestureHandlerEvents.m +11 -3
  20. package/lib/commonjs/components/GestureButtons.js +5 -1
  21. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  22. package/lib/commonjs/components/GestureComponents.js.map +1 -1
  23. package/lib/commonjs/components/Pressable/Pressable.js +5 -14
  24. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  25. package/lib/commonjs/components/Pressable/utils.js +1 -23
  26. package/lib/commonjs/components/Pressable/utils.js.map +1 -1
  27. package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
  28. package/lib/commonjs/handlers/createHandler.js +2 -1
  29. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  30. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  31. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
  32. package/lib/commonjs/jestUtils/jestUtils.js +12 -4
  33. package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
  34. package/lib/commonjs/web/handlers/GestureHandler.js +1 -3
  35. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  36. package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
  37. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
  38. package/lib/commonjs/web/handlers/PanGestureHandler.js +8 -1
  39. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  40. package/lib/commonjs/web/interfaces.js.map +1 -1
  41. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  42. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +0 -3
  43. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  44. package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
  45. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  46. package/lib/commonjs/web/utils.js +173 -0
  47. package/lib/commonjs/web/utils.js.map +1 -1
  48. package/lib/module/components/GestureButtons.js +5 -1
  49. package/lib/module/components/GestureButtons.js.map +1 -1
  50. package/lib/module/components/GestureComponents.js.map +1 -1
  51. package/lib/module/components/Pressable/Pressable.js +7 -14
  52. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  53. package/lib/module/components/Pressable/utils.js +1 -22
  54. package/lib/module/components/Pressable/utils.js.map +1 -1
  55. package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
  56. package/lib/module/handlers/createHandler.js +2 -1
  57. package/lib/module/handlers/createHandler.js.map +1 -1
  58. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  59. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
  60. package/lib/module/jestUtils/jestUtils.js +12 -4
  61. package/lib/module/jestUtils/jestUtils.js.map +1 -1
  62. package/lib/module/web/handlers/GestureHandler.js +1 -3
  63. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  64. package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
  65. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
  66. package/lib/module/web/handlers/PanGestureHandler.js +8 -1
  67. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  68. package/lib/module/web/interfaces.js.map +1 -1
  69. package/lib/module/web/tools/EventManager.js.map +1 -1
  70. package/lib/module/web/tools/GestureHandlerWebDelegate.js +0 -2
  71. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  72. package/lib/module/web/tools/PointerEventManager.js +4 -38
  73. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  74. package/lib/module/web/utils.js +170 -0
  75. package/lib/module/web/utils.js.map +1 -1
  76. package/lib/typescript/components/GestureComponents.d.ts +1 -1
  77. package/lib/typescript/components/Pressable/utils.d.ts +3 -5
  78. package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
  79. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
  80. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
  81. package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
  82. package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
  83. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
  84. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
  85. package/lib/typescript/web/interfaces.d.ts +8 -3
  86. package/lib/typescript/web/tools/EventManager.d.ts +2 -2
  87. package/lib/typescript/web/utils.d.ts +2 -1
  88. package/package.json +1 -1
  89. package/src/components/GestureButtons.tsx +2 -1
  90. package/src/components/GestureComponents.tsx +1 -1
  91. package/src/components/Pressable/Pressable.tsx +16 -29
  92. package/src/components/Pressable/utils.ts +5 -49
  93. package/src/handlers/GestureHandlerEventPayload.ts +42 -0
  94. package/src/handlers/createHandler.tsx +1 -0
  95. package/src/handlers/gestures/gesture.ts +3 -1
  96. package/src/handlers/gestures/hoverGesture.ts +1 -7
  97. package/src/jestUtils/jestUtils.ts +9 -1
  98. package/src/web/handlers/GestureHandler.ts +1 -1
  99. package/src/web/handlers/HoverGestureHandler.ts +16 -2
  100. package/src/web/handlers/PanGestureHandler.ts +10 -1
  101. package/src/web/interfaces.ts +9 -3
  102. package/src/web/tools/EventManager.ts +2 -4
  103. package/src/web/tools/GestureHandlerWebDelegate.ts +0 -2
  104. package/src/web/tools/PointerEventManager.ts +2 -38
  105. package/src/web/utils.ts +174 -1
  106. package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
  107. package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
  108. package/lib/module/web/tools/TouchEventManager.js +0 -149
  109. package/lib/module/web/tools/TouchEventManager.js.map +0 -1
  110. package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
  111. package/src/web/tools/TouchEventManager.ts +0 -175
@@ -33,16 +33,10 @@ def resolveReactNativeDirectory() {
33
33
  return file(reactNativeLocation)
34
34
  }
35
35
 
36
- // monorepo workaround
37
- // react-native can be hoisted or in project's own node_modules
38
- def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native")
39
- if (reactNativeFromProjectNodeModules.exists()) {
40
- return reactNativeFromProjectNodeModules
41
- }
42
-
43
- def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native")
44
- if (reactNativeFromNodeModulesWithReanimated.exists()) {
45
- return reactNativeFromNodeModulesWithReanimated
36
+ // Fallback to node resolver for custom directory structures like monorepos.
37
+ def reactNativePackage = file(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim())
38
+ if (reactNativePackage.exists()) {
39
+ return reactNativePackage.parentFile
46
40
  }
47
41
 
48
42
  throw new Exception(
@@ -124,8 +118,7 @@ android {
124
118
  externalNativeBuild {
125
119
  cmake {
126
120
  cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++20", "-DANDROID"
127
- arguments "-DAPP_BUILD_DIR=${appProject.buildDir}",
128
- "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
121
+ arguments "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
129
122
  "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
130
123
  "-DANDROID_STL=c++_shared"
131
124
  abiFilters (*reactNativeArchitectures())
@@ -153,6 +146,8 @@ android {
153
146
  // only the ones that make the build fail (ideally we should only include libgesturehandler but we
154
147
  // are only allowed to specify exclude patterns)
155
148
  exclude "**/libreact_render*.so"
149
+ exclude "**/libreactnative.so"
150
+ exclude "**/libjsi.so"
156
151
  }
157
152
 
158
153
  sourceSets.main {
@@ -8,5 +8,5 @@ import com.facebook.react.uimanager.events.Event
8
8
 
9
9
  fun ReactContext.dispatchEvent(event: Event<*>) {
10
10
  val fabricUIManager = UIManagerHelper.getUIManager(this, UIManagerType.FABRIC) as FabricUIManager
11
- fabricUIManager.eventDispatcher.dispatchEvent(event)
11
+ fabricUIManager.getEventDispatcher().dispatchEvent(event)
12
12
  }
@@ -6,7 +6,7 @@ import com.facebook.react.uimanager.events.Event
6
6
 
7
7
  fun ReactContext.dispatchEvent(event: Event<*>) {
8
8
  try {
9
- this.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher.dispatchEvent(event)
9
+ this.getNativeModule(UIManagerModule::class.java)!!.getEventDispatcher().dispatchEvent(event)
10
10
  } catch (e: NullPointerException) {
11
11
  throw Exception("Couldn't get an instance of UIManagerModule. Gesture Handler is unable to send an event.", e)
12
12
  }
@@ -45,6 +45,7 @@ object GestureUtils {
45
45
  event.getY(lastPointerIdx)
46
46
  }
47
47
  }
48
+
48
49
  fun coneToDeviation(angle: Double): Double =
49
50
  cos(Math.toRadians(angle / 2.0))
50
51
  }
@@ -11,6 +11,8 @@ import com.swmansion.gesturehandler.react.RNViewConfigurationHelper
11
11
  class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
12
12
  private var handler: Handler? = null
13
13
  private var finishRunnable = Runnable { finish() }
14
+ var stylusData: StylusData = StylusData()
15
+ private set
14
16
 
15
17
  private infix fun isAncestorOf(other: GestureHandler<*>): Boolean {
16
18
  var current: View? = other.view
@@ -103,6 +105,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
103
105
  finish()
104
106
  }
105
107
 
108
+ this.state == STATE_ACTIVE && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS -> {
109
+ stylusData = StylusData.fromEvent(event)
110
+ }
111
+
106
112
  this.state == STATE_UNDETERMINED &&
107
113
  (event.action == MotionEvent.ACTION_HOVER_MOVE || event.action == MotionEvent.ACTION_HOVER_ENTER) -> {
108
114
  begin()
@@ -111,6 +117,11 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
111
117
  }
112
118
  }
113
119
 
120
+ override fun onReset() {
121
+ super.onReset()
122
+ stylusData = StylusData()
123
+ }
124
+
114
125
  private fun finish() {
115
126
  when (this.state) {
116
127
  STATE_UNDETERMINED -> cancel()
@@ -45,6 +45,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
45
45
  private var activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS
46
46
  private val activateDelayed = Runnable { activate() }
47
47
  private var handler: Handler? = null
48
+ var stylusData: StylusData = StylusData()
49
+ private set
48
50
 
49
51
  /**
50
52
  * On Android when there are multiple pointers on the screen pan gestures most often just consider
@@ -212,6 +214,10 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
212
214
  return
213
215
  }
214
216
 
217
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
218
+ stylusData = StylusData.fromEvent(event)
219
+ }
220
+
215
221
  val state = state
216
222
  val action = sourceEvent.actionMasked
217
223
  if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
@@ -295,6 +301,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
295
301
  it.recycle()
296
302
  velocityTracker = null
297
303
  }
304
+
305
+ stylusData = StylusData()
298
306
  }
299
307
 
300
308
  override fun resetProgress() {
@@ -0,0 +1,103 @@
1
+ package com.swmansion.gesturehandler.core
2
+
3
+ import android.view.MotionEvent
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import kotlin.math.PI
7
+ import kotlin.math.abs
8
+ import kotlin.math.atan
9
+ import kotlin.math.cos
10
+ import kotlin.math.round
11
+ import kotlin.math.sin
12
+ import kotlin.math.tan
13
+
14
+ data class StylusData(
15
+ val tiltX: Double = 0.0,
16
+ val tiltY: Double = 0.0,
17
+ val altitudeAngle: Double = 0.0,
18
+ val azimuthAngle: Double = 0.0,
19
+ val pressure: Double = -1.0
20
+ ) {
21
+ fun toReadableMap(): ReadableMap {
22
+ val stylusDataObject = Arguments.createMap().apply {
23
+ putDouble("tiltX", tiltX)
24
+ putDouble("tiltY", tiltY)
25
+ putDouble("altitudeAngle", altitudeAngle)
26
+ putDouble("azimuthAngle", azimuthAngle)
27
+ putDouble("pressure", pressure)
28
+ }
29
+
30
+ val readableStylusData: ReadableMap = stylusDataObject
31
+
32
+ return readableStylusData
33
+ }
34
+
35
+ companion object {
36
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
37
+ private fun spherical2tilt(altitudeAngle: Double, azimuthAngle: Double): Pair<Double, Double> {
38
+ val eps = 0.000000001
39
+ val radToDeg = 180 / PI
40
+
41
+ var tiltXrad = 0.0
42
+ var tiltYrad = 0.0
43
+
44
+ if (altitudeAngle < eps) {
45
+ // the pen is in the X-Y plane
46
+ if (azimuthAngle < eps || abs(azimuthAngle - 2 * PI) < eps) {
47
+ // pen is on positive X axis
48
+ tiltXrad = PI / 2
49
+ }
50
+ if (abs(azimuthAngle - PI / 2) < eps) {
51
+ // pen is on positive Y axis
52
+ tiltYrad = PI / 2
53
+ }
54
+ if (abs(azimuthAngle - PI) < eps) {
55
+ // pen is on negative X axis
56
+ tiltXrad = -PI / 2
57
+ }
58
+ if (abs(azimuthAngle - (3 * PI) / 2) < eps) {
59
+ // pen is on negative Y axis
60
+ tiltYrad = -PI / 2
61
+ }
62
+ if (azimuthAngle > eps && abs(azimuthAngle - PI / 2) < eps) {
63
+ tiltXrad = PI / 2
64
+ tiltYrad = PI / 2
65
+ }
66
+ if (abs(azimuthAngle - PI / 2) > eps && abs(azimuthAngle - PI) < eps) {
67
+ tiltXrad = -PI / 2
68
+ tiltYrad = PI / 2
69
+ }
70
+ if (abs(azimuthAngle - PI) > eps && abs(azimuthAngle - (3 * PI) / 2) < eps) {
71
+ tiltXrad = -PI / 2
72
+ tiltYrad = -PI / 2
73
+ }
74
+ if (abs(azimuthAngle - (3 * PI) / 2) > eps && abs(azimuthAngle - 2 * PI) < eps) {
75
+ tiltXrad = PI / 2
76
+ tiltYrad = -PI / 2
77
+ }
78
+ } else {
79
+ val tanAlt = tan(altitudeAngle)
80
+
81
+ tiltXrad = atan(cos(azimuthAngle) / tanAlt)
82
+ tiltYrad = atan(sin(azimuthAngle) / tanAlt)
83
+ }
84
+
85
+ val tiltX = round(tiltXrad * radToDeg)
86
+ val tiltY = round(tiltYrad * radToDeg)
87
+
88
+ return Pair(tiltX, tiltY)
89
+ }
90
+
91
+ fun fromEvent(event: MotionEvent): StylusData {
92
+ // On web and iOS 0 degrees means that stylus is parallel to the surface. On android this value will be PI / 2.
93
+ val altitudeAngle = (PI / 2) - event.getAxisValue(MotionEvent.AXIS_TILT).toDouble()
94
+ val pressure = event.getPressure(0).toDouble()
95
+ val orientation = event.getOrientation(0).toDouble()
96
+ // To get azimuth angle, we need to use orientation property (https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features#orientation).
97
+ val azimuthAngle = (orientation + PI / 2).mod(2 * PI)
98
+ val tilts = spherical2tilt(altitudeAngle, azimuthAngle)
99
+
100
+ return StylusData(tilts.first, tilts.second, altitudeAngle, azimuthAngle, pressure)
101
+ }
102
+ }
103
+ }
@@ -286,22 +286,11 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
286
286
  return false
287
287
  }
288
288
 
289
- private fun updateBackgroundColor(backgroundColor: Int, selectable: Drawable?) {
289
+ private fun updateBackgroundColor(backgroundColor: Int, borderDrawable: Drawable, selectable: Drawable?) {
290
290
  val colorDrawable = PaintDrawable(backgroundColor)
291
- val borderDrawable = PaintDrawable(Color.TRANSPARENT)
292
291
 
293
292
  if (hasBorderRadii) {
294
293
  colorDrawable.setCornerRadii(buildBorderRadii())
295
- borderDrawable.setCornerRadii(buildBorderRadii())
296
- }
297
-
298
- if (borderWidth > 0f) {
299
- borderDrawable.paint.apply {
300
- style = Paint.Style.STROKE
301
- strokeWidth = borderWidth
302
- color = borderColor ?: Color.BLACK
303
- pathEffect = buildBorderStyle()
304
- }
305
294
  }
306
295
 
307
296
  val layerDrawable = LayerDrawable(if (selectable != null) arrayOf(colorDrawable, selectable, borderDrawable) else arrayOf(colorDrawable, borderDrawable))
@@ -324,6 +313,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
324
313
  }
325
314
 
326
315
  val selectable = createSelectableDrawable()
316
+ val borderDrawable = createBorderDrawable()
327
317
 
328
318
  if (hasBorderRadii && selectable is RippleDrawable) {
329
319
  val mask = PaintDrawable(Color.WHITE)
@@ -334,13 +324,32 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
334
324
  if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
335
325
  foreground = selectable
336
326
  if (_backgroundColor != Color.TRANSPARENT) {
337
- updateBackgroundColor(_backgroundColor, null)
327
+ updateBackgroundColor(_backgroundColor, borderDrawable, null)
338
328
  }
339
329
  } else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) {
340
- background = selectable
330
+ background = LayerDrawable(arrayOf(selectable, borderDrawable))
341
331
  } else {
342
- updateBackgroundColor(_backgroundColor, selectable)
332
+ updateBackgroundColor(_backgroundColor, borderDrawable, selectable)
333
+ }
334
+ }
335
+
336
+ private fun createBorderDrawable(): Drawable {
337
+ val borderDrawable = PaintDrawable(Color.TRANSPARENT)
338
+
339
+ if (hasBorderRadii) {
340
+ borderDrawable.setCornerRadii(buildBorderRadii())
341
+ }
342
+
343
+ if (borderWidth > 0f) {
344
+ borderDrawable.paint.apply {
345
+ style = Paint.Style.STROKE
346
+ strokeWidth = borderWidth
347
+ color = borderColor ?: Color.BLACK
348
+ pathEffect = buildBorderStyle()
349
+ }
343
350
  }
351
+
352
+ return borderDrawable
344
353
  }
345
354
 
346
355
  private fun createSelectableDrawable(): Drawable? {
@@ -3,18 +3,21 @@ package com.swmansion.gesturehandler.react.eventbuilders
3
3
  import com.facebook.react.bridge.WritableMap
4
4
  import com.facebook.react.uimanager.PixelUtil
5
5
  import com.swmansion.gesturehandler.core.HoverGestureHandler
6
+ import com.swmansion.gesturehandler.core.StylusData
6
7
 
7
8
  class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : GestureHandlerEventDataBuilder<HoverGestureHandler>(handler) {
8
9
  private val x: Float
9
10
  private val y: Float
10
11
  private val absoluteX: Float
11
12
  private val absoluteY: Float
13
+ private val stylusData: StylusData
12
14
 
13
15
  init {
14
16
  x = handler.lastRelativePositionX
15
17
  y = handler.lastRelativePositionY
16
18
  absoluteX = handler.lastPositionInWindowX
17
19
  absoluteY = handler.lastPositionInWindowY
20
+ stylusData = handler.stylusData
18
21
  }
19
22
 
20
23
  override fun buildEventData(eventData: WritableMap) {
@@ -25,6 +28,10 @@ class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : Gestur
25
28
  putDouble("y", PixelUtil.toDIPFromPixel(y).toDouble())
26
29
  putDouble("absoluteX", PixelUtil.toDIPFromPixel(absoluteX).toDouble())
27
30
  putDouble("absoluteY", PixelUtil.toDIPFromPixel(absoluteY).toDouble())
31
+
32
+ if (stylusData.pressure != -1.0) {
33
+ putMap("stylusData", stylusData.toReadableMap())
34
+ }
28
35
  }
29
36
  }
30
37
  }
@@ -3,6 +3,7 @@ package com.swmansion.gesturehandler.react.eventbuilders
3
3
  import com.facebook.react.bridge.WritableMap
4
4
  import com.facebook.react.uimanager.PixelUtil
5
5
  import com.swmansion.gesturehandler.core.PanGestureHandler
6
+ import com.swmansion.gesturehandler.core.StylusData
6
7
 
7
8
  class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHandlerEventDataBuilder<PanGestureHandler>(handler) {
8
9
  private val x: Float
@@ -13,6 +14,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
13
14
  private val translationY: Float
14
15
  private val velocityX: Float
15
16
  private val velocityY: Float
17
+ private val stylusData: StylusData
16
18
 
17
19
  init {
18
20
  x = handler.lastRelativePositionX
@@ -23,6 +25,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
23
25
  translationY = handler.translationY
24
26
  velocityX = handler.velocityX
25
27
  velocityY = handler.velocityY
28
+ stylusData = handler.stylusData
26
29
  }
27
30
 
28
31
  override fun buildEventData(eventData: WritableMap) {
@@ -37,6 +40,10 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
37
40
  putDouble("translationY", PixelUtil.toDIPFromPixel(translationY).toDouble())
38
41
  putDouble("velocityX", PixelUtil.toDIPFromPixel(velocityX).toDouble())
39
42
  putDouble("velocityY", PixelUtil.toDIPFromPixel(velocityY).toDouble())
43
+
44
+ if (stylusData.pressure != -1.0) {
45
+ putMap("stylusData", stylusData.toReadableMap())
46
+ }
40
47
  }
41
48
  }
42
49
  }
@@ -26,12 +26,21 @@ target_include_directories(
26
26
  )
27
27
 
28
28
  find_package(ReactAndroid REQUIRED CONFIG)
29
-
30
- target_link_libraries(
31
- gesturehandler
32
- ReactAndroid::react_render_core
33
- ReactAndroid::react_render_uimanager
34
- ReactAndroid::react_render_graphics
35
- ReactAndroid::jsi
36
- ReactAndroid::react_nativemodule_core
37
- )
29
+ if (ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
30
+ target_link_libraries(
31
+ ${PACKAGE_NAME}
32
+ ReactAndroid::reactnative
33
+ ReactAndroid::jsi
34
+ )
35
+ elseif (ReactAndroid_VERSION_MINOR GREATER_EQUAL 75)
36
+ target_link_libraries(
37
+ ${PACKAGE_NAME}
38
+ ReactAndroid::react_render_core
39
+ ReactAndroid::react_render_uimanager
40
+ ReactAndroid::react_render_graphics
41
+ ReactAndroid::jsi
42
+ ReactAndroid::react_nativemodule_core
43
+ )
44
+ else ()
45
+ message(FATAL_ERROR "react-native-gesture-handler on the New Architecture requires react-native 0.75 or newer.")
46
+ endif ()
@@ -233,10 +233,12 @@
233
233
  recognizer.allowableMovement = [RCTConvert CGFloat:prop];
234
234
  }
235
235
 
236
+ #if !TARGET_OS_TV
236
237
  prop = config[@"numberOfPointers"];
237
238
  if (prop != nil) {
238
239
  recognizer.numberOfTouchesRequired = [RCTConvert CGFloat:prop];
239
240
  }
241
+ #endif
240
242
  }
241
243
 
242
244
  #if !TARGET_OS_OSX
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  #import "RNPanHandler.h"
10
+ #import "RNGHStylusData.h"
10
11
 
11
12
  #if TARGET_OS_OSX
12
13
 
@@ -31,6 +32,10 @@
31
32
  @property (nonatomic) CGFloat failOffsetYEnd;
32
33
  @property (nonatomic) CGFloat activateAfterLongPress;
33
34
 
35
+ #if !TARGET_OS_OSX && !TARGET_OS_TV
36
+ @property (atomic, readonly, strong) RNGHStylusData *stylusData;
37
+ #endif
38
+
34
39
  - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler;
35
40
 
36
41
  @end
@@ -80,6 +85,28 @@
80
85
  }
81
86
  #endif
82
87
 
88
+ #if !TARGET_OS_OSX && !TARGET_OS_TV
89
+ - (void)tryUpdateStylusData:(UIEvent *)event
90
+ {
91
+ UITouch *touch = [[event allTouches] anyObject];
92
+
93
+ if (touch.type != UITouchTypePencil) {
94
+ return;
95
+ } else if (_stylusData == nil) {
96
+ _stylusData = [[RNGHStylusData alloc] init];
97
+ }
98
+
99
+ _stylusData.altitudeAngle = touch.altitudeAngle;
100
+ _stylusData.azimuthAngle = [touch azimuthAngleInView:nil];
101
+ _stylusData.pressure = touch.force / touch.maximumPossibleForce;
102
+
103
+ CGPoint tilts = ghSpherical2tilt(_stylusData.altitudeAngle, _stylusData.azimuthAngle);
104
+
105
+ _stylusData.tiltX = tilts.x;
106
+ _stylusData.tiltY = tilts.y;
107
+ }
108
+ #endif
109
+
83
110
  - (void)activateAfterLongPress
84
111
  {
85
112
  self.state = UIGestureRecognizerStateBegan;
@@ -102,6 +129,8 @@
102
129
  } else {
103
130
  super.minimumNumberOfTouches = _realMinimumNumberOfTouches;
104
131
  }
132
+
133
+ [self tryUpdateStylusData:event];
105
134
  #endif
106
135
 
107
136
  #if TARGET_OS_OSX
@@ -150,17 +179,28 @@
150
179
  [self setTranslation:CGPointMake(0, 0) inView:self.view];
151
180
  }
152
181
  }
182
+
183
+ [self tryUpdateStylusData:event];
153
184
  #endif
154
185
  }
155
186
 
156
187
  - (void)interactionsEnded:(NSSet *)touches withEvent:(UIEvent *)event
157
188
  {
158
189
  [_gestureHandler.pointerTracker touchesEnded:touches withEvent:event];
190
+
191
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
192
+ [self tryUpdateStylusData:event];
193
+ #endif
159
194
  }
160
195
 
161
196
  - (void)interactionsCancelled:(NSSet *)touches withEvent:(UIEvent *)event
162
197
  {
163
198
  [_gestureHandler.pointerTracker touchesCancelled:touches withEvent:event];
199
+
200
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
201
+ [self tryUpdateStylusData:event];
202
+ #endif
203
+
164
204
  [self reset];
165
205
  }
166
206
 
@@ -224,6 +264,10 @@
224
264
  self.enabled = YES;
225
265
  [super reset];
226
266
  [_gestureHandler reset];
267
+
268
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
269
+ _stylusData = nil;
270
+ #endif
227
271
  }
228
272
 
229
273
  - (void)updateHasCustomActivationCriteria
@@ -405,17 +449,23 @@
405
449
  withTranslation:[recognizer translationInView:recognizer.view.window.contentView]
406
450
  withVelocity:[recognizer velocityInView:recognizer.view.window.contentView]
407
451
  withNumberOfTouches:1
408
- withPointerType:RNGestureHandlerMouse];
452
+ withPointerType:RNGestureHandlerMouse
453
+ withStylusData:nil];
409
454
  }
410
455
  #else
411
456
  - (RNGestureHandlerEventExtraData *)eventExtraData:(UIPanGestureRecognizer *)recognizer
412
457
  {
413
- return [RNGestureHandlerEventExtraData forPan:[recognizer locationInView:recognizer.view]
414
- withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
415
- withTranslation:[recognizer translationInView:recognizer.view.window]
416
- withVelocity:[recognizer velocityInView:recognizer.view.window]
417
- withNumberOfTouches:recognizer.numberOfTouches
418
- withPointerType:_pointerType];
458
+ RNBetterPanGestureRecognizer *panRecognizer = (RNBetterPanGestureRecognizer *)recognizer;
459
+
460
+ return [RNGestureHandlerEventExtraData
461
+ forPan:[recognizer locationInView:recognizer.view]
462
+ withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
463
+ withTranslation:[recognizer translationInView:recognizer.view.window]
464
+ withVelocity:[recognizer velocityInView:recognizer.view.window]
465
+ withNumberOfTouches:recognizer.numberOfTouches
466
+ withPointerType:_pointerType
467
+ withStylusData:[panRecognizer.stylusData toDictionary]]; // In Objective-C calling method on nil returns
468
+ // nil, therefore this line does not crash.
419
469
  }
420
470
  #endif
421
471
 
@@ -149,7 +149,7 @@
149
149
  #if TARGET_OS_OSX
150
150
  - (RNGestureHandlerEventExtraData *)eventExtraData:(NSRotationGestureRecognizer *)recognizer
151
151
  {
152
- return [RNGestureHandlerEventExtraData forRotation:recognizer.rotation
152
+ return [RNGestureHandlerEventExtraData forRotation:-recognizer.rotation
153
153
  withAnchorPoint:[recognizer locationInView:recognizer.view]
154
154
  withVelocity:((RNBetterRotationRecognizer *)recognizer).velocity
155
155
  withNumberOfTouches:2
@@ -0,0 +1,77 @@
1
+ //
2
+ // RNGHStylusData.h
3
+ // Pods
4
+ //
5
+ // Created by Michał Bert on 18/09/2024.
6
+ //
7
+
8
+ #ifndef RNGHStylusData_h
9
+ #define RNGHStylusData_h
10
+
11
+ @interface RNGHStylusData : NSObject
12
+
13
+ @property (atomic, assign) double tiltX;
14
+ @property (atomic, assign) double tiltY;
15
+ @property (atomic, assign) double altitudeAngle;
16
+ @property (atomic, assign) double azimuthAngle;
17
+ @property (atomic, assign) double pressure;
18
+
19
+ - (NSDictionary *)toDictionary;
20
+
21
+ @end
22
+
23
+ static CGPoint ghSpherical2tilt(double altitudeAngle, double azimuthAngle)
24
+ {
25
+ CGPoint tilts = {.x = 0.0, .y = 0.0};
26
+
27
+ const double radToDeg = 180 / M_PI;
28
+ const double eps = 0.000000001;
29
+
30
+ if (altitudeAngle < eps) {
31
+ // the pen is in the X-Y plane
32
+ if (azimuthAngle < eps || fabs(azimuthAngle - 2 * M_PI) < eps) {
33
+ // pen is on positive X axis
34
+ tilts.x = M_PI_2;
35
+ }
36
+ if (fabs(azimuthAngle - M_PI_2) < eps) {
37
+ // pen is on positive Y axis
38
+ tilts.y = M_PI_2;
39
+ }
40
+ if (fabs(azimuthAngle - M_PI) < eps) {
41
+ // pen is on negative X axis
42
+ tilts.x = -M_PI_2;
43
+ }
44
+ if (fabs(azimuthAngle - 3 * M_PI_2) < eps) {
45
+ // pen is on negative Y axis
46
+ tilts.y = -M_PI_2;
47
+ }
48
+ if (azimuthAngle > eps && fabs(azimuthAngle - M_PI_2) < eps) {
49
+ tilts.x = M_PI_2;
50
+ tilts.y = M_PI_2;
51
+ }
52
+ if (fabs(azimuthAngle - M_PI_2) > eps && fabs(azimuthAngle - M_PI) < eps) {
53
+ tilts.x = -M_PI_2;
54
+ tilts.y = M_PI_2;
55
+ }
56
+ if (azimuthAngle - M_PI > eps && fabs(azimuthAngle - 3 * M_PI_2) < eps) {
57
+ tilts.x = -M_PI_2;
58
+ tilts.y = -M_PI_2;
59
+ }
60
+ if (fabs(azimuthAngle - 3 * M_PI_2) > eps && fabs(azimuthAngle - 2 * M_PI) < eps) {
61
+ tilts.x = M_PI_2;
62
+ tilts.y = -M_PI_2;
63
+ }
64
+ } else {
65
+ const double tanAlt = tan(altitudeAngle);
66
+
67
+ tilts.x = atan(cos(azimuthAngle) / tanAlt);
68
+ tilts.y = atan(sin(azimuthAngle) / tanAlt);
69
+ }
70
+
71
+ tilts.x = round(tilts.x * radToDeg);
72
+ tilts.y = round(tilts.y * radToDeg);
73
+
74
+ return tilts;
75
+ }
76
+
77
+ #endif /* RNGHStylusData_h */
@@ -0,0 +1,37 @@
1
+ //
2
+ // RNGHStylusData.m
3
+ // DoubleConversion
4
+ //
5
+ // Created by Michał Bert on 18/09/2024.
6
+ //
7
+
8
+ #import "RNGHStylusData.h"
9
+ #import <Foundation/Foundation.h>
10
+
11
+ @implementation RNGHStylusData
12
+
13
+ - (instancetype)init
14
+ {
15
+ if (self = [super init]) {
16
+ self.tiltX = 0;
17
+ self.tiltY = 0;
18
+ self.altitudeAngle = M_PI_2;
19
+ self.azimuthAngle = 0;
20
+ self.pressure = 0;
21
+ }
22
+
23
+ return self;
24
+ }
25
+
26
+ - (NSDictionary *)toDictionary
27
+ {
28
+ return @{
29
+ @"tiltX" : @(_tiltX),
30
+ @"tiltY" : @(_tiltY),
31
+ @"altitudeAngle" : @(_altitudeAngle),
32
+ @"azimuthAngle" : @(_azimuthAngle),
33
+ @"pressure" : @(_pressure),
34
+ };
35
+ }
36
+
37
+ @end