react-native-gesture-handler 2.16.0-rc.0 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. package/android/noreanimated/src/main/java/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt +2 -0
  2. package/android/paper/src/main/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java +9 -0
  3. package/android/paper/src/main/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java +3 -0
  4. package/android/src/main/java/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt +2 -2
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/DiagonalDirections.kt +8 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt +61 -24
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +17 -22
  8. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +30 -11
  9. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +3 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt +66 -0
  11. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +119 -19
  12. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.kt +2 -2
  13. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt +1 -4
  14. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt +4 -2
  15. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt +1 -1
  16. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt +1 -4
  17. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt +4 -7
  18. package/apple/Handlers/RNLongPressHandler.m +5 -13
  19. package/apple/Handlers/RNPinchHandler.m +12 -1
  20. package/apple/RNGestureHandler.m +3 -1
  21. package/lib/commonjs/Directions.js +19 -6
  22. package/lib/commonjs/Directions.js.map +1 -1
  23. package/lib/commonjs/RNGestureHandlerModule.web.js +7 -61
  24. package/lib/commonjs/RNGestureHandlerModule.web.js.map +1 -1
  25. package/lib/commonjs/components/DrawerLayout.js.map +1 -1
  26. package/lib/commonjs/components/Swipeable.js +3 -1
  27. package/lib/commonjs/components/Swipeable.js.map +1 -1
  28. package/lib/commonjs/components/touchables/GenericTouchable.js +1 -0
  29. package/lib/commonjs/components/touchables/GenericTouchable.js.map +1 -1
  30. package/lib/commonjs/handlers/createHandler.js +2 -2
  31. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  32. package/lib/commonjs/handlers/customDirectEventTypes.js +14 -0
  33. package/lib/commonjs/handlers/customDirectEventTypes.js.map +1 -0
  34. package/lib/commonjs/handlers/customDirectEventTypes.web.js +11 -0
  35. package/lib/commonjs/handlers/customDirectEventTypes.web.js.map +1 -0
  36. package/lib/commonjs/handlers/gestureHandlerCommon.js +13 -2
  37. package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
  38. package/lib/commonjs/handlers/gestures/GestureDetector.js +10 -0
  39. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  40. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  41. package/lib/commonjs/index.js +8 -8
  42. package/lib/commonjs/index.js.map +1 -1
  43. package/lib/commonjs/mocks.js +2 -0
  44. package/lib/commonjs/mocks.js.map +1 -1
  45. package/lib/commonjs/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  46. package/lib/commonjs/web/Gestures.js +66 -0
  47. package/lib/commonjs/web/Gestures.js.map +1 -0
  48. package/lib/commonjs/web/constants.js +3 -8
  49. package/lib/commonjs/web/constants.js.map +1 -1
  50. package/lib/commonjs/web/handlers/FlingGestureHandler.js +36 -12
  51. package/lib/commonjs/web/handlers/FlingGestureHandler.js.map +1 -1
  52. package/lib/commonjs/web/handlers/GestureHandler.js +4 -2
  53. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  54. package/lib/commonjs/web/handlers/IGestureHandler.js +2 -0
  55. package/lib/commonjs/web/handlers/IGestureHandler.js.map +1 -0
  56. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +5 -6
  57. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  58. package/lib/commonjs/web/interfaces.js +1 -13
  59. package/lib/commonjs/web/interfaces.js.map +1 -1
  60. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  61. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js +114 -115
  62. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  63. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +10 -5
  64. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  65. package/lib/commonjs/web/tools/InteractionManager.js +12 -3
  66. package/lib/commonjs/web/tools/InteractionManager.js.map +1 -1
  67. package/lib/commonjs/web/tools/NodeManager.js.map +1 -1
  68. package/lib/commonjs/web/tools/PointerEventManager.js +55 -27
  69. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  70. package/lib/commonjs/web/tools/TouchEventManager.js +26 -5
  71. package/lib/commonjs/web/tools/TouchEventManager.js.map +1 -1
  72. package/lib/commonjs/web/tools/Vector.js +58 -0
  73. package/lib/commonjs/web/tools/Vector.js.map +1 -0
  74. package/lib/commonjs/web/utils.js +9 -1
  75. package/lib/commonjs/web/utils.js.map +1 -1
  76. package/lib/commonjs/web_hammer/NodeManager.js.map +1 -1
  77. package/lib/module/Directions.js +16 -4
  78. package/lib/module/Directions.js.map +1 -1
  79. package/lib/module/RNGestureHandlerModule.web.js +2 -39
  80. package/lib/module/RNGestureHandlerModule.web.js.map +1 -1
  81. package/lib/module/components/DrawerLayout.js.map +1 -1
  82. package/lib/module/components/Swipeable.js +3 -1
  83. package/lib/module/components/Swipeable.js.map +1 -1
  84. package/lib/module/components/touchables/GenericTouchable.js +1 -0
  85. package/lib/module/components/touchables/GenericTouchable.js.map +1 -1
  86. package/lib/module/handlers/createHandler.js +2 -3
  87. package/lib/module/handlers/createHandler.js.map +1 -1
  88. package/lib/module/handlers/customDirectEventTypes.js +3 -0
  89. package/lib/module/handlers/customDirectEventTypes.js.map +1 -0
  90. package/lib/module/handlers/customDirectEventTypes.web.js +5 -0
  91. package/lib/module/handlers/customDirectEventTypes.web.js.map +1 -0
  92. package/lib/module/handlers/gestureHandlerCommon.js +11 -1
  93. package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
  94. package/lib/module/handlers/gestures/GestureDetector.js +10 -0
  95. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  96. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  97. package/lib/module/index.js +1 -1
  98. package/lib/module/index.js.map +1 -1
  99. package/lib/module/mocks.js +2 -0
  100. package/lib/module/mocks.js.map +1 -1
  101. package/lib/module/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  102. package/lib/module/web/Gestures.js +39 -0
  103. package/lib/module/web/Gestures.js.map +1 -0
  104. package/lib/module/web/constants.js +1 -6
  105. package/lib/module/web/constants.js.map +1 -1
  106. package/lib/module/web/handlers/FlingGestureHandler.js +34 -12
  107. package/lib/module/web/handlers/FlingGestureHandler.js.map +1 -1
  108. package/lib/module/web/handlers/GestureHandler.js +3 -2
  109. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  110. package/lib/module/web/handlers/IGestureHandler.js +2 -0
  111. package/lib/module/web/handlers/IGestureHandler.js.map +1 -0
  112. package/lib/module/web/handlers/NativeViewGestureHandler.js +5 -6
  113. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  114. package/lib/module/web/interfaces.js +0 -11
  115. package/lib/module/web/interfaces.js.map +1 -1
  116. package/lib/module/web/tools/EventManager.js.map +1 -1
  117. package/lib/module/web/tools/GestureHandlerOrchestrator.js +114 -115
  118. package/lib/module/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  119. package/lib/module/web/tools/GestureHandlerWebDelegate.js +9 -4
  120. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  121. package/lib/module/web/tools/InteractionManager.js +9 -3
  122. package/lib/module/web/tools/InteractionManager.js.map +1 -1
  123. package/lib/module/web/tools/NodeManager.js.map +1 -1
  124. package/lib/module/web/tools/PointerEventManager.js +53 -26
  125. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  126. package/lib/module/web/tools/TouchEventManager.js +26 -5
  127. package/lib/module/web/tools/TouchEventManager.js.map +1 -1
  128. package/lib/module/web/tools/Vector.js +47 -0
  129. package/lib/module/web/tools/Vector.js.map +1 -0
  130. package/lib/module/web/utils.js +2 -0
  131. package/lib/module/web/utils.js.map +1 -1
  132. package/lib/module/web_hammer/NodeManager.js.map +1 -1
  133. package/lib/typescript/Directions.d.ts +7 -0
  134. package/lib/typescript/RNGestureHandlerModule.web.d.ts +4 -39
  135. package/lib/typescript/components/DrawerLayout.d.ts +1 -2
  136. package/lib/typescript/components/touchables/GenericTouchable.d.ts +2 -1
  137. package/lib/typescript/handlers/NativeViewGestureHandler.d.ts +1 -1
  138. package/lib/typescript/handlers/customDirectEventTypes.d.ts +1 -0
  139. package/lib/typescript/handlers/customDirectEventTypes.web.d.ts +2 -0
  140. package/lib/typescript/handlers/gestureHandlerCommon.d.ts +11 -2
  141. package/lib/typescript/handlers/gestures/GestureDetector.d.ts +2 -1
  142. package/lib/typescript/handlers/gestures/gesture.d.ts +1 -2
  143. package/lib/typescript/index.d.ts +1 -1
  144. package/lib/typescript/mocks.d.ts +1 -0
  145. package/lib/typescript/specs/RNGestureHandlerButtonNativeComponent.d.ts +4 -1
  146. package/lib/typescript/web/Gestures.d.ts +36 -0
  147. package/lib/typescript/web/constants.d.ts +1 -6
  148. package/lib/typescript/web/handlers/FlingGestureHandler.d.ts +3 -3
  149. package/lib/typescript/web/handlers/GestureHandler.d.ts +11 -9
  150. package/lib/typescript/web/handlers/IGestureHandler.d.ts +38 -0
  151. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -0
  152. package/lib/typescript/web/interfaces.d.ts +7 -10
  153. package/lib/typescript/web/tools/EventManager.d.ts +15 -12
  154. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +3 -4
  155. package/lib/typescript/web/tools/GestureHandlerOrchestrator.d.ts +7 -5
  156. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +3 -3
  157. package/lib/typescript/web/tools/InteractionManager.d.ts +6 -6
  158. package/lib/typescript/web/tools/NodeManager.d.ts +4 -3
  159. package/lib/typescript/web/tools/PointerEventManager.d.ts +11 -2
  160. package/lib/typescript/web/tools/TouchEventManager.d.ts +6 -1
  161. package/lib/typescript/web/tools/Vector.d.ts +15 -0
  162. package/lib/typescript/web/utils.d.ts +4 -4
  163. package/lib/typescript/web_hammer/NodeManager.d.ts +1 -1
  164. package/package.json +2 -1
  165. package/src/Directions.ts +21 -4
  166. package/src/RNGestureHandlerModule.web.ts +3 -44
  167. package/src/components/DrawerLayout.tsx +1 -1
  168. package/src/components/Swipeable.tsx +2 -0
  169. package/src/components/touchables/GenericTouchable.tsx +3 -0
  170. package/src/handlers/createHandler.tsx +10 -4
  171. package/src/handlers/customDirectEventTypes.ts +2 -0
  172. package/src/handlers/customDirectEventTypes.web.ts +5 -0
  173. package/src/handlers/gestureHandlerCommon.ts +28 -1
  174. package/src/handlers/gestures/GestureDetector.tsx +15 -0
  175. package/src/handlers/gestures/gesture.ts +1 -1
  176. package/src/index.ts +1 -1
  177. package/src/mocks.ts +2 -0
  178. package/src/specs/RNGestureHandlerButtonNativeComponent.ts +4 -0
  179. package/src/web/Gestures.ts +41 -0
  180. package/src/web/constants.ts +1 -7
  181. package/src/web/handlers/FlingGestureHandler.ts +54 -24
  182. package/src/web/handlers/GestureHandler.ts +14 -10
  183. package/src/web/handlers/IGestureHandler.ts +50 -0
  184. package/src/web/handlers/NativeViewGestureHandler.ts +5 -6
  185. package/src/web/interfaces.ts +13 -10
  186. package/src/web/tools/EventManager.ts +16 -14
  187. package/src/web/tools/GestureHandlerDelegate.ts +3 -4
  188. package/src/web/tools/GestureHandlerOrchestrator.ts +160 -145
  189. package/src/web/tools/GestureHandlerWebDelegate.ts +14 -9
  190. package/src/web/tools/InteractionManager.ts +18 -12
  191. package/src/web/tools/NodeManager.ts +4 -3
  192. package/src/web/tools/PointerEventManager.ts +181 -166
  193. package/src/web/tools/TouchEventManager.ts +126 -114
  194. package/src/web/tools/Vector.ts +60 -0
  195. package/src/web/utils.ts +7 -4
  196. package/src/web_hammer/NodeManager.ts +1 -1
@@ -1,5 +1,6 @@
1
1
  import { ValueOf } from '../../typeUtils';
2
- import { Gestures } from '../../RNGestureHandlerModule.web';
2
+ import { Gestures } from '../Gestures';
3
+ import type IGestureHandler from '../handlers/IGestureHandler';
3
4
 
4
5
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
5
6
  export default abstract class NodeManager {
@@ -8,9 +9,9 @@ export default abstract class NodeManager {
8
9
  InstanceType<ValueOf<typeof Gestures>>
9
10
  > = {};
10
11
 
11
- public static getHandler(tag: number) {
12
+ public static getHandler(tag: number): IGestureHandler {
12
13
  if (tag in this.gestures) {
13
- return this.gestures[tag];
14
+ return this.gestures[tag] as IGestureHandler;
14
15
  }
15
16
 
16
17
  throw new Error(`No handler for tag ${tag}`);
@@ -1,5 +1,6 @@
1
- import { AdaptedEvent, EventTypes, MouseButton } from '../interfaces';
2
1
  import EventManager from './EventManager';
2
+ import { MouseButton } from '../../handlers/gestureHandlerCommon';
3
+ import { AdaptedEvent, EventTypes, Point } from '../interfaces';
3
4
  import { PointerTypeMapping, isPointerInBounds } from '../utils';
4
5
  import { PointerType } from '../../PointerType';
5
6
 
@@ -12,6 +13,7 @@ const PointerTypes = {
12
13
  export default class PointerEventManager extends EventManager<HTMLElement> {
13
14
  private trackedPointers = new Set<number>();
14
15
  private readonly mouseButtonsMapper = new Map<number, MouseButton>();
16
+ private lastPosition: Point;
15
17
 
16
18
  constructor(view: HTMLElement) {
17
19
  super(view);
@@ -21,200 +23,213 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
21
23
  this.mouseButtonsMapper.set(2, MouseButton.RIGHT);
22
24
  this.mouseButtonsMapper.set(3, MouseButton.BUTTON_4);
23
25
  this.mouseButtonsMapper.set(4, MouseButton.BUTTON_5);
26
+
27
+ this.lastPosition = {
28
+ x: -Infinity,
29
+ y: -Infinity,
30
+ };
24
31
  }
25
32
 
26
- public setListeners(): void {
27
- this.view.addEventListener('pointerdown', (event: PointerEvent): void => {
28
- if (event.pointerType === PointerTypes.Touch) {
29
- return;
30
- }
31
- if (
32
- !isPointerInBounds(this.view, { x: event.clientX, y: event.clientY })
33
- ) {
34
- return;
35
- }
33
+ private pointerDownCallback = (event: PointerEvent) => {
34
+ if (event.pointerType === PointerTypes.Touch) {
35
+ return;
36
+ }
37
+ if (!isPointerInBounds(this.view, { x: event.clientX, y: event.clientY })) {
38
+ return;
39
+ }
40
+
41
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.DOWN);
42
+ const target = event.target as HTMLElement;
43
+
44
+ if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
45
+ target.setPointerCapture(adaptedEvent.pointerId);
46
+ }
47
+
48
+ this.markAsInBounds(adaptedEvent.pointerId);
49
+ this.trackedPointers.add(adaptedEvent.pointerId);
50
+
51
+ if (++this.activePointersCounter > 1) {
52
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
53
+ this.onPointerAdd(adaptedEvent);
54
+ } else {
55
+ this.onPointerDown(adaptedEvent);
56
+ }
57
+ };
58
+
59
+ private pointerUpCallback = (event: PointerEvent) => {
60
+ if (event.pointerType === PointerTypes.Touch) {
61
+ return;
62
+ }
63
+
64
+ // When we call reset on gesture handlers, it also resets their event managers
65
+ // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
66
+ // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
67
+ // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
68
+ if (this.activePointersCounter === 0) {
69
+ return;
70
+ }
71
+
72
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.UP);
73
+ const target = event.target as HTMLElement;
74
+
75
+ if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
76
+ target.releasePointerCapture(adaptedEvent.pointerId);
77
+ }
78
+
79
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
80
+ this.trackedPointers.delete(adaptedEvent.pointerId);
81
+
82
+ if (--this.activePointersCounter > 0) {
83
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
84
+ this.onPointerRemove(adaptedEvent);
85
+ } else {
86
+ this.onPointerUp(adaptedEvent);
87
+ }
88
+ };
89
+
90
+ private pointerMoveCallback = (event: PointerEvent) => {
91
+ if (event.pointerType === PointerTypes.Touch) {
92
+ return;
93
+ }
94
+
95
+ // Stylus triggers `pointermove` event when it detects changes in pressure. Since it is very sensitive to those changes,
96
+ // it constantly sends events, even though there was no change in position. To fix that we check whether
97
+ // pointer has actually moved and if not, we do not send event.
98
+ if (
99
+ event.pointerType === PointerTypes.Stylus &&
100
+ event.x === this.lastPosition.x &&
101
+ event.y === this.lastPosition.y
102
+ ) {
103
+ return;
104
+ }
105
+
106
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE);
107
+ const target = event.target as HTMLElement;
108
+
109
+ // You may be wondering why are we setting pointer capture here, when we
110
+ // already set it in `pointerdown` handler. Well, that's a great question,
111
+ // for which I don't have an answer. Specification (https://www.w3.org/TR/pointerevents2/#dom-element-setpointercapture)
112
+ // says that the requirement for `setPointerCapture` to work is that pointer
113
+ // must be in 'active buttons state`, otherwise it will fail silently, which
114
+ // is lovely. Obviously, when `pointerdown` is fired, one of the buttons
115
+ // (when using mouse) is pressed, but that doesn't mean that `setPointerCapture`
116
+ // will succeed, for some reason. Since it fails silently, we don't actually know
117
+ // if it worked or not (there's `gotpointercapture` event, but the complexity of
118
+ // incorporating it here seems stupid), so we just call it again here, every time
119
+ // pointer moves until it succeeds.
120
+ // God, I do love web development.
121
+ if (
122
+ !target.hasPointerCapture(event.pointerId) &&
123
+ !POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)
124
+ ) {
125
+ target.setPointerCapture(event.pointerId);
126
+ }
127
+
128
+ const inBounds: boolean = isPointerInBounds(this.view, {
129
+ x: adaptedEvent.x,
130
+ y: adaptedEvent.y,
131
+ });
36
132
 
37
- const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.DOWN);
38
- const target = event.target as HTMLElement;
133
+ const pointerIndex: number = this.pointersInBounds.indexOf(
134
+ adaptedEvent.pointerId
135
+ );
39
136
 
40
- if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
41
- target.setPointerCapture(adaptedEvent.pointerId);
137
+ if (inBounds) {
138
+ if (pointerIndex < 0) {
139
+ adaptedEvent.eventType = EventTypes.ENTER;
140
+ this.onPointerEnter(adaptedEvent);
141
+ this.markAsInBounds(adaptedEvent.pointerId);
142
+ } else {
143
+ this.onPointerMove(adaptedEvent);
42
144
  }
43
-
44
- this.markAsInBounds(adaptedEvent.pointerId);
45
- this.trackedPointers.add(adaptedEvent.pointerId);
46
-
47
- if (++this.activePointersCounter > 1) {
48
- adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
49
- this.onPointerAdd(adaptedEvent);
145
+ } else {
146
+ if (pointerIndex >= 0) {
147
+ adaptedEvent.eventType = EventTypes.LEAVE;
148
+ this.onPointerLeave(adaptedEvent);
149
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
50
150
  } else {
51
- this.onPointerDown(adaptedEvent);
151
+ this.onPointerOutOfBounds(adaptedEvent);
52
152
  }
53
- });
153
+ }
54
154
 
55
- this.view.addEventListener('pointerup', (event: PointerEvent): void => {
56
- if (event.pointerType === PointerTypes.Touch) {
57
- return;
58
- }
155
+ this.lastPosition.x = event.x;
156
+ this.lastPosition.y = event.y;
157
+ };
59
158
 
60
- // When we call reset on gesture handlers, it also resets their event managers
61
- // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
62
- // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
63
- // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
64
- if (this.activePointersCounter === 0) {
65
- return;
66
- }
159
+ private pointerCancelCallback = (event: PointerEvent) => {
160
+ if (event.pointerType === PointerTypes.Touch) {
161
+ return;
162
+ }
67
163
 
68
- const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.UP);
69
- const target = event.target as HTMLElement;
164
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
70
165
 
71
- if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
72
- target.releasePointerCapture(adaptedEvent.pointerId);
73
- }
166
+ this.onPointerCancel(adaptedEvent);
167
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
168
+ this.activePointersCounter = 0;
169
+ this.trackedPointers.clear();
170
+ };
74
171
 
75
- this.markAsOutOfBounds(adaptedEvent.pointerId);
76
- this.trackedPointers.delete(adaptedEvent.pointerId);
172
+ private pointerEnterCallback = (event: PointerEvent) => {
173
+ if (event.pointerType === PointerTypes.Touch) {
174
+ return;
175
+ }
77
176
 
78
- if (--this.activePointersCounter > 0) {
79
- adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
80
- this.onPointerRemove(adaptedEvent);
81
- } else {
82
- this.onPointerUp(adaptedEvent);
83
- }
84
- });
177
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.ENTER);
85
178
 
86
- const lastPosition: { x: number | null; y: number | null } = {
87
- x: null,
88
- y: null,
89
- };
179
+ this.onPointerMoveOver(adaptedEvent);
180
+ };
90
181
 
91
- this.view.addEventListener('pointermove', (event: PointerEvent): void => {
92
- if (event.pointerType === PointerTypes.Touch) {
93
- return;
94
- }
182
+ private pointerLeaveCallback = (event: PointerEvent) => {
183
+ if (event.pointerType === PointerTypes.Touch) {
184
+ return;
185
+ }
95
186
 
96
- // Stylus triggers `pointermove` event when it detects changes in pressure. Since it is very sensitive to those changes,
97
- // it constantly sends events, even though there was no change in position. To fix that we check whether
98
- // pointer has actually moved and if not, we do not send event.
99
- if (
100
- event.pointerType === PointerTypes.Stylus &&
101
- event.x === lastPosition.x &&
102
- event.y === lastPosition.y
103
- ) {
104
- return;
105
- }
187
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.LEAVE);
106
188
 
107
- const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE);
108
- const target = event.target as HTMLElement;
109
-
110
- // You may be wondering why are we setting pointer capture here, when we
111
- // already set it in `pointerdown` handler. Well, that's a great question,
112
- // for which I don't have an answer. Specification (https://www.w3.org/TR/pointerevents2/#dom-element-setpointercapture)
113
- // says that the requirement for `setPointerCapture` to work is that pointer
114
- // must be in 'active buttons state`, otherwise it will fail silently, which
115
- // is lovely. Obviously, when `pointerdown` is fired, one of the buttons
116
- // (when using mouse) is pressed, but that doesn't mean that `setPointerCapture`
117
- // will succeed, for some reason. Since it fails silently, we don't actually know
118
- // if it worked or not (there's `gotpointercapture` event, but the complexity of
119
- // incorporating it here seems stupid), so we just call it again here, every time
120
- // pointer moves until it succeeds.
121
- // God, I do love web development.
122
- if (
123
- !target.hasPointerCapture(event.pointerId) &&
124
- !POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)
125
- ) {
126
- target.setPointerCapture(event.pointerId);
127
- }
189
+ this.onPointerMoveOut(adaptedEvent);
190
+ };
128
191
 
129
- const inBounds: boolean = isPointerInBounds(this.view, {
130
- x: adaptedEvent.x,
131
- y: adaptedEvent.y,
132
- });
133
-
134
- const pointerIndex: number = this.pointersInBounds.indexOf(
135
- adaptedEvent.pointerId
136
- );
137
-
138
- if (inBounds) {
139
- if (pointerIndex < 0) {
140
- adaptedEvent.eventType = EventTypes.ENTER;
141
- this.onPointerEnter(adaptedEvent);
142
- this.markAsInBounds(adaptedEvent.pointerId);
143
- } else {
144
- this.onPointerMove(adaptedEvent);
145
- }
146
- } else {
147
- if (pointerIndex >= 0) {
148
- adaptedEvent.eventType = EventTypes.LEAVE;
149
- this.onPointerLeave(adaptedEvent);
150
- this.markAsOutOfBounds(adaptedEvent.pointerId);
151
- } else {
152
- this.onPointerOutOfBounds(adaptedEvent);
153
- }
154
- }
155
-
156
- lastPosition.x = event.x;
157
- lastPosition.y = event.y;
158
- });
159
-
160
- this.view.addEventListener('pointercancel', (event: PointerEvent): void => {
161
- if (event.pointerType === PointerTypes.Touch) {
162
- return;
163
- }
164
-
165
- const adaptedEvent: AdaptedEvent = this.mapEvent(
166
- event,
167
- EventTypes.CANCEL
168
- );
192
+ private lostPointerCaptureCallback = (event: PointerEvent) => {
193
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
169
194
 
195
+ if (this.trackedPointers.has(adaptedEvent.pointerId)) {
196
+ // in some cases the `pointerup` event is not fired, but `lostpointercapture` is
197
+ // we simulate the `pointercancel` event here to make sure the gesture handler stops tracking it
170
198
  this.onPointerCancel(adaptedEvent);
171
- this.markAsOutOfBounds(adaptedEvent.pointerId);
199
+
172
200
  this.activePointersCounter = 0;
173
201
  this.trackedPointers.clear();
174
- });
202
+ }
203
+ };
204
+
205
+ public registerListeners(): void {
206
+ this.view.addEventListener('pointerdown', this.pointerDownCallback);
207
+ this.view.addEventListener('pointerup', this.pointerUpCallback);
208
+ this.view.addEventListener('pointermove', this.pointerMoveCallback);
209
+ this.view.addEventListener('pointercancel', this.pointerCancelCallback);
175
210
 
176
211
  // onPointerEnter and onPointerLeave are triggered by a custom logic responsible for
177
212
  // handling shouldCancelWhenOutside flag, and are unreliable unless the pointer is down.
178
213
  // We therefore use pointerenter and pointerleave events to handle the hover gesture,
179
214
  // mapping them to onPointerMoveOver and onPointerMoveOut respectively.
180
-
181
- this.view.addEventListener('pointerenter', (event: PointerEvent): void => {
182
- if (event.pointerType === PointerTypes.Touch) {
183
- return;
184
- }
185
-
186
- const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.ENTER);
187
-
188
- this.onPointerMoveOver(adaptedEvent);
189
- });
190
-
191
- this.view.addEventListener('pointerleave', (event: PointerEvent): void => {
192
- if (event.pointerType === PointerTypes.Touch) {
193
- return;
194
- }
195
-
196
- const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.LEAVE);
197
-
198
- this.onPointerMoveOut(adaptedEvent);
199
- });
200
-
215
+ this.view.addEventListener('pointerenter', this.pointerEnterCallback);
216
+ this.view.addEventListener('pointerleave', this.pointerLeaveCallback);
201
217
  this.view.addEventListener(
202
218
  'lostpointercapture',
203
- (event: PointerEvent): void => {
204
- const adaptedEvent: AdaptedEvent = this.mapEvent(
205
- event,
206
- EventTypes.CANCEL
207
- );
208
-
209
- if (this.trackedPointers.has(adaptedEvent.pointerId)) {
210
- // in some cases the `pointerup` event is not fired, but `lostpointercapture` is
211
- // we simulate the `pointercancel` event here to make sure the gesture handler stops tracking it
212
- this.onPointerCancel(adaptedEvent);
213
-
214
- this.activePointersCounter = 0;
215
- this.trackedPointers.clear();
216
- }
217
- }
219
+ this.lostPointerCaptureCallback
220
+ );
221
+ }
222
+
223
+ public unregisterListeners(): void {
224
+ this.view.removeEventListener('pointerdown', this.pointerDownCallback);
225
+ this.view.removeEventListener('pointerup', this.pointerUpCallback);
226
+ this.view.removeEventListener('pointermove', this.pointerMoveCallback);
227
+ this.view.removeEventListener('pointercancel', this.pointerCancelCallback);
228
+ this.view.removeEventListener('pointerenter', this.pointerEnterCallback);
229
+ this.view.removeEventListener('pointerleave', this.pointerLeaveCallback);
230
+ this.view.removeEventListener(
231
+ 'lostpointercapture',
232
+ this.lostPointerCaptureCallback
218
233
  );
219
234
  }
220
235
 
@@ -4,134 +4,146 @@ import { isPointerInBounds } from '../utils';
4
4
  import { PointerType } from '../../PointerType';
5
5
 
6
6
  export default class TouchEventManager extends EventManager<HTMLElement> {
7
- public setListeners(): void {
8
- this.view.addEventListener('touchstart', (event: TouchEvent) => {
9
- for (let i = 0; i < event.changedTouches.length; ++i) {
10
- const adaptedEvent: AdaptedEvent = this.mapEvent(
11
- event,
12
- EventTypes.DOWN,
13
- i,
14
- TouchEventType.DOWN
15
- );
16
-
17
- // Here we skip stylus, because in case of anything different than touch we want to handle it by using PointerEvents
18
- // If we leave stylus to send touch events, handlers will receive every action twice
19
- if (
20
- !isPointerInBounds(this.view, {
21
- x: adaptedEvent.x,
22
- y: adaptedEvent.y,
23
- }) ||
24
- //@ts-ignore touchType field does exist
25
- event.changedTouches[i].touchType === 'stylus'
26
- ) {
27
- continue;
28
- }
29
-
30
- this.markAsInBounds(adaptedEvent.pointerId);
31
-
32
- if (++this.activePointersCounter > 1) {
33
- adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
34
- this.onPointerAdd(adaptedEvent);
35
- } else {
36
- this.onPointerDown(adaptedEvent);
37
- }
38
- }
39
- });
40
-
41
- this.view.addEventListener('touchmove', (event: TouchEvent) => {
42
- for (let i = 0; i < event.changedTouches.length; ++i) {
43
- const adaptedEvent: AdaptedEvent = this.mapEvent(
44
- event,
45
- EventTypes.MOVE,
46
- i,
47
- TouchEventType.MOVE
48
- );
49
- //@ts-ignore touchType field does exist
50
- if (event.changedTouches[i].touchType === 'stylus') {
51
- continue;
52
- }
53
-
54
- const inBounds: boolean = isPointerInBounds(this.view, {
7
+ private touchStartCallback = (event: TouchEvent): void => {
8
+ for (let i = 0; i < event.changedTouches.length; ++i) {
9
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
10
+ event,
11
+ EventTypes.DOWN,
12
+ i,
13
+ TouchEventType.DOWN
14
+ );
15
+
16
+ // Here we skip stylus, because in case of anything different than touch we want to handle it by using PointerEvents
17
+ // If we leave stylus to send touch events, handlers will receive every action twice
18
+ if (
19
+ !isPointerInBounds(this.view, {
55
20
  x: adaptedEvent.x,
56
21
  y: adaptedEvent.y,
57
- });
58
-
59
- const pointerIndex: number = this.pointersInBounds.indexOf(
60
- adaptedEvent.pointerId
61
- );
62
-
63
- if (inBounds) {
64
- if (pointerIndex < 0) {
65
- adaptedEvent.eventType = EventTypes.ENTER;
66
- this.onPointerEnter(adaptedEvent);
67
- this.markAsInBounds(adaptedEvent.pointerId);
68
- } else {
69
- this.onPointerMove(adaptedEvent);
70
- }
71
- } else {
72
- if (pointerIndex >= 0) {
73
- adaptedEvent.eventType = EventTypes.LEAVE;
74
- this.onPointerLeave(adaptedEvent);
75
- this.markAsOutOfBounds(adaptedEvent.pointerId);
76
- } else {
77
- this.onPointerOutOfBounds(adaptedEvent);
78
- }
79
- }
22
+ }) ||
23
+ //@ts-ignore touchType field does exist
24
+ event.changedTouches[i].touchType === 'stylus'
25
+ ) {
26
+ continue;
80
27
  }
81
- });
82
-
83
- this.view.addEventListener('touchend', (event: TouchEvent) => {
84
- for (let i = 0; i < event.changedTouches.length; ++i) {
85
- // When we call reset on gesture handlers, it also resets their event managers
86
- // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
87
- // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
88
- // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
89
- if (this.activePointersCounter === 0) {
90
- break;
91
- }
92
28
 
93
- //@ts-ignore touchType field does exist
94
- if (event.changedTouches[i].touchType === 'stylus') {
95
- continue;
96
- }
29
+ this.markAsInBounds(adaptedEvent.pointerId);
97
30
 
98
- const adaptedEvent: AdaptedEvent = this.mapEvent(
99
- event,
100
- EventTypes.UP,
101
- i,
102
- TouchEventType.UP
103
- );
31
+ if (++this.activePointersCounter > 1) {
32
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
33
+ this.onPointerAdd(adaptedEvent);
34
+ } else {
35
+ this.onPointerDown(adaptedEvent);
36
+ }
37
+ }
38
+ };
39
+
40
+ private touchMoveCallback = (event: TouchEvent): void => {
41
+ for (let i = 0; i < event.changedTouches.length; ++i) {
42
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
43
+ event,
44
+ EventTypes.MOVE,
45
+ i,
46
+ TouchEventType.MOVE
47
+ );
48
+ //@ts-ignore touchType field does exist
49
+ if (event.changedTouches[i].touchType === 'stylus') {
50
+ continue;
51
+ }
104
52
 
105
- this.markAsOutOfBounds(adaptedEvent.pointerId);
53
+ const inBounds: boolean = isPointerInBounds(this.view, {
54
+ x: adaptedEvent.x,
55
+ y: adaptedEvent.y,
56
+ });
106
57
 
107
- if (--this.activePointersCounter > 0) {
108
- adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
109
- this.onPointerRemove(adaptedEvent);
58
+ const pointerIndex: number = this.pointersInBounds.indexOf(
59
+ adaptedEvent.pointerId
60
+ );
61
+
62
+ if (inBounds) {
63
+ if (pointerIndex < 0) {
64
+ adaptedEvent.eventType = EventTypes.ENTER;
65
+ this.onPointerEnter(adaptedEvent);
66
+ this.markAsInBounds(adaptedEvent.pointerId);
110
67
  } else {
111
- this.onPointerUp(adaptedEvent);
68
+ this.onPointerMove(adaptedEvent);
112
69
  }
70
+ } else {
71
+ if (pointerIndex >= 0) {
72
+ adaptedEvent.eventType = EventTypes.LEAVE;
73
+ this.onPointerLeave(adaptedEvent);
74
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
75
+ } else {
76
+ this.onPointerOutOfBounds(adaptedEvent);
77
+ }
78
+ }
79
+ }
80
+ };
81
+
82
+ private touchEndCallback = (event: TouchEvent): void => {
83
+ for (let i = 0; i < event.changedTouches.length; ++i) {
84
+ // When we call reset on gesture handlers, it also resets their event managers
85
+ // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
86
+ // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
87
+ // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
88
+ if (this.activePointersCounter === 0) {
89
+ break;
90
+ }
91
+
92
+ //@ts-ignore touchType field does exist
93
+ if (event.changedTouches[i].touchType === 'stylus') {
94
+ continue;
113
95
  }
114
- });
115
96
 
116
- this.view.addEventListener('touchcancel', (event: TouchEvent) => {
117
- for (let i = 0; i < event.changedTouches.length; ++i) {
118
- const adaptedEvent: AdaptedEvent = this.mapEvent(
119
- event,
120
- EventTypes.CANCEL,
121
- i,
122
- TouchEventType.CANCELLED
123
- );
97
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
98
+ event,
99
+ EventTypes.UP,
100
+ i,
101
+ TouchEventType.UP
102
+ );
124
103
 
125
- //@ts-ignore touchType field does exist
126
- if (event.changedTouches[i].touchType === 'stylus') {
127
- continue;
128
- }
104
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
129
105
 
130
- this.onPointerCancel(adaptedEvent);
131
- this.markAsOutOfBounds(adaptedEvent.pointerId);
132
- this.activePointersCounter = 0;
106
+ if (--this.activePointersCounter > 0) {
107
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
108
+ this.onPointerRemove(adaptedEvent);
109
+ } else {
110
+ this.onPointerUp(adaptedEvent);
111
+ }
112
+ }
113
+ };
114
+
115
+ private touchCancelCallback = (event: TouchEvent): void => {
116
+ for (let i = 0; i < event.changedTouches.length; ++i) {
117
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
118
+ event,
119
+ EventTypes.CANCEL,
120
+ i,
121
+ TouchEventType.CANCELLED
122
+ );
123
+
124
+ //@ts-ignore touchType field does exist
125
+ if (event.changedTouches[i].touchType === 'stylus') {
126
+ continue;
133
127
  }
134
- });
128
+
129
+ this.onPointerCancel(adaptedEvent);
130
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
131
+ this.activePointersCounter = 0;
132
+ }
133
+ };
134
+
135
+ public registerListeners(): void {
136
+ this.view.addEventListener('touchstart', this.touchStartCallback);
137
+ this.view.addEventListener('touchmove', this.touchMoveCallback);
138
+ this.view.addEventListener('touchend', this.touchEndCallback);
139
+ this.view.addEventListener('touchcancel', this.touchCancelCallback);
140
+ }
141
+
142
+ public unregisterListeners(): void {
143
+ this.view.removeEventListener('touchstart', this.touchStartCallback);
144
+ this.view.removeEventListener('touchmove', this.touchMoveCallback);
145
+ this.view.removeEventListener('touchend', this.touchEndCallback);
146
+ this.view.removeEventListener('touchcancel', this.touchCancelCallback);
135
147
  }
136
148
 
137
149
  protected mapEvent(