@rootnative/impulse 0.0.0-alpha.0 → 0.0.0-alpha.1
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.
- package/CHANGELOG.md +51 -5
- package/README.md +206 -11
- package/dist/{chunk-5BMRKYVY.js → chunk-2UZTAWUQ.js} +20 -2
- package/dist/chunk-BNSFDNLA.js +75 -0
- package/dist/chunk-DXXGWG4Q.js +136 -0
- package/dist/{chunk-PMR25UCT.js → chunk-HGBCIL6X.js} +1 -1
- package/dist/chunk-HI5PHDJY.js +94 -0
- package/dist/{chunk-IG5RXCYR.js → chunk-IH7SQ5X6.js} +11 -15
- package/dist/chunk-MWCIEVTA.js +199 -0
- package/dist/{chunk-F4RHM4ZK.js → chunk-NYDDZD4G.js} +58 -1
- package/dist/chunk-PGOQSKEJ.js +144 -0
- package/dist/{chunk-FR242SUF.js → chunk-TGOGIZDH.js} +13 -7
- package/dist/chunk-VEPUHGPN.js +12 -0
- package/dist/chunk-YZHAQ4XK.js +136 -0
- package/dist/compose/index.d.ts +1 -1
- package/dist/double-tap/index.d.ts +184 -0
- package/dist/double-tap/index.js +5 -0
- package/dist/drag/index.d.ts +18 -13
- package/dist/drag/index.js +3 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +12 -5
- package/dist/long-press/index.d.ts +219 -0
- package/dist/long-press/index.js +4 -0
- package/dist/pan/index.d.ts +221 -0
- package/dist/pan/index.js +4 -0
- package/dist/pinch/index.d.ts +239 -0
- package/dist/pinch/index.js +4 -0
- package/dist/raw/index.d.ts +3 -3
- package/dist/raw/index.js +2 -2
- package/dist/rotate/index.d.ts +263 -0
- package/dist/rotate/index.js +4 -0
- package/dist/swipe/index.d.ts +254 -0
- package/dist/swipe/index.js +4 -0
- package/dist/tap/index.d.ts +34 -29
- package/dist/tap/index.js +4 -3
- package/dist/tapEvent-KSSojt_l.d.ts +28 -0
- package/dist/{types-Ch2HM3aP.d.ts → types-ChGKY28a.d.ts} +27 -1
- package/dist/{useGestureMemo-Ccv8rB0C.d.ts → useGestureMemo-BRW1EKcJ.d.ts} +1 -1
- package/jest-setup.cjs +32 -1
- package/llms.txt +155 -0
- package/package.json +35 -2
- package/src/index.ts +50 -4
- package/src/intents/double-tap/index.ts +6 -0
- package/src/intents/long-press/index.ts +6 -0
- package/src/intents/pan/index.ts +2 -0
- package/src/intents/pinch/index.ts +2 -0
- package/src/intents/rotate/index.ts +6 -0
- package/src/intents/swipe/index.ts +8 -0
- package/src/intents/tapEvent.ts +50 -0
- package/src/intents/useDoubleTap.ts +321 -0
- package/src/intents/useDrag.ts +49 -28
- package/src/intents/useLongPress.ts +391 -0
- package/src/intents/usePan.ts +444 -0
- package/src/intents/usePinch.ts +483 -0
- package/src/intents/useRotate.ts +507 -0
- package/src/intents/useSwipe.ts +585 -0
- package/src/intents/useTap.ts +51 -60
- package/src/internal/intentResult.ts +67 -0
- package/src/internal/phaseCallbacks.ts +51 -0
- package/src/internal/useGestureMemo.ts +32 -4
- package/src/internal/useLatestCallback.ts +2 -2
- package/src/raw/useRawGesture.ts +1 -1
- package/src/relations/index.ts +94 -0
- package/src/types.ts +27 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useStableRecord, useLatestCallback, buildIntentResult } from './chunk-2UZTAWUQ.js';
|
|
2
|
+
import { useGestureMemo } from './chunk-NYDDZD4G.js';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { Gesture } from 'react-native-gesture-handler';
|
|
5
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
6
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
7
|
+
|
|
8
|
+
var DEFAULT_MIN_DURATION = 500;
|
|
9
|
+
var DEFAULT_MAX_DISTANCE = 10;
|
|
10
|
+
function toLongPressEvent(event) {
|
|
11
|
+
"worklet";
|
|
12
|
+
return {
|
|
13
|
+
x: event.x,
|
|
14
|
+
y: event.y,
|
|
15
|
+
absolute: { x: event.absoluteX, y: event.absoluteY },
|
|
16
|
+
duration: event.duration,
|
|
17
|
+
pointers: event.numberOfPointers
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function useLongPress(options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
minDuration = DEFAULT_MIN_DURATION,
|
|
23
|
+
maxDistance = DEFAULT_MAX_DISTANCE,
|
|
24
|
+
pointers,
|
|
25
|
+
enabled,
|
|
26
|
+
onLongPress,
|
|
27
|
+
onLongPressEnd,
|
|
28
|
+
onBegin,
|
|
29
|
+
onFinalize
|
|
30
|
+
} = options;
|
|
31
|
+
const isActive = useSharedValue(false);
|
|
32
|
+
const hitSlop = useStableRecord(options.hitSlop);
|
|
33
|
+
const handleLongPress = useLatestCallback(onLongPress);
|
|
34
|
+
const handleLongPressEnd = useLatestCallback(onLongPressEnd);
|
|
35
|
+
const hasLongPress = onLongPress !== void 0;
|
|
36
|
+
const hasLongPressEnd = onLongPressEnd !== void 0;
|
|
37
|
+
const built = useGestureMemo(
|
|
38
|
+
"useLongPress",
|
|
39
|
+
() => {
|
|
40
|
+
const press = Gesture.LongPress().minDuration(minDuration).maxDistance(maxDistance).onBegin((event) => {
|
|
41
|
+
"worklet";
|
|
42
|
+
onBegin?.(toLongPressEvent(event));
|
|
43
|
+
}).onStart((event) => {
|
|
44
|
+
"worklet";
|
|
45
|
+
isActive.value = true;
|
|
46
|
+
if (hasLongPress) {
|
|
47
|
+
scheduleOnRN(handleLongPress, toLongPressEvent(event));
|
|
48
|
+
}
|
|
49
|
+
}).onEnd((event, success) => {
|
|
50
|
+
"worklet";
|
|
51
|
+
if (hasLongPressEnd) {
|
|
52
|
+
scheduleOnRN(handleLongPressEnd, toLongPressEvent(event), {
|
|
53
|
+
cancelled: !success
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}).onFinalize((event, success) => {
|
|
57
|
+
"worklet";
|
|
58
|
+
isActive.value = false;
|
|
59
|
+
onFinalize?.(toLongPressEvent(event), success);
|
|
60
|
+
});
|
|
61
|
+
if (pointers !== void 0) {
|
|
62
|
+
press.numberOfPointers(pointers);
|
|
63
|
+
}
|
|
64
|
+
if (hitSlop !== void 0) {
|
|
65
|
+
press.hitSlop(hitSlop);
|
|
66
|
+
}
|
|
67
|
+
if (enabled !== void 0) {
|
|
68
|
+
press.enabled(enabled);
|
|
69
|
+
}
|
|
70
|
+
return press;
|
|
71
|
+
},
|
|
72
|
+
[
|
|
73
|
+
minDuration,
|
|
74
|
+
maxDistance,
|
|
75
|
+
pointers,
|
|
76
|
+
hitSlop,
|
|
77
|
+
enabled,
|
|
78
|
+
hasLongPress,
|
|
79
|
+
hasLongPressEnd,
|
|
80
|
+
handleLongPress,
|
|
81
|
+
handleLongPressEnd,
|
|
82
|
+
isActive,
|
|
83
|
+
onBegin,
|
|
84
|
+
onFinalize
|
|
85
|
+
],
|
|
86
|
+
options
|
|
87
|
+
);
|
|
88
|
+
return useMemo(
|
|
89
|
+
() => buildIntentResult(built, { isActive }),
|
|
90
|
+
[built, isActive]
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { useLongPress };
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { toTapEvent } from './chunk-VEPUHGPN.js';
|
|
2
|
+
import { useStableRecord, useLatestCallback, buildIntentResult } from './chunk-2UZTAWUQ.js';
|
|
3
|
+
import { useGestureMemo } from './chunk-NYDDZD4G.js';
|
|
3
4
|
import { useMemo } from 'react';
|
|
4
5
|
import { Gesture } from 'react-native-gesture-handler';
|
|
5
|
-
import { useSharedValue
|
|
6
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
7
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
6
8
|
|
|
7
9
|
var DEFAULT_MAX_DURATION = 500;
|
|
8
10
|
var DEFAULT_MAX_DISTANCE = 10;
|
|
9
|
-
function toTapEvent(event) {
|
|
10
|
-
"worklet";
|
|
11
|
-
return {
|
|
12
|
-
x: event.x,
|
|
13
|
-
y: event.y,
|
|
14
|
-
absolute: { x: event.absoluteX, y: event.absoluteY },
|
|
15
|
-
pointers: event.numberOfPointers
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
11
|
function useTap(options = {}) {
|
|
19
12
|
const {
|
|
20
13
|
pointers = 1,
|
|
@@ -38,8 +31,8 @@ function useTap(options = {}) {
|
|
|
38
31
|
onBegin?.(toTapEvent(event));
|
|
39
32
|
}).onEnd((event, success) => {
|
|
40
33
|
"worklet";
|
|
41
|
-
if (
|
|
42
|
-
|
|
34
|
+
if (hasTapHandler) {
|
|
35
|
+
scheduleOnRN(handleTap, toTapEvent(event), { cancelled: !success });
|
|
43
36
|
}
|
|
44
37
|
}).onFinalize((event, success) => {
|
|
45
38
|
"worklet";
|
|
@@ -68,7 +61,10 @@ function useTap(options = {}) {
|
|
|
68
61
|
],
|
|
69
62
|
options
|
|
70
63
|
);
|
|
71
|
-
return useMemo(
|
|
64
|
+
return useMemo(
|
|
65
|
+
() => buildIntentResult(built, { isActive }),
|
|
66
|
+
[built, isActive]
|
|
67
|
+
);
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
export { useTap };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { useStableRecord, useLatestCallback, buildIntentResult } from './chunk-2UZTAWUQ.js';
|
|
2
|
+
import { useGestureMemo } from './chunk-NYDDZD4G.js';
|
|
3
|
+
import { useStableList } from './chunk-ZX7WNICB.js';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { Gesture } from 'react-native-gesture-handler';
|
|
6
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
7
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
8
|
+
|
|
9
|
+
var DEFAULT_THRESHOLD = 10;
|
|
10
|
+
var DEFAULT_COMMIT_DISTANCE = 80;
|
|
11
|
+
var DEFAULT_COMMIT_SPEED = 800;
|
|
12
|
+
var ALL_DIRECTIONS = [
|
|
13
|
+
"left",
|
|
14
|
+
"right",
|
|
15
|
+
"up",
|
|
16
|
+
"down"
|
|
17
|
+
];
|
|
18
|
+
function pickDirection(translationX, translationY, velocityX, velocityY, commitDistance, commitSpeed, allowLeft, allowRight, allowUp, allowDown) {
|
|
19
|
+
"worklet";
|
|
20
|
+
const distanceX = Math.abs(translationX);
|
|
21
|
+
const distanceY = Math.abs(translationY);
|
|
22
|
+
if (distanceX >= distanceY) {
|
|
23
|
+
if (distanceX < commitDistance && Math.abs(velocityX) < commitSpeed) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (translationX < 0) {
|
|
27
|
+
return allowLeft ? "left" : null;
|
|
28
|
+
}
|
|
29
|
+
if (translationX > 0) {
|
|
30
|
+
return allowRight ? "right" : null;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (distanceY < commitDistance && Math.abs(velocityY) < commitSpeed) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (translationY < 0) {
|
|
38
|
+
return allowUp ? "up" : null;
|
|
39
|
+
}
|
|
40
|
+
if (translationY > 0) {
|
|
41
|
+
return allowDown ? "down" : null;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function useSwipe(options = {}) {
|
|
46
|
+
const {
|
|
47
|
+
threshold = DEFAULT_THRESHOLD,
|
|
48
|
+
commitDistance = DEFAULT_COMMIT_DISTANCE,
|
|
49
|
+
commitSpeed = DEFAULT_COMMIT_SPEED,
|
|
50
|
+
failOffset,
|
|
51
|
+
pointers,
|
|
52
|
+
enabled,
|
|
53
|
+
onSwipe,
|
|
54
|
+
onSwipeEnd,
|
|
55
|
+
onBegin,
|
|
56
|
+
onUpdate,
|
|
57
|
+
onFinalize
|
|
58
|
+
} = options;
|
|
59
|
+
const x = useSharedValue(0);
|
|
60
|
+
const y = useSharedValue(0);
|
|
61
|
+
const isActive = useSharedValue(false);
|
|
62
|
+
const originX = useSharedValue(0);
|
|
63
|
+
const originY = useSharedValue(0);
|
|
64
|
+
const hitSlop = useStableRecord(options.hitSlop);
|
|
65
|
+
const directions = useStableList(options.directions ?? ALL_DIRECTIONS);
|
|
66
|
+
const allowLeft = directions.includes("left");
|
|
67
|
+
const allowRight = directions.includes("right");
|
|
68
|
+
const allowUp = directions.includes("up");
|
|
69
|
+
const allowDown = directions.includes("down");
|
|
70
|
+
const hasHorizontal = allowLeft || allowRight;
|
|
71
|
+
const hasVertical = allowUp || allowDown;
|
|
72
|
+
const axis = hasHorizontal && !hasVertical ? "x" : hasVertical && !hasHorizontal ? "y" : null;
|
|
73
|
+
const handleSwipe = useLatestCallback(onSwipe);
|
|
74
|
+
const handleSwipeEnd = useLatestCallback(onSwipeEnd);
|
|
75
|
+
const hasSwipe = onSwipe !== void 0;
|
|
76
|
+
const hasSwipeEnd = onSwipeEnd !== void 0;
|
|
77
|
+
const built = useGestureMemo(
|
|
78
|
+
"useSwipe",
|
|
79
|
+
() => {
|
|
80
|
+
const toSwipeEvent = (event, direction) => {
|
|
81
|
+
"worklet";
|
|
82
|
+
const translationX = x.value;
|
|
83
|
+
const translationY = y.value;
|
|
84
|
+
const horizontal = Math.abs(translationX) >= Math.abs(translationY);
|
|
85
|
+
return {
|
|
86
|
+
direction,
|
|
87
|
+
distance: Math.abs(horizontal ? translationX : translationY),
|
|
88
|
+
speed: Math.abs(horizontal ? event.velocityX : event.velocityY),
|
|
89
|
+
translation: { x: translationX, y: translationY },
|
|
90
|
+
velocity: { x: event.velocityX, y: event.velocityY },
|
|
91
|
+
absolute: { x: event.absoluteX, y: event.absoluteY },
|
|
92
|
+
pointers: event.numberOfPointers
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const pan = Gesture.Pan().onBegin((event) => {
|
|
96
|
+
"worklet";
|
|
97
|
+
onBegin?.(toSwipeEvent(event, null));
|
|
98
|
+
}).onStart((event) => {
|
|
99
|
+
"worklet";
|
|
100
|
+
originX.value = event.translationX;
|
|
101
|
+
originY.value = event.translationY;
|
|
102
|
+
x.value = 0;
|
|
103
|
+
y.value = 0;
|
|
104
|
+
isActive.value = true;
|
|
105
|
+
}).onUpdate((event) => {
|
|
106
|
+
"worklet";
|
|
107
|
+
x.value = event.translationX - originX.value;
|
|
108
|
+
y.value = event.translationY - originY.value;
|
|
109
|
+
onUpdate?.(toSwipeEvent(event, null));
|
|
110
|
+
}).onEnd((event, success) => {
|
|
111
|
+
"worklet";
|
|
112
|
+
const direction = success ? pickDirection(
|
|
113
|
+
x.value,
|
|
114
|
+
y.value,
|
|
115
|
+
event.velocityX,
|
|
116
|
+
event.velocityY,
|
|
117
|
+
commitDistance,
|
|
118
|
+
commitSpeed,
|
|
119
|
+
allowLeft,
|
|
120
|
+
allowRight,
|
|
121
|
+
allowUp,
|
|
122
|
+
allowDown
|
|
123
|
+
) : null;
|
|
124
|
+
if (direction !== null && hasSwipe) {
|
|
125
|
+
scheduleOnRN(
|
|
126
|
+
handleSwipe,
|
|
127
|
+
toSwipeEvent(event, direction)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (hasSwipeEnd) {
|
|
131
|
+
scheduleOnRN(handleSwipeEnd, toSwipeEvent(event, direction), {
|
|
132
|
+
cancelled: !success
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}).onFinalize((event, success) => {
|
|
136
|
+
"worklet";
|
|
137
|
+
isActive.value = false;
|
|
138
|
+
onFinalize?.(toSwipeEvent(event, null), success);
|
|
139
|
+
});
|
|
140
|
+
if (axis === "x") {
|
|
141
|
+
pan.activeOffsetX([-threshold, threshold]);
|
|
142
|
+
} else if (axis === "y") {
|
|
143
|
+
pan.activeOffsetY([-threshold, threshold]);
|
|
144
|
+
} else {
|
|
145
|
+
pan.minDistance(threshold);
|
|
146
|
+
}
|
|
147
|
+
if (failOffset !== void 0) {
|
|
148
|
+
if (axis === "x") {
|
|
149
|
+
pan.failOffsetY([-failOffset, failOffset]);
|
|
150
|
+
} else if (axis === "y") {
|
|
151
|
+
pan.failOffsetX([-failOffset, failOffset]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (pointers !== void 0) {
|
|
155
|
+
pan.minPointers(pointers).maxPointers(pointers);
|
|
156
|
+
}
|
|
157
|
+
if (hitSlop !== void 0) {
|
|
158
|
+
pan.hitSlop(hitSlop);
|
|
159
|
+
}
|
|
160
|
+
if (enabled !== void 0) {
|
|
161
|
+
pan.enabled(enabled);
|
|
162
|
+
}
|
|
163
|
+
return pan;
|
|
164
|
+
},
|
|
165
|
+
[
|
|
166
|
+
axis,
|
|
167
|
+
threshold,
|
|
168
|
+
commitDistance,
|
|
169
|
+
commitSpeed,
|
|
170
|
+
failOffset,
|
|
171
|
+
pointers,
|
|
172
|
+
hitSlop,
|
|
173
|
+
enabled,
|
|
174
|
+
allowLeft,
|
|
175
|
+
allowRight,
|
|
176
|
+
allowUp,
|
|
177
|
+
allowDown,
|
|
178
|
+
hasSwipe,
|
|
179
|
+
hasSwipeEnd,
|
|
180
|
+
handleSwipe,
|
|
181
|
+
handleSwipeEnd,
|
|
182
|
+
x,
|
|
183
|
+
y,
|
|
184
|
+
originX,
|
|
185
|
+
originY,
|
|
186
|
+
isActive,
|
|
187
|
+
onBegin,
|
|
188
|
+
onUpdate,
|
|
189
|
+
onFinalize
|
|
190
|
+
],
|
|
191
|
+
options
|
|
192
|
+
);
|
|
193
|
+
return useMemo(
|
|
194
|
+
() => buildIntentResult(built, { x, y, isActive }),
|
|
195
|
+
[built, x, y, isActive]
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { useSwipe };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useStableList, isDevBuild, warnOnce } from './chunk-ZX7WNICB.js';
|
|
2
|
-
import { useRef, useMemo } from 'react';
|
|
2
|
+
import { useRef, useMemo, useEffect } from 'react';
|
|
3
|
+
import { isWorkletFunction } from 'react-native-worklets';
|
|
3
4
|
|
|
4
5
|
// src/relations/index.ts
|
|
5
6
|
var RELATIONS = [
|
|
@@ -16,6 +17,37 @@ function applyRelations(gesture, relations, hookName) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
}
|
|
20
|
+
function hasHandlerTag(candidate) {
|
|
21
|
+
const tag = candidate.handlerTag;
|
|
22
|
+
return typeof tag === "number" && tag > 0;
|
|
23
|
+
}
|
|
24
|
+
function isUnresolvable(reference) {
|
|
25
|
+
if (typeof reference !== "object" || reference === null) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (!("current" in reference)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const current = reference.current;
|
|
32
|
+
if (current === null || current === void 0) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return !hasHandlerTag(current);
|
|
36
|
+
}
|
|
37
|
+
function warnOnUnresolvableReferences(relations, hookName) {
|
|
38
|
+
if (!isDevBuild()) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (const [option] of RELATIONS) {
|
|
42
|
+
if (!relations[option].some(isUnresolvable)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
warnOnce(
|
|
46
|
+
`relations:untagged:${hookName}:${option}`,
|
|
47
|
+
`${hookName} received a \`${option}\` reference to a component that owns no gesture, so gesture-handler dropped the relation. The gesture still works and the two still conflict \u2014 nothing reports it at runtime. React Native's own \`ScrollView\` and \`FlatList\` are the usual cause: they carry no handler tag. Import \`ScrollView\` or \`FlatList\` from \`@rootnative/impulse/gesture-handler\` and put the ref on that component instead.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
19
51
|
function warnOnConflictingRelations(relations, hookName) {
|
|
20
52
|
if (!isDevBuild()) {
|
|
21
53
|
return;
|
|
@@ -41,6 +73,22 @@ function warnOnConflictingRelations(relations, hookName) {
|
|
|
41
73
|
}
|
|
42
74
|
}
|
|
43
75
|
}
|
|
76
|
+
var PHASE_CALLBACKS = ["onBegin", "onUpdate", "onFinalize"];
|
|
77
|
+
function warnOnPlainPhaseCallbacks(callbacks, hookName) {
|
|
78
|
+
if (!isDevBuild() || typeof isWorkletFunction !== "function") {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const name of PHASE_CALLBACKS) {
|
|
82
|
+
const callback = callbacks[name];
|
|
83
|
+
if (typeof callback !== "function" || isWorkletFunction(callback)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
warnOnce(
|
|
87
|
+
`worklets:plain:${hookName}:${name}`,
|
|
88
|
+
`${hookName} received an \`${name}\` that is not a worklet, and \`${name}\` runs on the UI thread. Add the 'worklet' directive as the first statement of the function. Without it, iOS and Android throw "Tried to synchronously call a Remote Function" when the gesture reaches that phase. For code that must run on the JS thread, such as a React state update, use the hook's intent callback instead.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
44
92
|
|
|
45
93
|
// src/internal/useGestureMemo.ts
|
|
46
94
|
function useGestureMemo(hookName, build, deps, options) {
|
|
@@ -48,6 +96,9 @@ function useGestureMemo(hookName, build, deps, options) {
|
|
|
48
96
|
const blocks = useStableList(options?.blocks);
|
|
49
97
|
const deferTo = useStableList(options?.deferTo);
|
|
50
98
|
const testId = options?.testId;
|
|
99
|
+
const onBegin = options?.onBegin;
|
|
100
|
+
const onUpdate = options?.onUpdate;
|
|
101
|
+
const onFinalize = options?.onFinalize;
|
|
51
102
|
const ref = useRef(void 0);
|
|
52
103
|
const gesture = useMemo(
|
|
53
104
|
() => {
|
|
@@ -71,6 +122,12 @@ function useGestureMemo(hookName, build, deps, options) {
|
|
|
71
122
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
123
|
[...deps, alongside, blocks, deferTo, testId, hookName]
|
|
73
124
|
);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
warnOnUnresolvableReferences({ alongside, blocks, deferTo }, hookName);
|
|
127
|
+
}, [alongside, blocks, deferTo, hookName]);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
warnOnPlainPhaseCallbacks({ onBegin, onUpdate, onFinalize }, hookName);
|
|
130
|
+
}, [onBegin, onUpdate, onFinalize, hookName]);
|
|
74
131
|
return useMemo(() => ({ gesture, ref }), [gesture]);
|
|
75
132
|
}
|
|
76
133
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useStableRecord, useLatestCallback, buildIntentResult } from './chunk-2UZTAWUQ.js';
|
|
2
|
+
import { useGestureMemo } from './chunk-NYDDZD4G.js';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { Gesture } from 'react-native-gesture-handler';
|
|
5
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
6
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
7
|
+
|
|
8
|
+
var DEFAULT_THRESHOLD = 10;
|
|
9
|
+
function usePan(options = {}) {
|
|
10
|
+
const {
|
|
11
|
+
axis = "both",
|
|
12
|
+
threshold = DEFAULT_THRESHOLD,
|
|
13
|
+
failOffset,
|
|
14
|
+
pointers,
|
|
15
|
+
enabled,
|
|
16
|
+
onPanStart,
|
|
17
|
+
onPanEnd,
|
|
18
|
+
onBegin,
|
|
19
|
+
onUpdate,
|
|
20
|
+
onFinalize
|
|
21
|
+
} = options;
|
|
22
|
+
const x = useSharedValue(0);
|
|
23
|
+
const y = useSharedValue(0);
|
|
24
|
+
const isActive = useSharedValue(false);
|
|
25
|
+
const originX = useSharedValue(0);
|
|
26
|
+
const originY = useSharedValue(0);
|
|
27
|
+
const lastX = useSharedValue(0);
|
|
28
|
+
const lastY = useSharedValue(0);
|
|
29
|
+
const hitSlop = useStableRecord(options.hitSlop);
|
|
30
|
+
const movesX = axis !== "y";
|
|
31
|
+
const movesY = axis !== "x";
|
|
32
|
+
const handlePanStart = useLatestCallback(onPanStart);
|
|
33
|
+
const handlePanEnd = useLatestCallback(onPanEnd);
|
|
34
|
+
const hasPanStart = onPanStart !== void 0;
|
|
35
|
+
const hasPanEnd = onPanEnd !== void 0;
|
|
36
|
+
const built = useGestureMemo(
|
|
37
|
+
"usePan",
|
|
38
|
+
() => {
|
|
39
|
+
const toPanEvent = (event, changeX, changeY) => {
|
|
40
|
+
"worklet";
|
|
41
|
+
return {
|
|
42
|
+
translation: { x: x.value, y: y.value },
|
|
43
|
+
change: { x: changeX, y: changeY },
|
|
44
|
+
velocity: { x: event.velocityX, y: event.velocityY },
|
|
45
|
+
absolute: { x: event.absoluteX, y: event.absoluteY },
|
|
46
|
+
pointers: event.numberOfPointers
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
const pan = Gesture.Pan().onBegin((event) => {
|
|
50
|
+
"worklet";
|
|
51
|
+
onBegin?.(toPanEvent(event, 0, 0));
|
|
52
|
+
}).onStart((event) => {
|
|
53
|
+
"worklet";
|
|
54
|
+
originX.value = event.translationX;
|
|
55
|
+
originY.value = event.translationY;
|
|
56
|
+
lastX.value = 0;
|
|
57
|
+
lastY.value = 0;
|
|
58
|
+
x.value = 0;
|
|
59
|
+
y.value = 0;
|
|
60
|
+
isActive.value = true;
|
|
61
|
+
if (hasPanStart) {
|
|
62
|
+
scheduleOnRN(handlePanStart, toPanEvent(event, 0, 0));
|
|
63
|
+
}
|
|
64
|
+
}).onUpdate((event) => {
|
|
65
|
+
"worklet";
|
|
66
|
+
const nextX = movesX ? event.translationX - originX.value : 0;
|
|
67
|
+
const nextY = movesY ? event.translationY - originY.value : 0;
|
|
68
|
+
const changeX = nextX - lastX.value;
|
|
69
|
+
const changeY = nextY - lastY.value;
|
|
70
|
+
lastX.value = nextX;
|
|
71
|
+
lastY.value = nextY;
|
|
72
|
+
x.value = nextX;
|
|
73
|
+
y.value = nextY;
|
|
74
|
+
onUpdate?.(toPanEvent(event, changeX, changeY));
|
|
75
|
+
}).onEnd((event, success) => {
|
|
76
|
+
"worklet";
|
|
77
|
+
if (hasPanEnd) {
|
|
78
|
+
scheduleOnRN(handlePanEnd, toPanEvent(event, 0, 0), {
|
|
79
|
+
cancelled: !success
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}).onFinalize((event, success) => {
|
|
83
|
+
"worklet";
|
|
84
|
+
isActive.value = false;
|
|
85
|
+
onFinalize?.(toPanEvent(event, 0, 0), success);
|
|
86
|
+
});
|
|
87
|
+
if (axis === "x") {
|
|
88
|
+
pan.activeOffsetX([-threshold, threshold]);
|
|
89
|
+
} else if (axis === "y") {
|
|
90
|
+
pan.activeOffsetY([-threshold, threshold]);
|
|
91
|
+
} else {
|
|
92
|
+
pan.minDistance(threshold);
|
|
93
|
+
}
|
|
94
|
+
if (failOffset !== void 0) {
|
|
95
|
+
if (axis === "x") {
|
|
96
|
+
pan.failOffsetY([-failOffset, failOffset]);
|
|
97
|
+
} else if (axis === "y") {
|
|
98
|
+
pan.failOffsetX([-failOffset, failOffset]);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (pointers !== void 0) {
|
|
102
|
+
pan.minPointers(pointers).maxPointers(pointers);
|
|
103
|
+
}
|
|
104
|
+
if (hitSlop !== void 0) {
|
|
105
|
+
pan.hitSlop(hitSlop);
|
|
106
|
+
}
|
|
107
|
+
if (enabled !== void 0) {
|
|
108
|
+
pan.enabled(enabled);
|
|
109
|
+
}
|
|
110
|
+
return pan;
|
|
111
|
+
},
|
|
112
|
+
[
|
|
113
|
+
axis,
|
|
114
|
+
threshold,
|
|
115
|
+
failOffset,
|
|
116
|
+
pointers,
|
|
117
|
+
hitSlop,
|
|
118
|
+
enabled,
|
|
119
|
+
movesX,
|
|
120
|
+
movesY,
|
|
121
|
+
hasPanStart,
|
|
122
|
+
hasPanEnd,
|
|
123
|
+
handlePanStart,
|
|
124
|
+
handlePanEnd,
|
|
125
|
+
x,
|
|
126
|
+
y,
|
|
127
|
+
originX,
|
|
128
|
+
originY,
|
|
129
|
+
lastX,
|
|
130
|
+
lastY,
|
|
131
|
+
isActive,
|
|
132
|
+
onBegin,
|
|
133
|
+
onUpdate,
|
|
134
|
+
onFinalize
|
|
135
|
+
],
|
|
136
|
+
options
|
|
137
|
+
);
|
|
138
|
+
return useMemo(
|
|
139
|
+
() => buildIntentResult(built, { x, y, isActive }),
|
|
140
|
+
[built, x, y, isActive]
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export { usePan };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useStableRecord, useLatestCallback } from './chunk-
|
|
2
|
-
import { useGestureMemo } from './chunk-
|
|
1
|
+
import { useStableRecord, useLatestCallback, buildIntentResult } from './chunk-2UZTAWUQ.js';
|
|
2
|
+
import { useGestureMemo } from './chunk-NYDDZD4G.js';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
import { Gesture } from 'react-native-gesture-handler';
|
|
5
|
-
import { useSharedValue
|
|
5
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
6
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
6
7
|
|
|
7
8
|
var DEFAULT_THRESHOLD = 10;
|
|
8
9
|
function resist(value, min, max, elastic) {
|
|
@@ -83,7 +84,7 @@ function useDrag(options = {}) {
|
|
|
83
84
|
startY.value = y.value - event.translationY;
|
|
84
85
|
isActive.value = true;
|
|
85
86
|
if (hasDragStart) {
|
|
86
|
-
|
|
87
|
+
scheduleOnRN(handleDragStart, toDragEvent(event));
|
|
87
88
|
}
|
|
88
89
|
}).onUpdate((event) => {
|
|
89
90
|
"worklet";
|
|
@@ -106,8 +107,10 @@ function useDrag(options = {}) {
|
|
|
106
107
|
onUpdate?.(toDragEvent(event));
|
|
107
108
|
}).onEnd((event, success) => {
|
|
108
109
|
"worklet";
|
|
109
|
-
if (
|
|
110
|
-
|
|
110
|
+
if (hasDragEnd) {
|
|
111
|
+
scheduleOnRN(handleDragEnd, toDragEvent(event), {
|
|
112
|
+
cancelled: !success
|
|
113
|
+
});
|
|
111
114
|
}
|
|
112
115
|
}).onFinalize((event, success) => {
|
|
113
116
|
"worklet";
|
|
@@ -168,7 +171,10 @@ function useDrag(options = {}) {
|
|
|
168
171
|
],
|
|
169
172
|
options
|
|
170
173
|
);
|
|
171
|
-
return useMemo(
|
|
174
|
+
return useMemo(
|
|
175
|
+
() => buildIntentResult(built, { x, y, isActive }),
|
|
176
|
+
[built, x, y, isActive]
|
|
177
|
+
);
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
export { useDrag };
|