react-native-gesture-handler 2.18.1 → 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 (210) hide show
  1. package/README.md +1 -0
  2. package/android/build.gradle +11 -29
  3. package/android/fabric/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  4. package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  5. package/android/src/main/AndroidManifest.xml +1 -3
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +21 -21
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +2 -2
  8. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
  9. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +16 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +80 -4
  11. package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
  12. package/android/src/main/java/com/swmansion/gesturehandler/core/PinchGestureHandler.kt +2 -1
  13. package/android/src/main/java/com/swmansion/gesturehandler/core/ScaleGestureDetector.java +10 -0
  14. package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
  15. package/android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt +2 -2
  16. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
  17. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +3 -0
  18. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
  19. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
  20. package/android/src/main/jni/CMakeLists.txt +18 -9
  21. package/apple/Handlers/RNFlingHandler.h +1 -0
  22. package/apple/Handlers/RNFlingHandler.m +153 -19
  23. package/apple/Handlers/RNHoverHandler.m +44 -2
  24. package/apple/Handlers/RNLongPressHandler.m +111 -20
  25. package/apple/Handlers/RNManualHandler.m +53 -29
  26. package/apple/Handlers/RNNativeViewHandler.mm +22 -15
  27. package/apple/Handlers/RNPanHandler.m +57 -7
  28. package/apple/Handlers/RNRotationHandler.m +1 -1
  29. package/apple/RNGHStylusData.h +77 -0
  30. package/apple/RNGHStylusData.m +37 -0
  31. package/apple/RNGHUIKit.h +2 -0
  32. package/apple/RNGHVector.h +31 -0
  33. package/apple/RNGHVector.m +67 -0
  34. package/apple/RNGestureHandler.h +7 -0
  35. package/apple/{RNGestureHandler.m → RNGestureHandler.mm} +63 -1
  36. package/apple/RNGestureHandlerButtonComponentView.mm +41 -0
  37. package/apple/RNGestureHandlerDirection.h +25 -0
  38. package/apple/RNGestureHandlerEvents.h +3 -1
  39. package/apple/RNGestureHandlerEvents.m +11 -3
  40. package/lib/commonjs/PointerType.js +2 -1
  41. package/lib/commonjs/PointerType.js.map +1 -1
  42. package/lib/commonjs/components/GestureButtons.js +5 -1
  43. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  44. package/lib/commonjs/components/GestureComponents.js.map +1 -1
  45. package/lib/commonjs/components/Pressable/Pressable.js +66 -78
  46. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  47. package/lib/commonjs/components/Pressable/index.js +0 -8
  48. package/lib/commonjs/components/Pressable/index.js.map +1 -1
  49. package/lib/commonjs/components/Pressable/utils.js +1 -23
  50. package/lib/commonjs/components/Pressable/utils.js.map +1 -1
  51. package/lib/commonjs/components/ReanimatedSwipeable.js +60 -41
  52. package/lib/commonjs/components/ReanimatedSwipeable.js.map +1 -1
  53. package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
  54. package/lib/commonjs/handlers/LongPressGestureHandler.js +1 -1
  55. package/lib/commonjs/handlers/LongPressGestureHandler.js.map +1 -1
  56. package/lib/commonjs/handlers/createHandler.js +2 -1
  57. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  58. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js +1 -1
  59. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js.map +1 -1
  60. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  61. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
  62. package/lib/commonjs/handlers/gestures/longPressGesture.js +10 -0
  63. package/lib/commonjs/handlers/gestures/longPressGesture.js.map +1 -1
  64. package/lib/commonjs/jestUtils/jestUtils.js +12 -4
  65. package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
  66. package/lib/commonjs/mocks.js +16 -3
  67. package/lib/commonjs/mocks.js.map +1 -1
  68. package/lib/commonjs/utils.js +4 -0
  69. package/lib/commonjs/utils.js.map +1 -1
  70. package/lib/commonjs/web/constants.js +3 -3
  71. package/lib/commonjs/web/constants.js.map +1 -1
  72. package/lib/commonjs/web/handlers/GestureHandler.js +2 -3
  73. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  74. package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
  75. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
  76. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +43 -9
  77. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  78. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +14 -3
  79. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  80. package/lib/commonjs/web/handlers/PanGestureHandler.js +12 -1
  81. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  82. package/lib/commonjs/web/interfaces.js.map +1 -1
  83. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  84. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +55 -11
  85. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  86. package/lib/commonjs/web/tools/KeyboardEventManager.js +110 -0
  87. package/lib/commonjs/web/tools/KeyboardEventManager.js.map +1 -0
  88. package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
  89. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  90. package/lib/commonjs/web/tools/Vector.js +4 -2
  91. package/lib/commonjs/web/tools/Vector.js.map +1 -1
  92. package/lib/commonjs/web/utils.js +187 -13
  93. package/lib/commonjs/web/utils.js.map +1 -1
  94. package/lib/module/PointerType.js +2 -1
  95. package/lib/module/PointerType.js.map +1 -1
  96. package/lib/module/components/GestureButtons.js +5 -1
  97. package/lib/module/components/GestureButtons.js.map +1 -1
  98. package/lib/module/components/GestureComponents.js.map +1 -1
  99. package/lib/module/components/Pressable/Pressable.js +67 -78
  100. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  101. package/lib/module/components/Pressable/index.js +0 -1
  102. package/lib/module/components/Pressable/index.js.map +1 -1
  103. package/lib/module/components/Pressable/utils.js +1 -22
  104. package/lib/module/components/Pressable/utils.js.map +1 -1
  105. package/lib/module/components/ReanimatedSwipeable.js +58 -37
  106. package/lib/module/components/ReanimatedSwipeable.js.map +1 -1
  107. package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
  108. package/lib/module/handlers/LongPressGestureHandler.js +1 -1
  109. package/lib/module/handlers/LongPressGestureHandler.js.map +1 -1
  110. package/lib/module/handlers/createHandler.js +2 -1
  111. package/lib/module/handlers/createHandler.js.map +1 -1
  112. package/lib/module/handlers/gestures/GestureDetector/utils.js +2 -2
  113. package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
  114. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  115. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
  116. package/lib/module/handlers/gestures/longPressGesture.js +10 -0
  117. package/lib/module/handlers/gestures/longPressGesture.js.map +1 -1
  118. package/lib/module/jestUtils/jestUtils.js +12 -4
  119. package/lib/module/jestUtils/jestUtils.js.map +1 -1
  120. package/lib/module/mocks.js +13 -3
  121. package/lib/module/mocks.js.map +1 -1
  122. package/lib/module/utils.js +1 -0
  123. package/lib/module/utils.js.map +1 -1
  124. package/lib/module/web/constants.js +1 -1
  125. package/lib/module/web/constants.js.map +1 -1
  126. package/lib/module/web/handlers/GestureHandler.js +2 -3
  127. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  128. package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
  129. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
  130. package/lib/module/web/handlers/LongPressGestureHandler.js +43 -9
  131. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  132. package/lib/module/web/handlers/NativeViewGestureHandler.js +14 -3
  133. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  134. package/lib/module/web/handlers/PanGestureHandler.js +12 -1
  135. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  136. package/lib/module/web/interfaces.js.map +1 -1
  137. package/lib/module/web/tools/EventManager.js.map +1 -1
  138. package/lib/module/web/tools/GestureHandlerWebDelegate.js +54 -10
  139. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  140. package/lib/module/web/tools/KeyboardEventManager.js +96 -0
  141. package/lib/module/web/tools/KeyboardEventManager.js.map +1 -0
  142. package/lib/module/web/tools/PointerEventManager.js +4 -38
  143. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  144. package/lib/module/web/tools/Vector.js +5 -3
  145. package/lib/module/web/tools/Vector.js.map +1 -1
  146. package/lib/module/web/utils.js +184 -13
  147. package/lib/module/web/utils.js.map +1 -1
  148. package/lib/typescript/PointerType.d.ts +2 -1
  149. package/lib/typescript/components/GestureComponents.d.ts +1 -1
  150. package/lib/typescript/components/Pressable/index.d.ts +1 -1
  151. package/lib/typescript/components/Pressable/utils.d.ts +3 -5
  152. package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
  153. package/lib/typescript/handlers/LongPressGestureHandler.d.ts +5 -1
  154. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
  155. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
  156. package/lib/typescript/handlers/gestures/longPressGesture.d.ts +5 -0
  157. package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
  158. package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
  159. package/lib/typescript/mocks.d.ts +4 -3
  160. package/lib/typescript/utils.d.ts +1 -0
  161. package/lib/typescript/web/constants.d.ts +1 -1
  162. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -1
  163. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
  164. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +3 -0
  165. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -0
  166. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
  167. package/lib/typescript/web/interfaces.d.ts +9 -4
  168. package/lib/typescript/web/tools/EventManager.d.ts +2 -2
  169. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +1 -0
  170. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +6 -0
  171. package/lib/typescript/web/tools/KeyboardEventManager.d.ts +13 -0
  172. package/lib/typescript/web/utils.d.ts +2 -1
  173. package/package.json +3 -3
  174. package/src/PointerType.ts +1 -0
  175. package/src/components/GestureButtons.tsx +2 -1
  176. package/src/components/GestureComponents.tsx +1 -1
  177. package/src/components/Pressable/Pressable.tsx +77 -70
  178. package/src/components/Pressable/index.ts +1 -1
  179. package/src/components/Pressable/utils.ts +5 -49
  180. package/src/components/ReanimatedSwipeable.tsx +70 -47
  181. package/src/handlers/GestureHandlerEventPayload.ts +42 -0
  182. package/src/handlers/LongPressGestureHandler.ts +6 -0
  183. package/src/handlers/createHandler.tsx +1 -0
  184. package/src/handlers/gestures/GestureDetector/utils.ts +2 -2
  185. package/src/handlers/gestures/gesture.ts +3 -1
  186. package/src/handlers/gestures/hoverGesture.ts +1 -7
  187. package/src/handlers/gestures/longPressGesture.ts +9 -0
  188. package/src/jestUtils/jestUtils.ts +9 -1
  189. package/src/{mocks.ts → mocks.tsx} +8 -3
  190. package/src/utils.ts +2 -0
  191. package/src/web/constants.ts +1 -1
  192. package/src/web/handlers/GestureHandler.ts +4 -2
  193. package/src/web/handlers/HoverGestureHandler.ts +16 -2
  194. package/src/web/handlers/LongPressGestureHandler.ts +49 -10
  195. package/src/web/handlers/NativeViewGestureHandler.ts +14 -4
  196. package/src/web/handlers/PanGestureHandler.ts +14 -1
  197. package/src/web/interfaces.ts +10 -4
  198. package/src/web/tools/EventManager.ts +2 -4
  199. package/src/web/tools/GestureHandlerDelegate.ts +1 -0
  200. package/src/web/tools/GestureHandlerWebDelegate.ts +67 -10
  201. package/src/web/tools/KeyboardEventManager.ts +91 -0
  202. package/src/web/tools/PointerEventManager.ts +2 -38
  203. package/src/web/tools/Vector.ts +4 -3
  204. package/src/web/utils.ts +188 -13
  205. package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
  206. package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
  207. package/lib/module/web/tools/TouchEventManager.js +0 -149
  208. package/lib/module/web/tools/TouchEventManager.js.map +0 -1
  209. package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
  210. package/src/web/tools/TouchEventManager.ts +0 -175
@@ -1,6 +1,6 @@
1
1
  import { State } from '../../State';
2
2
  import { DEFAULT_TOUCH_SLOP } from '../constants';
3
- import { AdaptedEvent, Config } from '../interfaces';
3
+ import { AdaptedEvent, Config, StylusData } from '../interfaces';
4
4
 
5
5
  import GestureHandler from './GestureHandler';
6
6
 
@@ -52,6 +52,8 @@ export default class PanGestureHandler extends GestureHandler {
52
52
  private lastX = 0;
53
53
  private lastY = 0;
54
54
 
55
+ private stylusData: StylusData | undefined;
56
+
55
57
  private activateAfterLongPress = 0;
56
58
  private activationTimeout = 0;
57
59
 
@@ -196,6 +198,7 @@ export default class PanGestureHandler extends GestureHandler {
196
198
  translationY: isNaN(translationY) ? 0 : translationY,
197
199
  velocityX: this.velocityX,
198
200
  velocityY: this.velocityY,
201
+ stylusData: this.stylusData,
199
202
  };
200
203
  }
201
204
 
@@ -217,6 +220,8 @@ export default class PanGestureHandler extends GestureHandler {
217
220
  }
218
221
 
219
222
  this.tracker.addToTracker(event);
223
+ this.stylusData = event.stylusData;
224
+
220
225
  super.onPointerDown(event);
221
226
 
222
227
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
@@ -259,6 +264,8 @@ export default class PanGestureHandler extends GestureHandler {
259
264
  }
260
265
 
261
266
  protected onPointerUp(event: AdaptedEvent): void {
267
+ this.stylusData = event.stylusData;
268
+
262
269
  super.onPointerUp(event);
263
270
  if (this.currentState === State.ACTIVE) {
264
271
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
@@ -268,6 +275,10 @@ export default class PanGestureHandler extends GestureHandler {
268
275
 
269
276
  this.tracker.removeFromTracker(event.pointerId);
270
277
 
278
+ if (this.tracker.getTrackedPointersCount() === 0) {
279
+ this.clearActivationTimeout();
280
+ }
281
+
271
282
  if (this.currentState === State.ACTIVE) {
272
283
  this.end();
273
284
  } else {
@@ -302,6 +313,7 @@ export default class PanGestureHandler extends GestureHandler {
302
313
 
303
314
  protected onPointerMove(event: AdaptedEvent): void {
304
315
  this.tracker.track(event);
316
+ this.stylusData = event.stylusData;
305
317
 
306
318
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
307
319
  this.lastX = lastCoords.x;
@@ -322,6 +334,7 @@ export default class PanGestureHandler extends GestureHandler {
322
334
  }
323
335
 
324
336
  this.tracker.track(event);
337
+ this.stylusData = event.stylusData;
325
338
 
326
339
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
327
340
  this.lastX = lastCoords.x;
@@ -36,7 +36,7 @@ type ConfigArgs =
36
36
  | undefined;
37
37
 
38
38
  export interface Config extends Record<string, ConfigArgs> {
39
- enabled?: boolean;
39
+ enabled: boolean;
40
40
  simultaneousHandlers?: Handler[] | null;
41
41
  waitFor?: Handler[] | null;
42
42
  blocksHandlers?: Handler[] | null;
@@ -132,6 +132,14 @@ export interface PropsRef {
132
132
  onGestureHandlerStateChange: () => void;
133
133
  }
134
134
 
135
+ export interface StylusData {
136
+ tiltX: number;
137
+ tiltY: number;
138
+ azimuthAngle: number;
139
+ altitudeAngle: number;
140
+ pressure: number;
141
+ }
142
+
135
143
  export interface AdaptedEvent {
136
144
  x: number;
137
145
  y: number;
@@ -142,9 +150,7 @@ export interface AdaptedEvent {
142
150
  pointerType: PointerType;
143
151
  time: number;
144
152
  button?: MouseButton;
145
- allTouches?: TouchList;
146
- changedTouches?: TouchList;
147
- touchEventType?: TouchEventType;
153
+ stylusData?: StylusData;
148
154
  }
149
155
 
150
156
  export enum EventTypes {
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-empty-function */
2
- import { AdaptedEvent, EventTypes, TouchEventType } from '../interfaces';
2
+ import { AdaptedEvent, EventTypes } from '../interfaces';
3
3
 
4
4
  type PointerEventCallback = (event: AdaptedEvent) => void;
5
5
 
@@ -18,9 +18,7 @@ export default abstract class EventManager<T> {
18
18
 
19
19
  protected abstract mapEvent(
20
20
  event: Event,
21
- eventType: EventTypes,
22
- index?: number,
23
- touchEventType?: TouchEventType
21
+ eventType: EventTypes
24
22
  ): AdaptedEvent;
25
23
 
26
24
  protected onPointerDown(_event: AdaptedEvent): void {}
@@ -20,6 +20,7 @@ export interface GestureHandlerDelegate<TComponent, THandler> {
20
20
  onEnd(): void;
21
21
  onCancel(): void;
22
22
  onFail(): void;
23
+ onEnabledChange(enabled: boolean): void;
23
24
 
24
25
  destroy(config: Config): void;
25
26
  }
@@ -5,19 +5,29 @@ import {
5
5
  MeasureResult,
6
6
  } from './GestureHandlerDelegate';
7
7
  import PointerEventManager from './PointerEventManager';
8
- import TouchEventManager from './TouchEventManager';
9
8
  import { State } from '../../State';
10
9
  import { isPointerInBounds } from '../utils';
11
10
  import EventManager from './EventManager';
12
11
  import { Config } from '../interfaces';
13
12
  import { MouseButton } from '../../handlers/gestureHandlerCommon';
13
+ import KeyboardEventManager from './KeyboardEventManager';
14
+
15
+ interface DefaultViewStyles {
16
+ userSelect: string;
17
+ touchAction: string;
18
+ }
14
19
 
15
20
  export class GestureHandlerWebDelegate
16
21
  implements GestureHandlerDelegate<HTMLElement, IGestureHandler>
17
22
  {
23
+ private isInitialized = false;
18
24
  private view!: HTMLElement;
19
25
  private gestureHandler!: IGestureHandler;
20
26
  private eventManagers: EventManager<unknown>[] = [];
27
+ private defaultViewStyles: DefaultViewStyles = {
28
+ userSelect: '',
29
+ touchAction: '',
30
+ };
21
31
 
22
32
  getView(): HTMLElement {
23
33
  return this.view;
@@ -30,22 +40,24 @@ export class GestureHandlerWebDelegate
30
40
  );
31
41
  }
32
42
 
43
+ this.isInitialized = true;
44
+
33
45
  this.gestureHandler = handler;
34
46
  this.view = findNodeHandle(viewRef) as unknown as HTMLElement;
35
47
 
36
- const config = handler.getConfig();
48
+ this.defaultViewStyles = {
49
+ userSelect: this.view.style.userSelect,
50
+ touchAction: this.view.style.touchAction,
51
+ };
37
52
 
38
- this.addContextMenuListeners(config);
53
+ const config = handler.getConfig();
39
54
 
40
- this.view.style['userSelect'] = config.userSelect ?? 'none';
41
- this.view.style['webkitUserSelect'] = config.userSelect ?? 'none';
42
-
43
- this.view.style['touchAction'] = config.touchAction ?? 'none';
44
- // @ts-ignore This one disables default events on Safari
45
- this.view.style['WebkitTouchCallout'] = 'none';
55
+ this.setUserSelect(config.enabled);
56
+ this.setTouchAction(config.enabled);
57
+ this.setContextMenu(config.enabled);
46
58
 
47
59
  this.eventManagers.push(new PointerEventManager(this.view));
48
- this.eventManagers.push(new TouchEventManager(this.view));
60
+ this.eventManagers.push(new KeyboardEventManager(this.view));
49
61
 
50
62
  this.eventManagers.forEach((manager) =>
51
63
  this.gestureHandler.attachEventManager(manager)
@@ -117,6 +129,51 @@ export class GestureHandlerWebDelegate
117
129
  e.stopPropagation();
118
130
  }
119
131
 
132
+ private setUserSelect(isHandlerEnabled: boolean) {
133
+ const { userSelect } = this.gestureHandler.getConfig();
134
+
135
+ this.view.style['userSelect'] = isHandlerEnabled
136
+ ? userSelect ?? 'none'
137
+ : this.defaultViewStyles.userSelect;
138
+
139
+ this.view.style['webkitUserSelect'] = isHandlerEnabled
140
+ ? userSelect ?? 'none'
141
+ : this.defaultViewStyles.userSelect;
142
+ }
143
+
144
+ private setTouchAction(isHandlerEnabled: boolean) {
145
+ const { touchAction } = this.gestureHandler.getConfig();
146
+
147
+ this.view.style['touchAction'] = isHandlerEnabled
148
+ ? touchAction ?? 'none'
149
+ : this.defaultViewStyles.touchAction;
150
+
151
+ // @ts-ignore This one disables default events on Safari
152
+ this.view.style['WebkitTouchCallout'] = isHandlerEnabled
153
+ ? touchAction ?? 'none'
154
+ : this.defaultViewStyles.touchAction;
155
+ }
156
+
157
+ private setContextMenu(isHandlerEnabled: boolean) {
158
+ const config = this.gestureHandler.getConfig();
159
+
160
+ if (isHandlerEnabled) {
161
+ this.addContextMenuListeners(config);
162
+ } else {
163
+ this.removeContextMenuListeners(config);
164
+ }
165
+ }
166
+
167
+ onEnabledChange(enabled: boolean): void {
168
+ if (!this.isInitialized) {
169
+ return;
170
+ }
171
+
172
+ this.setUserSelect(enabled);
173
+ this.setTouchAction(enabled);
174
+ this.setContextMenu(enabled);
175
+ }
176
+
120
177
  onBegin(): void {
121
178
  // no-op for now
122
179
  }
@@ -0,0 +1,91 @@
1
+ import { AdaptedEvent, EventTypes } from '../interfaces';
2
+ import EventManager from './EventManager';
3
+ import { PointerType } from '../../PointerType';
4
+
5
+ export default class KeyboardEventManager extends EventManager<HTMLElement> {
6
+ private activationKeys = ['Enter', ' '];
7
+ private cancelationKeys = ['Tab'];
8
+ private isPressed = false;
9
+
10
+ private keyDownCallback = (event: KeyboardEvent): void => {
11
+ if (this.cancelationKeys.indexOf(event.key) !== -1 && this.isPressed) {
12
+ this.dispatchEvent(event, EventTypes.CANCEL);
13
+ return;
14
+ }
15
+
16
+ if (this.activationKeys.indexOf(event.key) === -1) {
17
+ return;
18
+ }
19
+
20
+ this.dispatchEvent(event, EventTypes.DOWN);
21
+ };
22
+
23
+ private keyUpCallback = (event: KeyboardEvent): void => {
24
+ if (this.activationKeys.indexOf(event.key) === -1 || !this.isPressed) {
25
+ return;
26
+ }
27
+
28
+ this.dispatchEvent(event, EventTypes.UP);
29
+ };
30
+
31
+ private dispatchEvent(event: KeyboardEvent, eventType: EventTypes) {
32
+ if (!(event.target instanceof HTMLElement)) {
33
+ return;
34
+ }
35
+
36
+ const adaptedEvent = this.mapEvent(event, eventType);
37
+
38
+ switch (eventType) {
39
+ case EventTypes.UP:
40
+ this.isPressed = false;
41
+ this.onPointerUp(adaptedEvent);
42
+ break;
43
+ case EventTypes.DOWN:
44
+ this.isPressed = true;
45
+ this.onPointerDown(adaptedEvent);
46
+ break;
47
+ case EventTypes.CANCEL:
48
+ this.isPressed = false;
49
+ this.onPointerCancel(adaptedEvent);
50
+ break;
51
+ }
52
+ }
53
+
54
+ public registerListeners(): void {
55
+ this.view.addEventListener('keydown', this.keyDownCallback);
56
+ this.view.addEventListener('keyup', this.keyUpCallback);
57
+ }
58
+
59
+ public unregisterListeners(): void {
60
+ this.view.addEventListener('keydown', this.keyDownCallback);
61
+ this.view.addEventListener('keyup', this.keyUpCallback);
62
+ }
63
+
64
+ protected mapEvent(
65
+ event: KeyboardEvent,
66
+ eventType: EventTypes
67
+ ): AdaptedEvent {
68
+ const viewRect = (event.target as HTMLElement).getBoundingClientRect();
69
+
70
+ const viewportPosition = {
71
+ x: viewRect?.x + viewRect?.width / 2,
72
+ y: viewRect?.y + viewRect?.height / 2,
73
+ };
74
+
75
+ const relativePosition = {
76
+ x: viewRect?.width / 2,
77
+ y: viewRect?.height / 2,
78
+ };
79
+
80
+ return {
81
+ x: viewportPosition.x,
82
+ y: viewportPosition.y,
83
+ offsetX: relativePosition.x,
84
+ offsetY: relativePosition.y,
85
+ pointerId: 0,
86
+ eventType: eventType,
87
+ pointerType: PointerType.KEY,
88
+ time: event.timeStamp,
89
+ };
90
+ }
91
+ }
@@ -4,15 +4,12 @@ import { AdaptedEvent, EventTypes, Point } from '../interfaces';
4
4
  import {
5
5
  PointerTypeMapping,
6
6
  calculateViewScale,
7
+ tryExtractStylusData,
7
8
  isPointerInBounds,
8
9
  } from '../utils';
9
10
  import { PointerType } from '../../PointerType';
10
11
 
11
12
  const POINTER_CAPTURE_EXCLUDE_LIST = new Set<string>(['SELECT', 'INPUT']);
12
- const PointerTypes = {
13
- Touch: 'touch',
14
- Stylus: 'pen',
15
- };
16
13
 
17
14
  export default class PointerEventManager extends EventManager<HTMLElement> {
18
15
  private trackedPointers = new Set<number>();
@@ -35,9 +32,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
35
32
  }
36
33
 
37
34
  private pointerDownCallback = (event: PointerEvent) => {
38
- if (event.pointerType === PointerTypes.Touch) {
39
- return;
40
- }
41
35
  if (!isPointerInBounds(this.view, { x: event.clientX, y: event.clientY })) {
42
36
  return;
43
37
  }
@@ -61,10 +55,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
61
55
  };
62
56
 
63
57
  private pointerUpCallback = (event: PointerEvent) => {
64
- if (event.pointerType === PointerTypes.Touch) {
65
- return;
66
- }
67
-
68
58
  // When we call reset on gesture handlers, it also resets their event managers
69
59
  // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
70
60
  // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
@@ -92,21 +82,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
92
82
  };
93
83
 
94
84
  private pointerMoveCallback = (event: PointerEvent) => {
95
- if (event.pointerType === PointerTypes.Touch) {
96
- return;
97
- }
98
-
99
- // Stylus triggers `pointermove` event when it detects changes in pressure. Since it is very sensitive to those changes,
100
- // it constantly sends events, even though there was no change in position. To fix that we check whether
101
- // pointer has actually moved and if not, we do not send event.
102
- if (
103
- event.pointerType === PointerTypes.Stylus &&
104
- event.x === this.lastPosition.x &&
105
- event.y === this.lastPosition.y
106
- ) {
107
- return;
108
- }
109
-
110
85
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE);
111
86
  const target = event.target as HTMLElement;
112
87
 
@@ -161,10 +136,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
161
136
  };
162
137
 
163
138
  private pointerCancelCallback = (event: PointerEvent) => {
164
- if (event.pointerType === PointerTypes.Touch) {
165
- return;
166
- }
167
-
168
139
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
169
140
 
170
141
  this.onPointerCancel(adaptedEvent);
@@ -174,20 +145,12 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
174
145
  };
175
146
 
176
147
  private pointerEnterCallback = (event: PointerEvent) => {
177
- if (event.pointerType === PointerTypes.Touch) {
178
- return;
179
- }
180
-
181
148
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.ENTER);
182
149
 
183
150
  this.onPointerMoveOver(adaptedEvent);
184
151
  };
185
152
 
186
153
  private pointerLeaveCallback = (event: PointerEvent) => {
187
- if (event.pointerType === PointerTypes.Touch) {
188
- return;
189
- }
190
-
191
154
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.LEAVE);
192
155
 
193
156
  this.onPointerMoveOut(adaptedEvent);
@@ -252,6 +215,7 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
252
215
  PointerTypeMapping.get(event.pointerType) ?? PointerType.OTHER,
253
216
  button: this.mouseButtonsMapper.get(event.button),
254
217
  time: event.timeStamp,
218
+ stylusData: tryExtractStylusData(event),
255
219
  };
256
220
  }
257
221
 
@@ -1,5 +1,5 @@
1
1
  import { DiagonalDirections, Directions } from '../../Directions';
2
- import { MINIMAL_FLING_VELOCITY } from '../constants';
2
+ import { MINIMAL_RECOGNIZABLE_MAGNITUDE } from '../constants';
3
3
  import PointerTracker from './PointerTracker';
4
4
 
5
5
  export default class Vector {
@@ -14,14 +14,15 @@ export default class Vector {
14
14
  this.y = y;
15
15
 
16
16
  this._magnitude = Math.hypot(this.x, this.y);
17
- const isMagnitudeSufficient = this._magnitude > MINIMAL_FLING_VELOCITY;
17
+ const isMagnitudeSufficient =
18
+ this._magnitude > MINIMAL_RECOGNIZABLE_MAGNITUDE;
18
19
 
19
20
  this.unitX = isMagnitudeSufficient ? this.x / this._magnitude : 0;
20
21
  this.unitY = isMagnitudeSufficient ? this.y / this._magnitude : 0;
21
22
  }
22
23
 
23
24
  static fromDirection(direction: Directions | DiagonalDirections): Vector {
24
- return DirectionToVectorMappings.get(direction)!;
25
+ return DirectionToVectorMappings.get(direction) ?? new Vector(0, 0);
25
26
  }
26
27
 
27
28
  static fromVelocity(tracker: PointerTracker, pointerId: number) {
package/src/web/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PointerType } from '../PointerType';
2
- import { Point } from './interfaces';
2
+ import type { Point, StylusData } from './interfaces';
3
3
 
4
4
  export function isPointerInBounds(view: HTMLElement, { x, y }: Point): boolean {
5
5
  const rect: DOMRect = view.getBoundingClientRect();
@@ -27,28 +27,203 @@ export function calculateViewScale(view: HTMLElement) {
27
27
  scaleY: 1,
28
28
  };
29
29
 
30
- const scales = styles.scale.split(' ');
30
+ // Get scales from scale property
31
+ if (styles.scale !== undefined && styles.scale !== 'none') {
32
+ const scales = styles.scale.split(' ');
31
33
 
32
- if (scales[0] !== 'none') {
33
- resultScales.scaleX = parseFloat(scales[0]);
34
- }
34
+ if (scales[0]) {
35
+ resultScales.scaleX = parseFloat(scales[0]);
36
+ }
35
37
 
36
- if (scales[1]) {
37
- resultScales.scaleY = parseFloat(scales[1]);
38
+ resultScales.scaleY = scales[1]
39
+ ? parseFloat(scales[1])
40
+ : parseFloat(scales[0]);
38
41
  }
39
42
 
43
+ // Get scales from transform property
40
44
  const matrixElements = new RegExp(/matrix\((.+)\)/).exec(
41
45
  styles.transform
42
46
  )?.[1];
43
47
 
44
- if (!matrixElements) {
45
- return resultScales;
48
+ if (matrixElements) {
49
+ const matrixElementsArray = matrixElements.split(', ');
50
+
51
+ resultScales.scaleX *= parseFloat(matrixElementsArray[0]);
52
+ resultScales.scaleY *= parseFloat(matrixElementsArray[3]);
46
53
  }
47
54
 
48
- const matrixElementsArray = matrixElements.split(', ');
55
+ return resultScales;
56
+ }
49
57
 
50
- resultScales.scaleX *= parseFloat(matrixElementsArray[0]);
51
- resultScales.scaleY *= parseFloat(matrixElementsArray[3]);
58
+ export function tryExtractStylusData(
59
+ event: PointerEvent
60
+ ): StylusData | undefined {
61
+ const pointerType = PointerTypeMapping.get(event.pointerType);
52
62
 
53
- return resultScales;
63
+ if (pointerType !== PointerType.STYLUS) {
64
+ return;
65
+ }
66
+
67
+ // @ts-ignore This property exists (https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent#instance_properties)
68
+ const eventAzimuthAngle: number | undefined = event.azimuthAngle;
69
+ // @ts-ignore This property exists (https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent#instance_properties)
70
+ const eventAltitudeAngle: number | undefined = event.altitudeAngle;
71
+
72
+ if (event.tiltX === 0 && event.tiltY === 0) {
73
+ // If we are in this branch, it means that either tilt properties are not supported and we have to calculate them from altitude and azimuth angles,
74
+ // or stylus is perpendicular to the screen and we can use altitude / azimuth instead of tilt
75
+
76
+ // If azimuth and altitude are undefined in this branch, it means that we are either perpendicular to the screen,
77
+ // or that none of the position sets is supported. In that case, we can treat stylus as perpendicular
78
+ if (eventAzimuthAngle === undefined || eventAltitudeAngle === undefined) {
79
+ return {
80
+ tiltX: 0,
81
+ tiltY: 0,
82
+ azimuthAngle: Math.PI / 2,
83
+ altitudeAngle: Math.PI / 2,
84
+ pressure: event.pressure,
85
+ };
86
+ }
87
+
88
+ const { tiltX, tiltY } = spherical2tilt(
89
+ eventAltitudeAngle,
90
+ eventAzimuthAngle
91
+ );
92
+
93
+ return {
94
+ tiltX,
95
+ tiltY,
96
+ azimuthAngle: eventAzimuthAngle,
97
+ altitudeAngle: eventAltitudeAngle,
98
+ pressure: event.pressure,
99
+ };
100
+ }
101
+
102
+ const { altitudeAngle, azimuthAngle } = tilt2spherical(
103
+ event.tiltX,
104
+ event.tiltY
105
+ );
106
+
107
+ return {
108
+ tiltX: event.tiltX,
109
+ tiltY: event.tiltY,
110
+ azimuthAngle,
111
+ altitudeAngle,
112
+ pressure: event.pressure,
113
+ };
114
+ }
115
+
116
+ // `altitudeAngle` and `azimuthAngle` are experimental properties, which are not supported on Firefox and Safari.
117
+ // Given that, we use `tilt` properties and algorithm that converts one value to another.
118
+ //
119
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
120
+ function tilt2spherical(tiltX: number, tiltY: number) {
121
+ const tiltXrad = (tiltX * Math.PI) / 180;
122
+ const tiltYrad = (tiltY * Math.PI) / 180;
123
+
124
+ // calculate azimuth angle
125
+ let azimuthAngle = 0;
126
+
127
+ if (tiltX === 0) {
128
+ if (tiltY > 0) {
129
+ azimuthAngle = Math.PI / 2;
130
+ } else if (tiltY < 0) {
131
+ azimuthAngle = (3 * Math.PI) / 2;
132
+ }
133
+ } else if (tiltY === 0) {
134
+ if (tiltX < 0) {
135
+ azimuthAngle = Math.PI;
136
+ }
137
+ } else if (Math.abs(tiltX) === 90 || Math.abs(tiltY) === 90) {
138
+ // not enough information to calculate azimuth
139
+ azimuthAngle = 0;
140
+ } else {
141
+ // Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
142
+ const tanX = Math.tan(tiltXrad);
143
+ const tanY = Math.tan(tiltYrad);
144
+
145
+ azimuthAngle = Math.atan2(tanY, tanX);
146
+ if (azimuthAngle < 0) {
147
+ azimuthAngle += 2 * Math.PI;
148
+ }
149
+ }
150
+
151
+ // calculate altitude angle
152
+ let altitudeAngle = 0;
153
+
154
+ if (Math.abs(tiltX) === 90 || Math.abs(tiltY) === 90) {
155
+ altitudeAngle = 0;
156
+ } else if (tiltX === 0) {
157
+ altitudeAngle = Math.PI / 2 - Math.abs(tiltYrad);
158
+ } else if (tiltY === 0) {
159
+ altitudeAngle = Math.PI / 2 - Math.abs(tiltXrad);
160
+ } else {
161
+ // Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
162
+ altitudeAngle = Math.atan(
163
+ 1.0 /
164
+ Math.sqrt(
165
+ Math.pow(Math.tan(tiltXrad), 2) + Math.pow(Math.tan(tiltYrad), 2)
166
+ )
167
+ );
168
+ }
169
+
170
+ return { altitudeAngle: altitudeAngle, azimuthAngle: azimuthAngle };
171
+ }
172
+
173
+ // If we are on a platform that doesn't support `tiltX` and `tiltY`, we have to calculate them from `altitude` and `azimuth` angles.
174
+ //
175
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
176
+ function spherical2tilt(altitudeAngle: number, azimuthAngle: number) {
177
+ const radToDeg = 180 / Math.PI;
178
+
179
+ let tiltXrad = 0;
180
+ let tiltYrad = 0;
181
+
182
+ if (altitudeAngle === 0) {
183
+ // the pen is in the X-Y plane
184
+ if (azimuthAngle === 0 || azimuthAngle === 2 * Math.PI) {
185
+ // pen is on positive X axis
186
+ tiltXrad = Math.PI / 2;
187
+ }
188
+ if (azimuthAngle === Math.PI / 2) {
189
+ // pen is on positive Y axis
190
+ tiltYrad = Math.PI / 2;
191
+ }
192
+ if (azimuthAngle === Math.PI) {
193
+ // pen is on negative X axis
194
+ tiltXrad = -Math.PI / 2;
195
+ }
196
+ if (azimuthAngle === (3 * Math.PI) / 2) {
197
+ // pen is on negative Y axis
198
+ tiltYrad = -Math.PI / 2;
199
+ }
200
+ if (azimuthAngle > 0 && azimuthAngle < Math.PI / 2) {
201
+ tiltXrad = Math.PI / 2;
202
+ tiltYrad = Math.PI / 2;
203
+ }
204
+ if (azimuthAngle > Math.PI / 2 && azimuthAngle < Math.PI) {
205
+ tiltXrad = -Math.PI / 2;
206
+ tiltYrad = Math.PI / 2;
207
+ }
208
+ if (azimuthAngle > Math.PI && azimuthAngle < (3 * Math.PI) / 2) {
209
+ tiltXrad = -Math.PI / 2;
210
+ tiltYrad = -Math.PI / 2;
211
+ }
212
+ if (azimuthAngle > (3 * Math.PI) / 2 && azimuthAngle < 2 * Math.PI) {
213
+ tiltXrad = Math.PI / 2;
214
+ tiltYrad = -Math.PI / 2;
215
+ }
216
+ }
217
+
218
+ if (altitudeAngle !== 0) {
219
+ const tanAlt = Math.tan(altitudeAngle);
220
+
221
+ tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
222
+ tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
223
+ }
224
+
225
+ const tiltX = Math.round(tiltXrad * radToDeg);
226
+ const tiltY = Math.round(tiltYrad * radToDeg);
227
+
228
+ return { tiltX, tiltY };
54
229
  }