react-native-gesture-handler 2.18.1 → 2.20.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }