@react-native-oh-tpl/react-native-gesture-handler 2.12.6-1 → 2.12.6-2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/harmony/gesture_handler/LICENSE +21 -0
  2. package/harmony/gesture_handler/OAT.xml +44 -0
  3. package/harmony/gesture_handler/README.OpenSource +11 -0
  4. package/harmony/gesture_handler/README.md +1 -0
  5. package/harmony/gesture_handler/build-profile.json5 +7 -7
  6. package/harmony/gesture_handler/hvigorfile.ts +2 -2
  7. package/harmony/gesture_handler/index.ets +2 -2
  8. package/harmony/gesture_handler/oh-package.json5 +13 -11
  9. package/harmony/gesture_handler/src/main/cpp/CMakeLists.txt +8 -8
  10. package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.cpp +33 -33
  11. package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.h +14 -14
  12. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerButtonComponentDescriptor.h +60 -60
  13. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.cpp +17 -17
  14. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.h +11 -11
  15. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerRootViewComponentDescriptor.h +60 -60
  16. package/harmony/gesture_handler/src/main/ets/CircularBuffer.ts +42 -42
  17. package/harmony/gesture_handler/src/main/ets/Event.ts +67 -67
  18. package/harmony/gesture_handler/src/main/ets/EventDispatcher.ts +37 -37
  19. package/harmony/gesture_handler/src/main/ets/GestureHandler.ts +663 -663
  20. package/harmony/gesture_handler/src/main/ets/GestureHandlerArkUIAdapter.ets +201 -201
  21. package/harmony/gesture_handler/src/main/ets/GestureHandlerFactory.ts +44 -44
  22. package/harmony/gesture_handler/src/main/ets/GestureHandlerOrchestrator.ts +280 -280
  23. package/harmony/gesture_handler/src/main/ets/GestureHandlerPackage.ts +22 -22
  24. package/harmony/gesture_handler/src/main/ets/GestureHandlerRegistry.ts +27 -27
  25. package/harmony/gesture_handler/src/main/ets/InteractionManager.ts +108 -108
  26. package/harmony/gesture_handler/src/main/ets/LeastSquareSolver.ts +182 -182
  27. package/harmony/gesture_handler/src/main/ets/NativeViewGestureHandler.ts +114 -114
  28. package/harmony/gesture_handler/src/main/ets/OutgoingEvent.ts +33 -33
  29. package/harmony/gesture_handler/src/main/ets/PanGestureHandler.ts +327 -327
  30. package/harmony/gesture_handler/src/main/ets/PointerTracker.ts +239 -239
  31. package/harmony/gesture_handler/src/main/ets/RNGHError.ts +4 -4
  32. package/harmony/gesture_handler/src/main/ets/RNGHLogger.ts +28 -28
  33. package/harmony/gesture_handler/src/main/ets/RNGHRootTouchHandler.ets +57 -57
  34. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerButton.ets +36 -36
  35. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerModule.ts +125 -125
  36. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerRootView.ets +56 -55
  37. package/harmony/gesture_handler/src/main/ets/RNOHScrollLocker.ts +10 -10
  38. package/harmony/gesture_handler/src/main/ets/State.ts +46 -46
  39. package/harmony/gesture_handler/src/main/ets/TapGestureHandler.ts +205 -205
  40. package/harmony/gesture_handler/src/main/ets/Vector2D.ts +36 -36
  41. package/harmony/gesture_handler/src/main/ets/VelocityTracker.ts +98 -98
  42. package/harmony/gesture_handler/src/main/ets/View.ts +70 -70
  43. package/harmony/gesture_handler/src/main/ets/ViewRegistry.ts +42 -42
  44. package/harmony/gesture_handler/src/main/ets/pages/Index.ets +16 -16
  45. package/harmony/gesture_handler/src/main/ets/webviewability/WebviewAbility.ts +41 -41
  46. package/harmony/gesture_handler/src/main/module.json5 +6 -6
  47. package/harmony/gesture_handler/src/main/resources/base/element/color.json +7 -7
  48. package/harmony/gesture_handler/src/main/resources/base/element/string.json +15 -15
  49. package/harmony/gesture_handler/src/main/resources/base/profile/main_pages.json +5 -5
  50. package/harmony/gesture_handler/src/main/resources/en_US/element/string.json +15 -15
  51. package/harmony/gesture_handler/src/main/resources/zh_CN/element/string.json +15 -15
  52. package/harmony/gesture_handler.har +0 -0
  53. package/lib/commonjs/components/touchables/GenericTouchable.js +9 -9
  54. package/lib/commonjs/components/touchables/TouchableOpacity.js +2 -2
  55. package/lib/commonjs/handlers/createNativeWrapper.js +6 -6
  56. package/lib/commonjs/handlers/gestures/GestureDetector.js +3 -3
  57. package/lib/module/components/touchables/GenericTouchable.js +9 -9
  58. package/lib/module/components/touchables/TouchableOpacity.js +2 -2
  59. package/lib/module/handlers/createNativeWrapper.js +6 -6
  60. package/lib/module/handlers/gestures/GestureDetector.js +3 -3
  61. package/package.json +70 -70
  62. package/src/RNGestureHandlerModule.ts +6 -6
  63. package/src/components/GestureButtons.tsx +334 -334
  64. package/src/components/GestureHandlerButton.tsx +5 -5
  65. package/src/components/GestureHandlerRootView.tsx +34 -34
  66. package/src/components/RNGestureHandlerButton.tsx +23 -23
  67. package/src/components/touchables/GenericTouchable.tsx +301 -301
  68. package/src/components/touchables/TouchableOpacity.tsx +76 -76
  69. package/src/components/touchables/TouchableWithoutFeedback.tsx +14 -14
  70. package/src/components/touchables/index.ts +7 -7
  71. package/src/handlers/NativeViewGestureHandler.ts +55 -55
  72. package/src/handlers/PanGestureHandler.ts +327 -327
  73. package/src/handlers/TapGestureHandler.ts +95 -95
  74. package/src/handlers/createHandler.tsx +535 -535
  75. package/src/handlers/createNativeWrapper.tsx +81 -81
  76. package/src/handlers/gestureHandlerCommon.ts +15 -15
  77. package/src/handlers/gestures/GestureDetector.tsx +823 -823
  78. package/src/index.ts +172 -172
  79. package/src/init.ts +18 -18
@@ -1,301 +1,301 @@
1
- import * as React from 'react';
2
- import { Component } from 'react';
3
- import {
4
- Animated,
5
- Platform,
6
- StyleProp,
7
- ViewStyle,
8
- TouchableWithoutFeedbackProps,
9
- Insets,
10
- } from 'react-native';
11
-
12
- import { State } from 'react-native-gesture-handler/src/State';
13
- import { BaseButton } from '../GestureButtons';
14
-
15
- import {
16
- GestureEvent,
17
- HandlerStateChangeEvent,
18
- } from 'react-native-gesture-handler/src/handlers/gestureHandlerCommon';
19
- import { NativeViewGestureHandlerPayload } from 'react-native-gesture-handler/src/handlers/NativeViewGestureHandler';
20
-
21
- /**
22
- * Each touchable is a states' machine which preforms transitions.
23
- * On very beginning (and on the very end or recognition) touchable is
24
- * UNDETERMINED. Then it moves to BEGAN. If touchable recognizes that finger
25
- * travel outside it transits to special MOVED_OUTSIDE state. Gesture recognition
26
- * finishes in UNDETERMINED state.
27
- */
28
- export const TOUCHABLE_STATE = {
29
- UNDETERMINED: 0,
30
- BEGAN: 1,
31
- MOVED_OUTSIDE: 2,
32
- } as const;
33
-
34
- type TouchableState = (typeof TOUCHABLE_STATE)[keyof typeof TOUCHABLE_STATE];
35
-
36
- export interface GenericTouchableProps
37
- extends Omit<TouchableWithoutFeedbackProps, 'hitSlop'> {
38
- // Decided to drop not used fields from RN's implementation.
39
- // e.g. onBlur and onFocus as well as deprecated props. - TODO: this comment may be unuseful in this moment
40
-
41
- // TODO: in RN these events get native event parameter, which prolly could be used in our implementation too
42
- onPress?: () => void;
43
- onPressIn?: () => void;
44
- onPressOut?: () => void;
45
- onLongPress?: () => void;
46
-
47
- nativeID?: string;
48
- shouldActivateOnStart?: boolean;
49
- disallowInterruption?: boolean;
50
-
51
- containerStyle?: StyleProp<ViewStyle>;
52
- hitSlop?: Insets | number;
53
- }
54
-
55
- interface InternalProps {
56
- extraButtonProps: any;
57
- onStateChange?: (oldState: TouchableState, newState: TouchableState) => void;
58
- }
59
-
60
- // TODO: maybe can be better
61
- // TODO: all clearTimeout have ! added, maybe they shouldn't ?
62
- type Timeout = ReturnType<typeof setTimeout> | null | undefined;
63
-
64
- /**
65
- * GenericTouchable is not intented to be used as it is.
66
- * Should be treated as a source for the rest of touchables
67
- */
68
-
69
- export default class GenericTouchable extends Component<
70
- GenericTouchableProps & InternalProps
71
- > {
72
- static defaultProps = {
73
- delayLongPress: 600,
74
- extraButtonProps: {
75
- rippleColor: 'transparent',
76
- exclusive: true,
77
- },
78
- };
79
-
80
- // timeout handlers
81
- pressInTimeout: Timeout;
82
- pressOutTimeout: Timeout;
83
- longPressTimeout: Timeout;
84
-
85
- // This flag is required since recognition of longPress implies not-invoking onPress
86
- longPressDetected = false;
87
-
88
- pointerInside = true;
89
-
90
- // State of touchable
91
- STATE: TouchableState = TOUCHABLE_STATE.UNDETERMINED;
92
-
93
- // handlePressIn in called on first touch on traveling inside component.
94
- // Handles state transition with delay.
95
- handlePressIn() {
96
- if (this.props.delayPressIn) {
97
- this.pressInTimeout = setTimeout(() => {
98
- this.moveToState(TOUCHABLE_STATE.BEGAN);
99
- this.pressInTimeout = null;
100
- }, this.props.delayPressIn);
101
- } else {
102
- this.moveToState(TOUCHABLE_STATE.BEGAN);
103
- }
104
- if (this.props.onLongPress) {
105
- const time =
106
- (this.props.delayPressIn || 0) + (this.props.delayLongPress || 0);
107
- this.longPressTimeout = setTimeout(this.onLongPressDetected, time);
108
- }
109
- }
110
- // handleMoveOutside in called on traveling outside component.
111
- // Handles state transition with delay.
112
- handleMoveOutside() {
113
- if (this.props.delayPressOut) {
114
- this.pressOutTimeout =
115
- this.pressOutTimeout ||
116
- setTimeout(() => {
117
- this.moveToState(TOUCHABLE_STATE.MOVED_OUTSIDE);
118
- this.pressOutTimeout = null;
119
- }, this.props.delayPressOut);
120
- } else {
121
- this.moveToState(TOUCHABLE_STATE.MOVED_OUTSIDE);
122
- }
123
- }
124
-
125
- // handleGoToUndetermined transits to UNDETERMINED state with proper delay
126
- handleGoToUndetermined() {
127
- clearTimeout(this.pressOutTimeout!); // TODO: maybe it can be undefined
128
- if (this.props.delayPressOut) {
129
- this.pressOutTimeout = setTimeout(() => {
130
- if (this.STATE === TOUCHABLE_STATE.UNDETERMINED) {
131
- this.moveToState(TOUCHABLE_STATE.BEGAN);
132
- }
133
- this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
134
- this.pressOutTimeout = null;
135
- }, this.props.delayPressOut);
136
- } else {
137
- if (this.STATE === TOUCHABLE_STATE.UNDETERMINED) {
138
- this.moveToState(TOUCHABLE_STATE.BEGAN);
139
- }
140
- this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
141
- }
142
- }
143
-
144
- componentDidMount() {
145
- this.reset();
146
- }
147
- // reset timeout to prevent memory leaks.
148
- reset() {
149
- this.longPressDetected = false;
150
- this.pointerInside = true;
151
- clearTimeout(this.pressInTimeout!);
152
- clearTimeout(this.pressOutTimeout!);
153
- clearTimeout(this.longPressTimeout!);
154
- this.pressOutTimeout = null;
155
- this.longPressTimeout = null;
156
- this.pressInTimeout = null;
157
- }
158
-
159
- // All states' transitions are defined here.
160
- moveToState(newState: TouchableState) {
161
- if (newState === this.STATE) {
162
- // Ignore dummy transitions
163
- return;
164
- }
165
- if (newState === TOUCHABLE_STATE.BEGAN) {
166
- // First touch and moving inside
167
- this.props.onPressIn?.();
168
- } else if (newState === TOUCHABLE_STATE.MOVED_OUTSIDE) {
169
- // Moving outside
170
- this.props.onPressOut?.();
171
- } else if (newState === TOUCHABLE_STATE.UNDETERMINED) {
172
- // Need to reset each time on transition to UNDETERMINED
173
- this.reset();
174
- if (this.STATE === TOUCHABLE_STATE.BEGAN) {
175
- // ... and if it happens inside button.
176
- this.props.onPressOut?.();
177
- }
178
- }
179
- // Finally call lister (used by subclasses)
180
- this.props.onStateChange?.(this.STATE, newState);
181
- // ... and make transition.
182
- this.STATE = newState;
183
- }
184
-
185
- onGestureEvent = ({
186
- nativeEvent: { pointerInside },
187
- }: GestureEvent<NativeViewGestureHandlerPayload>) => {
188
- if (this.pointerInside !== pointerInside) {
189
- if (pointerInside) {
190
- this.onMoveIn();
191
- } else {
192
- this.onMoveOut();
193
- }
194
- }
195
- this.pointerInside = pointerInside;
196
- };
197
-
198
- onHandlerStateChange = ({
199
- nativeEvent,
200
- }: HandlerStateChangeEvent<NativeViewGestureHandlerPayload>) => {
201
- const { state } = nativeEvent;
202
- if (state === State.CANCELLED || state === State.FAILED) {
203
- // Need to handle case with external cancellation (e.g. by ScrollView)
204
- this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
205
- } else if (
206
- // This platform check is an implication of slightly different behavior of handlers on different platform.
207
- // And Android "Active" state is achieving on first move of a finger, not on press in.
208
- // On iOS event on "Began" is not delivered.
209
- state === (Platform.OS !== 'android' ? State.ACTIVE : State.BEGAN) &&
210
- this.STATE === TOUCHABLE_STATE.UNDETERMINED
211
- ) {
212
- // Moving inside requires
213
- this.handlePressIn();
214
- } else if (state === State.END) {
215
- const shouldCallOnPress =
216
- !this.longPressDetected &&
217
- this.STATE !== TOUCHABLE_STATE.MOVED_OUTSIDE &&
218
- this.pressOutTimeout === null;
219
- this.handleGoToUndetermined();
220
- if (shouldCallOnPress) {
221
- // Calls only inside component whether no long press was called previously
222
- this.props.onPress?.();
223
- }
224
- }
225
- };
226
-
227
- onLongPressDetected = () => {
228
- this.longPressDetected = true;
229
- // checked for in the caller of `onLongPressDetected`, but better to check twice
230
- this.props.onLongPress?.();
231
- };
232
-
233
- componentWillUnmount() {
234
- // to prevent memory leaks
235
- this.reset();
236
- }
237
-
238
- onMoveIn() {
239
- if (this.STATE === TOUCHABLE_STATE.MOVED_OUTSIDE) {
240
- // This call is not throttled with delays (like in RN's implementation).
241
- this.moveToState(TOUCHABLE_STATE.BEGAN);
242
- }
243
- }
244
-
245
- onMoveOut() {
246
- // long press should no longer be detected
247
- clearTimeout(this.longPressTimeout!);
248
- this.longPressTimeout = null;
249
- if (this.STATE === TOUCHABLE_STATE.BEGAN) {
250
- this.handleMoveOutside();
251
- }
252
- }
253
-
254
- render() {
255
- const hitSlop =
256
- (typeof this.props.hitSlop === 'number'
257
- ? {
258
- top: this.props.hitSlop,
259
- left: this.props.hitSlop,
260
- bottom: this.props.hitSlop,
261
- right: this.props.hitSlop,
262
- }
263
- : this.props.hitSlop) ?? undefined;
264
-
265
- const coreProps = {
266
- accessible: this.props.accessible !== false,
267
- accessibilityLabel: this.props.accessibilityLabel,
268
- accessibilityHint: this.props.accessibilityHint,
269
- accessibilityRole: this.props.accessibilityRole,
270
- // TODO: check if changed to no 's' correctly, also removed 2 props that are no longer available: `accessibilityComponentType` and `accessibilityTraits`,
271
- // would be good to check if it is ok for sure, see: https://github.com/facebook/react-native/issues/24016
272
- accessibilityState: this.props.accessibilityState,
273
- accessibilityActions: this.props.accessibilityActions,
274
- onAccessibilityAction: this.props.onAccessibilityAction,
275
- nativeID: this.props.nativeID,
276
- onLayout: this.props.onLayout,
277
- };
278
-
279
- return (
280
- <BaseButton
281
- style={this.props.containerStyle}
282
- onHandlerStateChange={
283
- // TODO: not sure if it can be undefined instead of null
284
- this.props.disabled ? undefined : this.onHandlerStateChange
285
- }
286
- onGestureEvent={this.onGestureEvent}
287
- hitSlop={hitSlop}
288
- shouldActivateOnStart={this.props.shouldActivateOnStart}
289
- disallowInterruption={this.props.disallowInterruption}
290
- testID={this.props.testID}
291
- touchSoundDisabled={this.props.touchSoundDisabled ?? false}
292
- enabled={!this.props.disabled}
293
- {...this.props.extraButtonProps}
294
- >
295
- <Animated.View {...coreProps} style={this.props.style}>
296
- {this.props.children}
297
- </Animated.View>
298
- </BaseButton>
299
- );
300
- }
301
- }
1
+ import * as React from 'react';
2
+ import { Component } from 'react';
3
+ import {
4
+ Animated,
5
+ Platform,
6
+ StyleProp,
7
+ ViewStyle,
8
+ TouchableWithoutFeedbackProps,
9
+ Insets,
10
+ } from 'react-native';
11
+
12
+ import { State } from 'react-native-gesture-handler/src/State';
13
+ import { BaseButton } from '../GestureButtons';
14
+
15
+ import {
16
+ GestureEvent,
17
+ HandlerStateChangeEvent,
18
+ } from 'react-native-gesture-handler/src/handlers/gestureHandlerCommon';
19
+ import { NativeViewGestureHandlerPayload } from 'react-native-gesture-handler/src/handlers/NativeViewGestureHandler';
20
+
21
+ /**
22
+ * Each touchable is a states' machine which preforms transitions.
23
+ * On very beginning (and on the very end or recognition) touchable is
24
+ * UNDETERMINED. Then it moves to BEGAN. If touchable recognizes that finger
25
+ * travel outside it transits to special MOVED_OUTSIDE state. Gesture recognition
26
+ * finishes in UNDETERMINED state.
27
+ */
28
+ export const TOUCHABLE_STATE = {
29
+ UNDETERMINED: 0,
30
+ BEGAN: 1,
31
+ MOVED_OUTSIDE: 2,
32
+ } as const;
33
+
34
+ type TouchableState = (typeof TOUCHABLE_STATE)[keyof typeof TOUCHABLE_STATE];
35
+
36
+ export interface GenericTouchableProps
37
+ extends Omit<TouchableWithoutFeedbackProps, 'hitSlop'> {
38
+ // Decided to drop not used fields from RN's implementation.
39
+ // e.g. onBlur and onFocus as well as deprecated props. - TODO: this comment may be unuseful in this moment
40
+
41
+ // TODO: in RN these events get native event parameter, which prolly could be used in our implementation too
42
+ onPress?: () => void;
43
+ onPressIn?: () => void;
44
+ onPressOut?: () => void;
45
+ onLongPress?: () => void;
46
+
47
+ nativeID?: string;
48
+ shouldActivateOnStart?: boolean;
49
+ disallowInterruption?: boolean;
50
+
51
+ containerStyle?: StyleProp<ViewStyle>;
52
+ hitSlop?: Insets | number;
53
+ }
54
+
55
+ interface InternalProps {
56
+ extraButtonProps: any;
57
+ onStateChange?: (oldState: TouchableState, newState: TouchableState) => void;
58
+ }
59
+
60
+ // TODO: maybe can be better
61
+ // TODO: all clearTimeout have ! added, maybe they shouldn't ?
62
+ type Timeout = ReturnType<typeof setTimeout> | null | undefined;
63
+
64
+ /**
65
+ * GenericTouchable is not intented to be used as it is.
66
+ * Should be treated as a source for the rest of touchables
67
+ */
68
+
69
+ export default class GenericTouchable extends Component<
70
+ GenericTouchableProps & InternalProps
71
+ > {
72
+ static defaultProps = {
73
+ delayLongPress: 600,
74
+ extraButtonProps: {
75
+ rippleColor: 'transparent',
76
+ exclusive: true,
77
+ },
78
+ };
79
+
80
+ // timeout handlers
81
+ pressInTimeout: Timeout;
82
+ pressOutTimeout: Timeout;
83
+ longPressTimeout: Timeout;
84
+
85
+ // This flag is required since recognition of longPress implies not-invoking onPress
86
+ longPressDetected = false;
87
+
88
+ pointerInside = true;
89
+
90
+ // State of touchable
91
+ STATE: TouchableState = TOUCHABLE_STATE.UNDETERMINED;
92
+
93
+ // handlePressIn in called on first touch on traveling inside component.
94
+ // Handles state transition with delay.
95
+ handlePressIn() {
96
+ if (this.props.delayPressIn) {
97
+ this.pressInTimeout = setTimeout(() => {
98
+ this.moveToState(TOUCHABLE_STATE.BEGAN);
99
+ this.pressInTimeout = null;
100
+ }, this.props.delayPressIn);
101
+ } else {
102
+ this.moveToState(TOUCHABLE_STATE.BEGAN);
103
+ }
104
+ if (this.props.onLongPress) {
105
+ const time =
106
+ (this.props.delayPressIn || 0) + (this.props.delayLongPress || 0);
107
+ this.longPressTimeout = setTimeout(this.onLongPressDetected, time);
108
+ }
109
+ }
110
+ // handleMoveOutside in called on traveling outside component.
111
+ // Handles state transition with delay.
112
+ handleMoveOutside() {
113
+ if (this.props.delayPressOut) {
114
+ this.pressOutTimeout =
115
+ this.pressOutTimeout ||
116
+ setTimeout(() => {
117
+ this.moveToState(TOUCHABLE_STATE.MOVED_OUTSIDE);
118
+ this.pressOutTimeout = null;
119
+ }, this.props.delayPressOut);
120
+ } else {
121
+ this.moveToState(TOUCHABLE_STATE.MOVED_OUTSIDE);
122
+ }
123
+ }
124
+
125
+ // handleGoToUndetermined transits to UNDETERMINED state with proper delay
126
+ handleGoToUndetermined() {
127
+ clearTimeout(this.pressOutTimeout!); // TODO: maybe it can be undefined
128
+ if (this.props.delayPressOut) {
129
+ this.pressOutTimeout = setTimeout(() => {
130
+ if (this.STATE === TOUCHABLE_STATE.UNDETERMINED) {
131
+ this.moveToState(TOUCHABLE_STATE.BEGAN);
132
+ }
133
+ this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
134
+ this.pressOutTimeout = null;
135
+ }, this.props.delayPressOut);
136
+ } else {
137
+ if (this.STATE === TOUCHABLE_STATE.UNDETERMINED) {
138
+ this.moveToState(TOUCHABLE_STATE.BEGAN);
139
+ }
140
+ this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
141
+ }
142
+ }
143
+
144
+ componentDidMount() {
145
+ this.reset();
146
+ }
147
+ // reset timeout to prevent memory leaks.
148
+ reset() {
149
+ this.longPressDetected = false;
150
+ this.pointerInside = true;
151
+ clearTimeout(this.pressInTimeout!);
152
+ clearTimeout(this.pressOutTimeout!);
153
+ clearTimeout(this.longPressTimeout!);
154
+ this.pressOutTimeout = null;
155
+ this.longPressTimeout = null;
156
+ this.pressInTimeout = null;
157
+ }
158
+
159
+ // All states' transitions are defined here.
160
+ moveToState(newState: TouchableState) {
161
+ if (newState === this.STATE) {
162
+ // Ignore dummy transitions
163
+ return;
164
+ }
165
+ if (newState === TOUCHABLE_STATE.BEGAN) {
166
+ // First touch and moving inside
167
+ this.props.onPressIn?.();
168
+ } else if (newState === TOUCHABLE_STATE.MOVED_OUTSIDE) {
169
+ // Moving outside
170
+ this.props.onPressOut?.();
171
+ } else if (newState === TOUCHABLE_STATE.UNDETERMINED) {
172
+ // Need to reset each time on transition to UNDETERMINED
173
+ this.reset();
174
+ if (this.STATE === TOUCHABLE_STATE.BEGAN) {
175
+ // ... and if it happens inside button.
176
+ this.props.onPressOut?.();
177
+ }
178
+ }
179
+ // Finally call lister (used by subclasses)
180
+ this.props.onStateChange?.(this.STATE, newState);
181
+ // ... and make transition.
182
+ this.STATE = newState;
183
+ }
184
+
185
+ onGestureEvent = ({
186
+ nativeEvent: { pointerInside },
187
+ }: GestureEvent<NativeViewGestureHandlerPayload>) => {
188
+ if (this.pointerInside !== pointerInside) {
189
+ if (pointerInside) {
190
+ this.onMoveIn();
191
+ } else {
192
+ this.onMoveOut();
193
+ }
194
+ }
195
+ this.pointerInside = pointerInside;
196
+ };
197
+
198
+ onHandlerStateChange = ({
199
+ nativeEvent,
200
+ }: HandlerStateChangeEvent<NativeViewGestureHandlerPayload>) => {
201
+ const { state } = nativeEvent;
202
+ if (state === State.CANCELLED || state === State.FAILED) {
203
+ // Need to handle case with external cancellation (e.g. by ScrollView)
204
+ this.moveToState(TOUCHABLE_STATE.UNDETERMINED);
205
+ } else if (
206
+ // This platform check is an implication of slightly different behavior of handlers on different platform.
207
+ // And Android "Active" state is achieving on first move of a finger, not on press in.
208
+ // On iOS event on "Began" is not delivered.
209
+ state === (Platform.OS !== 'android' ? State.ACTIVE : State.BEGAN) &&
210
+ this.STATE === TOUCHABLE_STATE.UNDETERMINED
211
+ ) {
212
+ // Moving inside requires
213
+ this.handlePressIn();
214
+ } else if (state === State.END) {
215
+ const shouldCallOnPress =
216
+ !this.longPressDetected &&
217
+ this.STATE !== TOUCHABLE_STATE.MOVED_OUTSIDE &&
218
+ this.pressOutTimeout === null;
219
+ this.handleGoToUndetermined();
220
+ if (shouldCallOnPress) {
221
+ // Calls only inside component whether no long press was called previously
222
+ this.props.onPress?.();
223
+ }
224
+ }
225
+ };
226
+
227
+ onLongPressDetected = () => {
228
+ this.longPressDetected = true;
229
+ // checked for in the caller of `onLongPressDetected`, but better to check twice
230
+ this.props.onLongPress?.();
231
+ };
232
+
233
+ componentWillUnmount() {
234
+ // to prevent memory leaks
235
+ this.reset();
236
+ }
237
+
238
+ onMoveIn() {
239
+ if (this.STATE === TOUCHABLE_STATE.MOVED_OUTSIDE) {
240
+ // This call is not throttled with delays (like in RN's implementation).
241
+ this.moveToState(TOUCHABLE_STATE.BEGAN);
242
+ }
243
+ }
244
+
245
+ onMoveOut() {
246
+ // long press should no longer be detected
247
+ clearTimeout(this.longPressTimeout!);
248
+ this.longPressTimeout = null;
249
+ if (this.STATE === TOUCHABLE_STATE.BEGAN) {
250
+ this.handleMoveOutside();
251
+ }
252
+ }
253
+
254
+ render() {
255
+ const hitSlop =
256
+ (typeof this.props.hitSlop === 'number'
257
+ ? {
258
+ top: this.props.hitSlop,
259
+ left: this.props.hitSlop,
260
+ bottom: this.props.hitSlop,
261
+ right: this.props.hitSlop,
262
+ }
263
+ : this.props.hitSlop) ?? undefined;
264
+
265
+ const coreProps = {
266
+ accessible: this.props.accessible !== false,
267
+ accessibilityLabel: this.props.accessibilityLabel,
268
+ accessibilityHint: this.props.accessibilityHint,
269
+ accessibilityRole: this.props.accessibilityRole,
270
+ // TODO: check if changed to no 's' correctly, also removed 2 props that are no longer available: `accessibilityComponentType` and `accessibilityTraits`,
271
+ // would be good to check if it is ok for sure, see: https://github.com/facebook/react-native/issues/24016
272
+ accessibilityState: this.props.accessibilityState,
273
+ accessibilityActions: this.props.accessibilityActions,
274
+ onAccessibilityAction: this.props.onAccessibilityAction,
275
+ nativeID: this.props.nativeID,
276
+ onLayout: this.props.onLayout,
277
+ };
278
+
279
+ return (
280
+ <BaseButton
281
+ style={this.props.containerStyle}
282
+ onHandlerStateChange={
283
+ // TODO: not sure if it can be undefined instead of null
284
+ this.props.disabled ? undefined : this.onHandlerStateChange
285
+ }
286
+ onGestureEvent={this.onGestureEvent}
287
+ hitSlop={hitSlop}
288
+ shouldActivateOnStart={this.props.shouldActivateOnStart}
289
+ disallowInterruption={this.props.disallowInterruption}
290
+ testID={this.props.testID}
291
+ touchSoundDisabled={this.props.touchSoundDisabled ?? false}
292
+ enabled={!this.props.disabled}
293
+ {...this.props.extraButtonProps}
294
+ >
295
+ <Animated.View {...coreProps} style={this.props.style}>
296
+ {this.props.children}
297
+ </Animated.View>
298
+ </BaseButton>
299
+ );
300
+ }
301
+ }