react-native-gesture-handler 2.18.1 → 2.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. package/README.md +1 -0
  2. package/android/build.gradle +4 -17
  3. package/android/src/main/AndroidManifest.xml +1 -3
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +21 -21
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +2 -2
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +5 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +80 -4
  8. package/android/src/main/java/com/swmansion/gesturehandler/core/PinchGestureHandler.kt +2 -1
  9. package/android/src/main/java/com/swmansion/gesturehandler/core/ScaleGestureDetector.java +10 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt +2 -2
  11. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +3 -0
  12. package/apple/Handlers/RNFlingHandler.h +1 -0
  13. package/apple/Handlers/RNFlingHandler.m +153 -19
  14. package/apple/Handlers/RNHoverHandler.m +44 -2
  15. package/apple/Handlers/RNLongPressHandler.m +109 -20
  16. package/apple/Handlers/RNManualHandler.m +53 -29
  17. package/apple/Handlers/RNNativeViewHandler.mm +22 -15
  18. package/apple/RNGHUIKit.h +2 -0
  19. package/apple/RNGHVector.h +31 -0
  20. package/apple/RNGHVector.m +67 -0
  21. package/apple/RNGestureHandler.h +7 -0
  22. package/apple/{RNGestureHandler.m → RNGestureHandler.mm} +63 -1
  23. package/apple/RNGestureHandlerButtonComponentView.mm +6 -0
  24. package/apple/RNGestureHandlerDirection.h +25 -0
  25. package/lib/commonjs/PointerType.js +2 -1
  26. package/lib/commonjs/PointerType.js.map +1 -1
  27. package/lib/commonjs/components/Pressable/Pressable.js +67 -70
  28. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  29. package/lib/commonjs/components/Pressable/index.js +0 -8
  30. package/lib/commonjs/components/Pressable/index.js.map +1 -1
  31. package/lib/commonjs/components/ReanimatedSwipeable.js +60 -41
  32. package/lib/commonjs/components/ReanimatedSwipeable.js.map +1 -1
  33. package/lib/commonjs/handlers/LongPressGestureHandler.js +1 -1
  34. package/lib/commonjs/handlers/LongPressGestureHandler.js.map +1 -1
  35. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js +1 -1
  36. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js.map +1 -1
  37. package/lib/commonjs/handlers/gestures/longPressGesture.js +10 -0
  38. package/lib/commonjs/handlers/gestures/longPressGesture.js.map +1 -1
  39. package/lib/commonjs/mocks.js +16 -3
  40. package/lib/commonjs/mocks.js.map +1 -1
  41. package/lib/commonjs/utils.js +4 -0
  42. package/lib/commonjs/utils.js.map +1 -1
  43. package/lib/commonjs/web/constants.js +3 -3
  44. package/lib/commonjs/web/constants.js.map +1 -1
  45. package/lib/commonjs/web/handlers/GestureHandler.js +1 -0
  46. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  47. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +43 -9
  48. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  49. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +14 -3
  50. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  51. package/lib/commonjs/web/handlers/PanGestureHandler.js +4 -0
  52. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  53. package/lib/commonjs/web/interfaces.js.map +1 -1
  54. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +55 -8
  55. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  56. package/lib/commonjs/web/tools/KeyboardEventManager.js +110 -0
  57. package/lib/commonjs/web/tools/KeyboardEventManager.js.map +1 -0
  58. package/lib/commonjs/web/tools/Vector.js +4 -2
  59. package/lib/commonjs/web/tools/Vector.js.map +1 -1
  60. package/lib/commonjs/web/utils.js +14 -13
  61. package/lib/commonjs/web/utils.js.map +1 -1
  62. package/lib/module/PointerType.js +2 -1
  63. package/lib/module/PointerType.js.map +1 -1
  64. package/lib/module/components/Pressable/Pressable.js +66 -70
  65. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  66. package/lib/module/components/Pressable/index.js +0 -1
  67. package/lib/module/components/Pressable/index.js.map +1 -1
  68. package/lib/module/components/ReanimatedSwipeable.js +58 -37
  69. package/lib/module/components/ReanimatedSwipeable.js.map +1 -1
  70. package/lib/module/handlers/LongPressGestureHandler.js +1 -1
  71. package/lib/module/handlers/LongPressGestureHandler.js.map +1 -1
  72. package/lib/module/handlers/gestures/GestureDetector/utils.js +2 -2
  73. package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
  74. package/lib/module/handlers/gestures/longPressGesture.js +10 -0
  75. package/lib/module/handlers/gestures/longPressGesture.js.map +1 -1
  76. package/lib/module/mocks.js +13 -3
  77. package/lib/module/mocks.js.map +1 -1
  78. package/lib/module/utils.js +1 -0
  79. package/lib/module/utils.js.map +1 -1
  80. package/lib/module/web/constants.js +1 -1
  81. package/lib/module/web/constants.js.map +1 -1
  82. package/lib/module/web/handlers/GestureHandler.js +1 -0
  83. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  84. package/lib/module/web/handlers/LongPressGestureHandler.js +43 -9
  85. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  86. package/lib/module/web/handlers/NativeViewGestureHandler.js +14 -3
  87. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  88. package/lib/module/web/handlers/PanGestureHandler.js +4 -0
  89. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  90. package/lib/module/web/interfaces.js.map +1 -1
  91. package/lib/module/web/tools/GestureHandlerWebDelegate.js +54 -8
  92. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  93. package/lib/module/web/tools/KeyboardEventManager.js +96 -0
  94. package/lib/module/web/tools/KeyboardEventManager.js.map +1 -0
  95. package/lib/module/web/tools/Vector.js +5 -3
  96. package/lib/module/web/tools/Vector.js.map +1 -1
  97. package/lib/module/web/utils.js +14 -13
  98. package/lib/module/web/utils.js.map +1 -1
  99. package/lib/typescript/PointerType.d.ts +2 -1
  100. package/lib/typescript/components/Pressable/index.d.ts +1 -1
  101. package/lib/typescript/handlers/LongPressGestureHandler.d.ts +5 -1
  102. package/lib/typescript/handlers/gestures/longPressGesture.d.ts +5 -0
  103. package/lib/typescript/mocks.d.ts +4 -3
  104. package/lib/typescript/utils.d.ts +1 -0
  105. package/lib/typescript/web/constants.d.ts +1 -1
  106. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -1
  107. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +3 -0
  108. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -0
  109. package/lib/typescript/web/interfaces.d.ts +1 -1
  110. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +1 -0
  111. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +6 -0
  112. package/lib/typescript/web/tools/KeyboardEventManager.d.ts +13 -0
  113. package/package.json +3 -3
  114. package/src/PointerType.ts +1 -0
  115. package/src/components/Pressable/Pressable.tsx +70 -50
  116. package/src/components/Pressable/index.ts +1 -1
  117. package/src/components/ReanimatedSwipeable.tsx +70 -47
  118. package/src/handlers/LongPressGestureHandler.ts +6 -0
  119. package/src/handlers/gestures/GestureDetector/utils.ts +2 -2
  120. package/src/handlers/gestures/longPressGesture.ts +9 -0
  121. package/src/{mocks.ts → mocks.tsx} +8 -3
  122. package/src/utils.ts +2 -0
  123. package/src/web/constants.ts +1 -1
  124. package/src/web/handlers/GestureHandler.ts +3 -1
  125. package/src/web/handlers/LongPressGestureHandler.ts +49 -10
  126. package/src/web/handlers/NativeViewGestureHandler.ts +14 -4
  127. package/src/web/handlers/PanGestureHandler.ts +4 -0
  128. package/src/web/interfaces.ts +1 -1
  129. package/src/web/tools/GestureHandlerDelegate.ts +1 -0
  130. package/src/web/tools/GestureHandlerWebDelegate.ts +67 -8
  131. package/src/web/tools/KeyboardEventManager.ts +91 -0
  132. package/src/web/tools/Vector.ts +4 -3
  133. package/src/web/utils.ts +15 -13
@@ -31,6 +31,15 @@ export class LongPressGesture extends BaseGesture<LongPressGestureHandlerEventPa
31
31
  this.config.maxDist = distance;
32
32
  return this;
33
33
  }
34
+
35
+ /**
36
+ * Determine exact number of points required to handle the long press gesture.
37
+ * @param pointers
38
+ */
39
+ numberOfPointers(pointers: number) {
40
+ this.config.numberOfPointers = pointers;
41
+ return this;
42
+ }
34
43
  }
35
44
 
36
45
  export type LongPressGestureType = InstanceType<typeof LongPressGesture>;
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import {
2
3
  TouchableHighlight,
3
4
  TouchableNativeFeedback,
@@ -30,9 +31,13 @@ const LongPressGestureHandler = View;
30
31
  const PinchGestureHandler = View;
31
32
  const RotationGestureHandler = View;
32
33
  const FlingGestureHandler = View;
33
- const RawButton = TouchableNativeFeedback;
34
- const BaseButton = TouchableNativeFeedback;
35
- const RectButton = TouchableNativeFeedback;
34
+ const RawButton = ({ enabled, ...rest }: any) => (
35
+ <TouchableNativeFeedback disabled={!enabled} {...rest}>
36
+ <View />
37
+ </TouchableNativeFeedback>
38
+ );
39
+ const BaseButton = RawButton;
40
+ const RectButton = RawButton;
36
41
  const BorderlessButton = TouchableNativeFeedback;
37
42
 
38
43
  export default {
package/src/utils.ts CHANGED
@@ -98,3 +98,5 @@ export function deepEqual(obj1: any, obj2: any) {
98
98
 
99
99
  return true;
100
100
  }
101
+
102
+ export const INT32_MAX = 2 ** 31 - 1;
@@ -1,2 +1,2 @@
1
1
  export const DEFAULT_TOUCH_SLOP = 15;
2
- export const MINIMAL_FLING_VELOCITY = 0.1;
2
+ export const MINIMAL_RECOGNIZABLE_MAGNITUDE = 0.1;
@@ -14,10 +14,10 @@ import EventManager from '../tools/EventManager';
14
14
  import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator';
15
15
  import InteractionManager from '../tools/InteractionManager';
16
16
  import PointerTracker, { TrackerElement } from '../tools/PointerTracker';
17
- import { GestureHandlerDelegate } from '../tools/GestureHandlerDelegate';
18
17
  import IGestureHandler from './IGestureHandler';
19
18
  import { MouseButton } from '../../handlers/gestureHandlerCommon';
20
19
  import { PointerType } from '../../PointerType';
20
+ import { GestureHandlerDelegate } from '../tools/GestureHandlerDelegate';
21
21
 
22
22
  export default abstract class GestureHandler implements IGestureHandler {
23
23
  private lastSentState: State | null = null;
@@ -589,6 +589,8 @@ export default abstract class GestureHandler implements IGestureHandler {
589
589
  this.config = { enabled: enabled, ...props };
590
590
  this.enabled = enabled;
591
591
 
592
+ this.delegate.onEnabledChange(enabled);
593
+
592
594
  if (this.config.shouldCancelWhenOutside !== undefined) {
593
595
  this.setShouldCancelWhenOutside(this.config.shouldCancelWhenOutside);
594
596
  }
@@ -12,6 +12,7 @@ export default class LongPressGestureHandler extends GestureHandler {
12
12
  private defaultMaxDistSq = DEFAULT_MAX_DIST_DP * SCALING_FACTOR;
13
13
 
14
14
  private maxDistSq = this.defaultMaxDistSq;
15
+ private numberOfPointers = 1;
15
16
  private startX = 0;
16
17
  private startY = 0;
17
18
 
@@ -45,6 +46,10 @@ export default class LongPressGestureHandler extends GestureHandler {
45
46
  if (this.config.maxDist !== undefined) {
46
47
  this.maxDistSq = this.config.maxDist * this.config.maxDist;
47
48
  }
49
+
50
+ if (this.config.numberOfPointers !== undefined) {
51
+ this.numberOfPointers = this.config.numberOfPointers;
52
+ }
48
53
  }
49
54
 
50
55
  protected resetConfig(): void {
@@ -64,17 +69,36 @@ export default class LongPressGestureHandler extends GestureHandler {
64
69
 
65
70
  this.tracker.addToTracker(event);
66
71
  super.onPointerDown(event);
67
- this.tryBegin(event);
72
+
73
+ this.startX = event.x;
74
+ this.startY = event.y;
75
+
76
+ this.tryBegin();
68
77
  this.tryActivate();
69
- this.checkDistanceFail(event);
70
78
 
71
79
  this.tryToSendTouchEvent(event);
72
80
  }
81
+ protected onPointerAdd(event: AdaptedEvent): void {
82
+ super.onPointerAdd(event);
83
+ this.tracker.addToTracker(event);
84
+
85
+ if (this.tracker.getTrackedPointersCount() > this.numberOfPointers) {
86
+ this.fail();
87
+ return;
88
+ }
89
+
90
+ const absoluteCoordsAverage = this.tracker.getAbsoluteCoordsAverage();
91
+
92
+ this.startX = absoluteCoordsAverage.x;
93
+ this.startY = absoluteCoordsAverage.y;
94
+
95
+ this.tryActivate();
96
+ }
73
97
 
74
98
  protected onPointerMove(event: AdaptedEvent): void {
75
99
  super.onPointerMove(event);
76
100
  this.tracker.track(event);
77
- this.checkDistanceFail(event);
101
+ this.checkDistanceFail();
78
102
  }
79
103
 
80
104
  protected onPointerUp(event: AdaptedEvent): void {
@@ -88,7 +112,19 @@ export default class LongPressGestureHandler extends GestureHandler {
88
112
  }
89
113
  }
90
114
 
91
- private tryBegin(event: AdaptedEvent): void {
115
+ protected onPointerRemove(event: AdaptedEvent): void {
116
+ super.onPointerRemove(event);
117
+ this.tracker.removeFromTracker(event.pointerId);
118
+
119
+ if (
120
+ this.tracker.getTrackedPointersCount() < this.numberOfPointers &&
121
+ this.getState() !== State.ACTIVE
122
+ ) {
123
+ this.fail();
124
+ }
125
+ }
126
+
127
+ private tryBegin(): void {
92
128
  if (this.currentState !== State.UNDETERMINED) {
93
129
  return;
94
130
  }
@@ -97,12 +133,13 @@ export default class LongPressGestureHandler extends GestureHandler {
97
133
  this.startTime = this.previousTime;
98
134
 
99
135
  this.begin();
100
-
101
- this.startX = event.x;
102
- this.startY = event.y;
103
136
  }
104
137
 
105
138
  private tryActivate(): void {
139
+ if (this.tracker.getTrackedPointersCount() !== this.numberOfPointers) {
140
+ return;
141
+ }
142
+
106
143
  if (this.minDurationMs > 0) {
107
144
  this.activationTimeout = setTimeout(() => {
108
145
  this.activate();
@@ -112,9 +149,11 @@ export default class LongPressGestureHandler extends GestureHandler {
112
149
  }
113
150
  }
114
151
 
115
- private checkDistanceFail(event: AdaptedEvent): void {
116
- const dx = event.x - this.startX;
117
- const dy = event.y - this.startY;
152
+ private checkDistanceFail(): void {
153
+ const absoluteCoordsAverage = this.tracker.getAbsoluteCoordsAverage();
154
+
155
+ const dx = absoluteCoordsAverage.x - this.startX;
156
+ const dy = absoluteCoordsAverage.y - this.startY;
118
157
  const distSq = dx * dx + dy * dy;
119
158
 
120
159
  if (distSq <= this.maxDistSq) {
@@ -27,10 +27,7 @@ export default class NativeViewGestureHandler extends GestureHandler {
27
27
 
28
28
  const view = this.delegate.getView() as HTMLElement;
29
29
 
30
- view.style['touchAction'] = 'auto';
31
- // @ts-ignore Turns on defualt touch behavior on Safari
32
- view.style['WebkitTouchCallout'] = 'auto';
33
-
30
+ this.restoreViewStyles(view);
34
31
  this.buttonRole = view.getAttribute('role') === 'button';
35
32
  }
36
33
 
@@ -43,6 +40,19 @@ export default class NativeViewGestureHandler extends GestureHandler {
43
40
  if (this.config.disallowInterruption !== undefined) {
44
41
  this.disallowInterruption = this.config.disallowInterruption;
45
42
  }
43
+
44
+ const view = this.delegate.getView() as HTMLElement;
45
+ this.restoreViewStyles(view);
46
+ }
47
+
48
+ private restoreViewStyles(view: HTMLElement) {
49
+ if (!view) {
50
+ return;
51
+ }
52
+
53
+ view.style['touchAction'] = 'auto';
54
+ // @ts-ignore Turns on defualt touch behavior on Safari
55
+ view.style['WebkitTouchCallout'] = 'auto';
46
56
  }
47
57
 
48
58
  protected resetConfig(): void {
@@ -268,6 +268,10 @@ export default class PanGestureHandler extends GestureHandler {
268
268
 
269
269
  this.tracker.removeFromTracker(event.pointerId);
270
270
 
271
+ if (this.tracker.getTrackedPointersCount() === 0) {
272
+ this.clearActivationTimeout();
273
+ }
274
+
271
275
  if (this.currentState === State.ACTIVE) {
272
276
  this.end();
273
277
  } else {
@@ -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;
@@ -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
  }
@@ -11,13 +11,24 @@ import { isPointerInBounds } from '../utils';
11
11
  import EventManager from './EventManager';
12
12
  import { Config } from '../interfaces';
13
13
  import { MouseButton } from '../../handlers/gestureHandlerCommon';
14
+ import KeyboardEventManager from './KeyboardEventManager';
15
+
16
+ interface DefaultViewStyles {
17
+ userSelect: string;
18
+ touchAction: string;
19
+ }
14
20
 
15
21
  export class GestureHandlerWebDelegate
16
22
  implements GestureHandlerDelegate<HTMLElement, IGestureHandler>
17
23
  {
24
+ private isInitialized = false;
18
25
  private view!: HTMLElement;
19
26
  private gestureHandler!: IGestureHandler;
20
27
  private eventManagers: EventManager<unknown>[] = [];
28
+ private defaultViewStyles: DefaultViewStyles = {
29
+ userSelect: '',
30
+ touchAction: '',
31
+ };
21
32
 
22
33
  getView(): HTMLElement {
23
34
  return this.view;
@@ -30,22 +41,25 @@ export class GestureHandlerWebDelegate
30
41
  );
31
42
  }
32
43
 
44
+ this.isInitialized = true;
45
+
33
46
  this.gestureHandler = handler;
34
47
  this.view = findNodeHandle(viewRef) as unknown as HTMLElement;
35
48
 
36
- const config = handler.getConfig();
49
+ this.defaultViewStyles = {
50
+ userSelect: this.view.style.userSelect,
51
+ touchAction: this.view.style.touchAction,
52
+ };
37
53
 
38
- this.addContextMenuListeners(config);
54
+ const config = handler.getConfig();
39
55
 
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';
56
+ this.setUserSelect(config.enabled);
57
+ this.setTouchAction(config.enabled);
58
+ this.setContextMenu(config.enabled);
46
59
 
47
60
  this.eventManagers.push(new PointerEventManager(this.view));
48
61
  this.eventManagers.push(new TouchEventManager(this.view));
62
+ this.eventManagers.push(new KeyboardEventManager(this.view));
49
63
 
50
64
  this.eventManagers.forEach((manager) =>
51
65
  this.gestureHandler.attachEventManager(manager)
@@ -117,6 +131,51 @@ export class GestureHandlerWebDelegate
117
131
  e.stopPropagation();
118
132
  }
119
133
 
134
+ private setUserSelect(isHandlerEnabled: boolean) {
135
+ const { userSelect } = this.gestureHandler.getConfig();
136
+
137
+ this.view.style['userSelect'] = isHandlerEnabled
138
+ ? userSelect ?? 'none'
139
+ : this.defaultViewStyles.userSelect;
140
+
141
+ this.view.style['webkitUserSelect'] = isHandlerEnabled
142
+ ? userSelect ?? 'none'
143
+ : this.defaultViewStyles.userSelect;
144
+ }
145
+
146
+ private setTouchAction(isHandlerEnabled: boolean) {
147
+ const { touchAction } = this.gestureHandler.getConfig();
148
+
149
+ this.view.style['touchAction'] = isHandlerEnabled
150
+ ? touchAction ?? 'none'
151
+ : this.defaultViewStyles.touchAction;
152
+
153
+ // @ts-ignore This one disables default events on Safari
154
+ this.view.style['WebkitTouchCallout'] = isHandlerEnabled
155
+ ? touchAction ?? 'none'
156
+ : this.defaultViewStyles.touchAction;
157
+ }
158
+
159
+ private setContextMenu(isHandlerEnabled: boolean) {
160
+ const config = this.gestureHandler.getConfig();
161
+
162
+ if (isHandlerEnabled) {
163
+ this.addContextMenuListeners(config);
164
+ } else {
165
+ this.removeContextMenuListeners(config);
166
+ }
167
+ }
168
+
169
+ onEnabledChange(enabled: boolean): void {
170
+ if (!this.isInitialized) {
171
+ return;
172
+ }
173
+
174
+ this.setUserSelect(enabled);
175
+ this.setTouchAction(enabled);
176
+ this.setContextMenu(enabled);
177
+ }
178
+
120
179
  onBegin(): void {
121
180
  // no-op for now
122
181
  }
@@ -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
+ }
@@ -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
@@ -27,28 +27,30 @@ 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;
46
- }
47
-
48
- const matrixElementsArray = matrixElements.split(', ');
48
+ if (matrixElements) {
49
+ const matrixElementsArray = matrixElements.split(', ');
49
50
 
50
- resultScales.scaleX *= parseFloat(matrixElementsArray[0]);
51
- resultScales.scaleY *= parseFloat(matrixElementsArray[3]);
51
+ resultScales.scaleX *= parseFloat(matrixElementsArray[0]);
52
+ resultScales.scaleY *= parseFloat(matrixElementsArray[3]);
53
+ }
52
54
 
53
55
  return resultScales;
54
56
  }