@rootnative/inertia-gestures 0.0.19 → 0.0.20
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 +9 -1
- package/README.md +1 -1
- package/dist/index.js +220 -203
- package/dist/index.mjs +222 -205
- package/package.json +16 -16
- package/src/useDrag.ts +36 -29
- package/src/usePan.ts +32 -25
- package/src/useSwipe.ts +36 -29
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@ This package ships in lockstep with `@rootnative/inertia` — version numbers tr
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.0.20] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **The supported band is Expo SDK 58.** The peer ranges are `react >=19.3.0 <20.0.0`, `react-native >=0.88.0 <0.89.0`, `react-native-reanimated >=4.7.0 <4.8.0` and `react-native-gesture-handler >=3.3.0 <4.0.0`. SDK 57 stays on `0.0.19`. See the `@rootnative/inertia` entry for the reason.
|
|
14
|
+
- **`useDrag`, `useSwipe` and `usePan` build their gesture with the Gesture Handler 3 hook API.** Each hook calls `usePanGesture` on a memoized config instead of the `Gesture.Pan()` builder, which Gesture Handler 3 marks as deprecated. The returned `gesture` is the `PanGesture` of that hook; pass it to `<GestureDetector>` as before. The lifecycle callbacks moved to the new names (`onActivate`, `onUpdate`, `onDeactivate`, `onFinalize`) with no change in when they fire. **Breaking for one case:** the legacy composition helpers (`Gesture.Simultaneous`, `Gesture.Race`, `Gesture.Exclusive`) do not accept a hook gesture. Compose with the Gesture Handler 3 composition hooks instead.
|
|
15
|
+
|
|
9
16
|
## [0.0.19] - 2026-10-17
|
|
10
17
|
|
|
11
18
|
**Lockstep version bump** alongside `@rootnative/inertia@0.0.19` (`focusVisible` follows the browser `:focus-visible` on web, and a control that mounts disabled starts at its `useGestureLayer` `disabled` layer). No runtime changes in this adapter; the `@rootnative/inertia` peer range moves to `>=0.0.19 <0.1.0`.
|
|
@@ -133,7 +140,8 @@ Initial alpha publish alongside `@rootnative/inertia@0.0.0-alpha.0`. Optional ad
|
|
|
133
140
|
- `useDrag({ onRelease })` — release worklet returns per-axis Inertia transitions (snap-to-tick spring, decay with bounds, etc.). Velocity stays on the UI thread; no JS round-trip.
|
|
134
141
|
- `useSwipe`, `usePan` hooks composable with any `Motion.*` primitive via `<GestureDetector>`.
|
|
135
142
|
|
|
136
|
-
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.
|
|
143
|
+
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.20...HEAD
|
|
144
|
+
[0.0.20]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.20
|
|
137
145
|
[0.0.19]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.19
|
|
138
146
|
[0.0.18]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.18
|
|
139
147
|
[0.0.17]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.17
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ pnpm add @rootnative/inertia-gestures react-native-gesture-handler
|
|
|
18
18
|
|
|
19
19
|
Then follow the [`react-native-gesture-handler` install guide](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) — it needs `<GestureHandlerRootView>` near the root of your app.
|
|
20
20
|
|
|
21
|
-
**Peer dependencies:** `@rootnative/inertia` (workspace or installed), `react >=19.
|
|
21
|
+
**Peer dependencies:** `@rootnative/inertia` (workspace or installed), `react >=19.3.0`, `react-native >=0.88.0 <0.89.0`, `react-native-reanimated >=4.7.0 <4.8.0`, `react-native-gesture-handler >=3.3.0 <4.0.0`.
|
|
22
22
|
|
|
23
23
|
## What ships
|
|
24
24
|
|
package/dist/index.js
CHANGED
|
@@ -40,81 +40,86 @@ function useDrag(options = {}) {
|
|
|
40
40
|
const hasDragEnd = onDragEnd !== void 0;
|
|
41
41
|
const fireDragStart = useLatestCallback(onDragStart);
|
|
42
42
|
const fireDragEnd = useLatestCallback(onDragEnd);
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
toX
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
toY
|
|
90
|
-
|
|
43
|
+
const config = react.useMemo(
|
|
44
|
+
() => ({
|
|
45
|
+
onActivate: () => {
|
|
46
|
+
"worklet";
|
|
47
|
+
startX.value = dragX.value;
|
|
48
|
+
startY.value = dragY.value;
|
|
49
|
+
isDragging.value = true;
|
|
50
|
+
if (hasDragStart) reactNativeReanimated.runOnJS(fireDragStart)();
|
|
51
|
+
},
|
|
52
|
+
onUpdate: (e) => {
|
|
53
|
+
"worklet";
|
|
54
|
+
if (lockX) {
|
|
55
|
+
dragX.value = inertia.applyBounds(
|
|
56
|
+
startX.value + e.translationX,
|
|
57
|
+
left,
|
|
58
|
+
right,
|
|
59
|
+
elasticCoef
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (lockY) {
|
|
63
|
+
dragY.value = inertia.applyBounds(
|
|
64
|
+
startY.value + e.translationY,
|
|
65
|
+
top,
|
|
66
|
+
bottom,
|
|
67
|
+
elasticCoef
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
onDeactivate: (e) => {
|
|
72
|
+
"worklet";
|
|
73
|
+
isDragging.value = false;
|
|
74
|
+
const x = dragX.value;
|
|
75
|
+
const y = dragY.value;
|
|
76
|
+
const vx = e.velocityX;
|
|
77
|
+
const vy = e.velocityY;
|
|
78
|
+
if (onRelease) {
|
|
79
|
+
const result = onRelease({ x, y, velocity: { x: vx, y: vy } });
|
|
80
|
+
if (result) {
|
|
81
|
+
if (result.x && lockX) {
|
|
82
|
+
const toX = "to" in result.x ? result.x.to : x;
|
|
83
|
+
dragX.value = inertia.buildReleaseAnimation(
|
|
84
|
+
result.x,
|
|
85
|
+
toX
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (result.y && lockY) {
|
|
89
|
+
const toY = "to" in result.y ? result.y.to : y;
|
|
90
|
+
dragY.value = inertia.buildReleaseAnimation(
|
|
91
|
+
result.y,
|
|
92
|
+
toY
|
|
93
|
+
);
|
|
94
|
+
}
|
|
91
95
|
}
|
|
92
96
|
}
|
|
97
|
+
if (hasDragEnd) {
|
|
98
|
+
reactNativeReanimated.runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } });
|
|
99
|
+
}
|
|
93
100
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
isDragging
|
|
117
|
-
]);
|
|
101
|
+
}),
|
|
102
|
+
[
|
|
103
|
+
lockX,
|
|
104
|
+
lockY,
|
|
105
|
+
left,
|
|
106
|
+
right,
|
|
107
|
+
top,
|
|
108
|
+
bottom,
|
|
109
|
+
elasticCoef,
|
|
110
|
+
hasDragStart,
|
|
111
|
+
hasDragEnd,
|
|
112
|
+
fireDragStart,
|
|
113
|
+
fireDragEnd,
|
|
114
|
+
onRelease,
|
|
115
|
+
dragX,
|
|
116
|
+
dragY,
|
|
117
|
+
startX,
|
|
118
|
+
startY,
|
|
119
|
+
isDragging
|
|
120
|
+
]
|
|
121
|
+
);
|
|
122
|
+
const gesture = reactNativeGestureHandler.usePanGesture(config);
|
|
118
123
|
const animatedStyle = inertia.useTranslateStyle(dragX, dragY);
|
|
119
124
|
return { gesture, animatedStyle, dragX, dragY, isDragging };
|
|
120
125
|
}
|
|
@@ -157,103 +162,109 @@ function useSwipe(options = {}) {
|
|
|
157
162
|
const hasSwipeEnd = onSwipeEnd !== void 0;
|
|
158
163
|
const fireSwipe = useLatestCallback(onSwipe);
|
|
159
164
|
const fireSwipeEnd = useLatestCallback(onSwipeEnd);
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const distance = isHoriz ? Math.abs(e.translationX) : Math.abs(e.translationY);
|
|
186
|
-
const velocity = isHoriz ? Math.abs(e.velocityX) : Math.abs(e.velocityY);
|
|
187
|
-
reactNativeReanimated.runOnJS(fireSwipe)(direction, { distance, velocity });
|
|
188
|
-
}
|
|
189
|
-
let exit = void 0;
|
|
190
|
-
if (direction !== null && onCommit) {
|
|
191
|
-
exit = onCommit(direction, {
|
|
192
|
-
x: swipeX.value,
|
|
193
|
-
y: swipeY.value,
|
|
194
|
-
velocity: { x: e.velocityX, y: e.velocityY }
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
let settle;
|
|
198
|
-
if (direction !== null && hasSwipeEnd) {
|
|
199
|
-
const dir = direction;
|
|
200
|
-
settle = (finished) => {
|
|
201
|
-
reactNativeReanimated.runOnJS(fireSwipeEnd)(dir, { finished: finished === true });
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
const isHorizontalCommit = direction === "left" || direction === "right";
|
|
205
|
-
const settleX = isHorizontalCommit ? settle : void 0;
|
|
206
|
-
const settleY = isHorizontalCommit ? void 0 : settle;
|
|
207
|
-
const exitX = exit ? exit.x : void 0;
|
|
208
|
-
const exitY = exit ? exit.y : void 0;
|
|
209
|
-
if (exitX) {
|
|
210
|
-
swipeX.value = inertia.buildReleaseAnimation(
|
|
211
|
-
exitX,
|
|
212
|
-
"to" in exitX ? exitX.to : swipeX.value,
|
|
213
|
-
settleX
|
|
214
|
-
);
|
|
215
|
-
} else {
|
|
216
|
-
swipeX.value = inertia.buildReleaseAnimation(
|
|
217
|
-
withReleaseVelocity(snapBack, e.velocityX),
|
|
218
|
-
0,
|
|
219
|
-
settleX
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
if (exitY) {
|
|
223
|
-
swipeY.value = inertia.buildReleaseAnimation(
|
|
224
|
-
exitY,
|
|
225
|
-
"to" in exitY ? exitY.to : swipeY.value,
|
|
226
|
-
settleY
|
|
227
|
-
);
|
|
228
|
-
} else {
|
|
229
|
-
swipeY.value = inertia.buildReleaseAnimation(
|
|
230
|
-
withReleaseVelocity(snapBack, e.velocityY),
|
|
231
|
-
0,
|
|
232
|
-
settleY
|
|
165
|
+
const config = react.useMemo(
|
|
166
|
+
() => ({
|
|
167
|
+
onActivate: () => {
|
|
168
|
+
"worklet";
|
|
169
|
+
isActive.value = true;
|
|
170
|
+
},
|
|
171
|
+
onUpdate: (e) => {
|
|
172
|
+
"worklet";
|
|
173
|
+
swipeX.value = e.translationX;
|
|
174
|
+
swipeY.value = e.translationY;
|
|
175
|
+
},
|
|
176
|
+
onDeactivate: (e) => {
|
|
177
|
+
"worklet";
|
|
178
|
+
isActive.value = false;
|
|
179
|
+
const direction = pickDirection(
|
|
180
|
+
e.translationX,
|
|
181
|
+
e.translationY,
|
|
182
|
+
e.velocityX,
|
|
183
|
+
e.velocityY,
|
|
184
|
+
distanceThreshold,
|
|
185
|
+
velocityThreshold,
|
|
186
|
+
allowLeft,
|
|
187
|
+
allowRight,
|
|
188
|
+
allowUp,
|
|
189
|
+
allowDown
|
|
233
190
|
);
|
|
191
|
+
if (direction !== null && hasSwipe) {
|
|
192
|
+
const isHoriz = direction === "left" || direction === "right";
|
|
193
|
+
const distance = isHoriz ? Math.abs(e.translationX) : Math.abs(e.translationY);
|
|
194
|
+
const velocity = isHoriz ? Math.abs(e.velocityX) : Math.abs(e.velocityY);
|
|
195
|
+
reactNativeReanimated.runOnJS(fireSwipe)(direction, { distance, velocity });
|
|
196
|
+
}
|
|
197
|
+
let exit = void 0;
|
|
198
|
+
if (direction !== null && onCommit) {
|
|
199
|
+
exit = onCommit(direction, {
|
|
200
|
+
x: swipeX.value,
|
|
201
|
+
y: swipeY.value,
|
|
202
|
+
velocity: { x: e.velocityX, y: e.velocityY }
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
let settle;
|
|
206
|
+
if (direction !== null && hasSwipeEnd) {
|
|
207
|
+
const dir = direction;
|
|
208
|
+
settle = (finished) => {
|
|
209
|
+
reactNativeReanimated.runOnJS(fireSwipeEnd)(dir, { finished: finished === true });
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const isHorizontalCommit = direction === "left" || direction === "right";
|
|
213
|
+
const settleX = isHorizontalCommit ? settle : void 0;
|
|
214
|
+
const settleY = isHorizontalCommit ? void 0 : settle;
|
|
215
|
+
const exitX = exit ? exit.x : void 0;
|
|
216
|
+
const exitY = exit ? exit.y : void 0;
|
|
217
|
+
if (exitX) {
|
|
218
|
+
swipeX.value = inertia.buildReleaseAnimation(
|
|
219
|
+
exitX,
|
|
220
|
+
"to" in exitX ? exitX.to : swipeX.value,
|
|
221
|
+
settleX
|
|
222
|
+
);
|
|
223
|
+
} else {
|
|
224
|
+
swipeX.value = inertia.buildReleaseAnimation(
|
|
225
|
+
withReleaseVelocity(snapBack, e.velocityX),
|
|
226
|
+
0,
|
|
227
|
+
settleX
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
if (exitY) {
|
|
231
|
+
swipeY.value = inertia.buildReleaseAnimation(
|
|
232
|
+
exitY,
|
|
233
|
+
"to" in exitY ? exitY.to : swipeY.value,
|
|
234
|
+
settleY
|
|
235
|
+
);
|
|
236
|
+
} else {
|
|
237
|
+
swipeY.value = inertia.buildReleaseAnimation(
|
|
238
|
+
withReleaseVelocity(snapBack, e.velocityY),
|
|
239
|
+
0,
|
|
240
|
+
settleY
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
onFinalize: () => {
|
|
245
|
+
"worklet";
|
|
246
|
+
isActive.value = false;
|
|
234
247
|
}
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
isActive
|
|
256
|
-
]);
|
|
248
|
+
}),
|
|
249
|
+
[
|
|
250
|
+
distanceThreshold,
|
|
251
|
+
velocityThreshold,
|
|
252
|
+
allowLeft,
|
|
253
|
+
allowRight,
|
|
254
|
+
allowUp,
|
|
255
|
+
allowDown,
|
|
256
|
+
snapBack,
|
|
257
|
+
hasSwipe,
|
|
258
|
+
hasSwipeEnd,
|
|
259
|
+
fireSwipe,
|
|
260
|
+
fireSwipeEnd,
|
|
261
|
+
onCommit,
|
|
262
|
+
swipeX,
|
|
263
|
+
swipeY,
|
|
264
|
+
isActive
|
|
265
|
+
]
|
|
266
|
+
);
|
|
267
|
+
const gesture = reactNativeGestureHandler.usePanGesture(config);
|
|
257
268
|
const animatedStyle = inertia.useTranslateStyle(swipeX, swipeY);
|
|
258
269
|
const reset = react.useCallback(() => {
|
|
259
270
|
swipeX.value = 0;
|
|
@@ -296,42 +307,48 @@ function usePan(options = {}) {
|
|
|
296
307
|
const top = constraints?.top;
|
|
297
308
|
const bottom = constraints?.bottom;
|
|
298
309
|
const decel = deceleration;
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
310
|
+
const config = react.useMemo(
|
|
311
|
+
() => ({
|
|
312
|
+
onActivate: () => {
|
|
313
|
+
"worklet";
|
|
314
|
+
startX.value = panX.value;
|
|
315
|
+
startY.value = panY.value;
|
|
316
|
+
isPanning.value = true;
|
|
317
|
+
},
|
|
318
|
+
onUpdate: (e) => {
|
|
319
|
+
"worklet";
|
|
320
|
+
panX.value = clamp(startX.value + e.translationX, left, right);
|
|
321
|
+
panY.value = clamp(startY.value + e.translationY, top, bottom);
|
|
322
|
+
},
|
|
323
|
+
onDeactivate: (e) => {
|
|
324
|
+
"worklet";
|
|
325
|
+
isPanning.value = false;
|
|
326
|
+
if (disableMomentum) return;
|
|
327
|
+
const clampX = boundsTuple(left, right);
|
|
328
|
+
const clampY = boundsTuple(top, bottom);
|
|
329
|
+
panX.value = reactNativeReanimated.withDecay(decayConfig(e.velocityX, decel, clampX));
|
|
330
|
+
panY.value = reactNativeReanimated.withDecay(decayConfig(e.velocityY, decel, clampY));
|
|
331
|
+
},
|
|
332
|
+
onFinalize: () => {
|
|
333
|
+
"worklet";
|
|
334
|
+
isPanning.value = false;
|
|
335
|
+
}
|
|
336
|
+
}),
|
|
337
|
+
[
|
|
338
|
+
left,
|
|
339
|
+
right,
|
|
340
|
+
top,
|
|
341
|
+
bottom,
|
|
342
|
+
decel,
|
|
343
|
+
disableMomentum,
|
|
344
|
+
panX,
|
|
345
|
+
panY,
|
|
346
|
+
startX,
|
|
347
|
+
startY,
|
|
348
|
+
isPanning
|
|
349
|
+
]
|
|
350
|
+
);
|
|
351
|
+
const gesture = reactNativeGestureHandler.usePanGesture(config);
|
|
335
352
|
const animatedStyle = inertia.useTranslateStyle(panX, panY);
|
|
336
353
|
return { gesture, animatedStyle, panX, panY, isPanning };
|
|
337
354
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo, useCallback, useRef } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { usePanGesture } from 'react-native-gesture-handler';
|
|
3
3
|
import { useSharedValue, runOnJS, withDecay } from 'react-native-reanimated';
|
|
4
|
-
import {
|
|
4
|
+
import { buildReleaseAnimation, applyBounds, useTranslateStyle, useNamedTransitions, resolveNamedTransition } from '@rootnative/inertia';
|
|
5
5
|
|
|
6
6
|
// src/useDrag.ts
|
|
7
7
|
function useLatestCallback(fn) {
|
|
@@ -38,81 +38,86 @@ function useDrag(options = {}) {
|
|
|
38
38
|
const hasDragEnd = onDragEnd !== void 0;
|
|
39
39
|
const fireDragStart = useLatestCallback(onDragStart);
|
|
40
40
|
const fireDragEnd = useLatestCallback(onDragEnd);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
toX
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
toY
|
|
88
|
-
|
|
41
|
+
const config = useMemo(
|
|
42
|
+
() => ({
|
|
43
|
+
onActivate: () => {
|
|
44
|
+
"worklet";
|
|
45
|
+
startX.value = dragX.value;
|
|
46
|
+
startY.value = dragY.value;
|
|
47
|
+
isDragging.value = true;
|
|
48
|
+
if (hasDragStart) runOnJS(fireDragStart)();
|
|
49
|
+
},
|
|
50
|
+
onUpdate: (e) => {
|
|
51
|
+
"worklet";
|
|
52
|
+
if (lockX) {
|
|
53
|
+
dragX.value = applyBounds(
|
|
54
|
+
startX.value + e.translationX,
|
|
55
|
+
left,
|
|
56
|
+
right,
|
|
57
|
+
elasticCoef
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
if (lockY) {
|
|
61
|
+
dragY.value = applyBounds(
|
|
62
|
+
startY.value + e.translationY,
|
|
63
|
+
top,
|
|
64
|
+
bottom,
|
|
65
|
+
elasticCoef
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
onDeactivate: (e) => {
|
|
70
|
+
"worklet";
|
|
71
|
+
isDragging.value = false;
|
|
72
|
+
const x = dragX.value;
|
|
73
|
+
const y = dragY.value;
|
|
74
|
+
const vx = e.velocityX;
|
|
75
|
+
const vy = e.velocityY;
|
|
76
|
+
if (onRelease) {
|
|
77
|
+
const result = onRelease({ x, y, velocity: { x: vx, y: vy } });
|
|
78
|
+
if (result) {
|
|
79
|
+
if (result.x && lockX) {
|
|
80
|
+
const toX = "to" in result.x ? result.x.to : x;
|
|
81
|
+
dragX.value = buildReleaseAnimation(
|
|
82
|
+
result.x,
|
|
83
|
+
toX
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (result.y && lockY) {
|
|
87
|
+
const toY = "to" in result.y ? result.y.to : y;
|
|
88
|
+
dragY.value = buildReleaseAnimation(
|
|
89
|
+
result.y,
|
|
90
|
+
toY
|
|
91
|
+
);
|
|
92
|
+
}
|
|
89
93
|
}
|
|
90
94
|
}
|
|
95
|
+
if (hasDragEnd) {
|
|
96
|
+
runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } });
|
|
97
|
+
}
|
|
91
98
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
isDragging
|
|
115
|
-
]);
|
|
99
|
+
}),
|
|
100
|
+
[
|
|
101
|
+
lockX,
|
|
102
|
+
lockY,
|
|
103
|
+
left,
|
|
104
|
+
right,
|
|
105
|
+
top,
|
|
106
|
+
bottom,
|
|
107
|
+
elasticCoef,
|
|
108
|
+
hasDragStart,
|
|
109
|
+
hasDragEnd,
|
|
110
|
+
fireDragStart,
|
|
111
|
+
fireDragEnd,
|
|
112
|
+
onRelease,
|
|
113
|
+
dragX,
|
|
114
|
+
dragY,
|
|
115
|
+
startX,
|
|
116
|
+
startY,
|
|
117
|
+
isDragging
|
|
118
|
+
]
|
|
119
|
+
);
|
|
120
|
+
const gesture = usePanGesture(config);
|
|
116
121
|
const animatedStyle = useTranslateStyle(dragX, dragY);
|
|
117
122
|
return { gesture, animatedStyle, dragX, dragY, isDragging };
|
|
118
123
|
}
|
|
@@ -155,103 +160,109 @@ function useSwipe(options = {}) {
|
|
|
155
160
|
const hasSwipeEnd = onSwipeEnd !== void 0;
|
|
156
161
|
const fireSwipe = useLatestCallback(onSwipe);
|
|
157
162
|
const fireSwipeEnd = useLatestCallback(onSwipeEnd);
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const distance = isHoriz ? Math.abs(e.translationX) : Math.abs(e.translationY);
|
|
184
|
-
const velocity = isHoriz ? Math.abs(e.velocityX) : Math.abs(e.velocityY);
|
|
185
|
-
runOnJS(fireSwipe)(direction, { distance, velocity });
|
|
186
|
-
}
|
|
187
|
-
let exit = void 0;
|
|
188
|
-
if (direction !== null && onCommit) {
|
|
189
|
-
exit = onCommit(direction, {
|
|
190
|
-
x: swipeX.value,
|
|
191
|
-
y: swipeY.value,
|
|
192
|
-
velocity: { x: e.velocityX, y: e.velocityY }
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
let settle;
|
|
196
|
-
if (direction !== null && hasSwipeEnd) {
|
|
197
|
-
const dir = direction;
|
|
198
|
-
settle = (finished) => {
|
|
199
|
-
runOnJS(fireSwipeEnd)(dir, { finished: finished === true });
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const isHorizontalCommit = direction === "left" || direction === "right";
|
|
203
|
-
const settleX = isHorizontalCommit ? settle : void 0;
|
|
204
|
-
const settleY = isHorizontalCommit ? void 0 : settle;
|
|
205
|
-
const exitX = exit ? exit.x : void 0;
|
|
206
|
-
const exitY = exit ? exit.y : void 0;
|
|
207
|
-
if (exitX) {
|
|
208
|
-
swipeX.value = buildReleaseAnimation(
|
|
209
|
-
exitX,
|
|
210
|
-
"to" in exitX ? exitX.to : swipeX.value,
|
|
211
|
-
settleX
|
|
212
|
-
);
|
|
213
|
-
} else {
|
|
214
|
-
swipeX.value = buildReleaseAnimation(
|
|
215
|
-
withReleaseVelocity(snapBack, e.velocityX),
|
|
216
|
-
0,
|
|
217
|
-
settleX
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
if (exitY) {
|
|
221
|
-
swipeY.value = buildReleaseAnimation(
|
|
222
|
-
exitY,
|
|
223
|
-
"to" in exitY ? exitY.to : swipeY.value,
|
|
224
|
-
settleY
|
|
225
|
-
);
|
|
226
|
-
} else {
|
|
227
|
-
swipeY.value = buildReleaseAnimation(
|
|
228
|
-
withReleaseVelocity(snapBack, e.velocityY),
|
|
229
|
-
0,
|
|
230
|
-
settleY
|
|
163
|
+
const config = useMemo(
|
|
164
|
+
() => ({
|
|
165
|
+
onActivate: () => {
|
|
166
|
+
"worklet";
|
|
167
|
+
isActive.value = true;
|
|
168
|
+
},
|
|
169
|
+
onUpdate: (e) => {
|
|
170
|
+
"worklet";
|
|
171
|
+
swipeX.value = e.translationX;
|
|
172
|
+
swipeY.value = e.translationY;
|
|
173
|
+
},
|
|
174
|
+
onDeactivate: (e) => {
|
|
175
|
+
"worklet";
|
|
176
|
+
isActive.value = false;
|
|
177
|
+
const direction = pickDirection(
|
|
178
|
+
e.translationX,
|
|
179
|
+
e.translationY,
|
|
180
|
+
e.velocityX,
|
|
181
|
+
e.velocityY,
|
|
182
|
+
distanceThreshold,
|
|
183
|
+
velocityThreshold,
|
|
184
|
+
allowLeft,
|
|
185
|
+
allowRight,
|
|
186
|
+
allowUp,
|
|
187
|
+
allowDown
|
|
231
188
|
);
|
|
189
|
+
if (direction !== null && hasSwipe) {
|
|
190
|
+
const isHoriz = direction === "left" || direction === "right";
|
|
191
|
+
const distance = isHoriz ? Math.abs(e.translationX) : Math.abs(e.translationY);
|
|
192
|
+
const velocity = isHoriz ? Math.abs(e.velocityX) : Math.abs(e.velocityY);
|
|
193
|
+
runOnJS(fireSwipe)(direction, { distance, velocity });
|
|
194
|
+
}
|
|
195
|
+
let exit = void 0;
|
|
196
|
+
if (direction !== null && onCommit) {
|
|
197
|
+
exit = onCommit(direction, {
|
|
198
|
+
x: swipeX.value,
|
|
199
|
+
y: swipeY.value,
|
|
200
|
+
velocity: { x: e.velocityX, y: e.velocityY }
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
let settle;
|
|
204
|
+
if (direction !== null && hasSwipeEnd) {
|
|
205
|
+
const dir = direction;
|
|
206
|
+
settle = (finished) => {
|
|
207
|
+
runOnJS(fireSwipeEnd)(dir, { finished: finished === true });
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const isHorizontalCommit = direction === "left" || direction === "right";
|
|
211
|
+
const settleX = isHorizontalCommit ? settle : void 0;
|
|
212
|
+
const settleY = isHorizontalCommit ? void 0 : settle;
|
|
213
|
+
const exitX = exit ? exit.x : void 0;
|
|
214
|
+
const exitY = exit ? exit.y : void 0;
|
|
215
|
+
if (exitX) {
|
|
216
|
+
swipeX.value = buildReleaseAnimation(
|
|
217
|
+
exitX,
|
|
218
|
+
"to" in exitX ? exitX.to : swipeX.value,
|
|
219
|
+
settleX
|
|
220
|
+
);
|
|
221
|
+
} else {
|
|
222
|
+
swipeX.value = buildReleaseAnimation(
|
|
223
|
+
withReleaseVelocity(snapBack, e.velocityX),
|
|
224
|
+
0,
|
|
225
|
+
settleX
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
if (exitY) {
|
|
229
|
+
swipeY.value = buildReleaseAnimation(
|
|
230
|
+
exitY,
|
|
231
|
+
"to" in exitY ? exitY.to : swipeY.value,
|
|
232
|
+
settleY
|
|
233
|
+
);
|
|
234
|
+
} else {
|
|
235
|
+
swipeY.value = buildReleaseAnimation(
|
|
236
|
+
withReleaseVelocity(snapBack, e.velocityY),
|
|
237
|
+
0,
|
|
238
|
+
settleY
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
onFinalize: () => {
|
|
243
|
+
"worklet";
|
|
244
|
+
isActive.value = false;
|
|
232
245
|
}
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
isActive
|
|
254
|
-
]);
|
|
246
|
+
}),
|
|
247
|
+
[
|
|
248
|
+
distanceThreshold,
|
|
249
|
+
velocityThreshold,
|
|
250
|
+
allowLeft,
|
|
251
|
+
allowRight,
|
|
252
|
+
allowUp,
|
|
253
|
+
allowDown,
|
|
254
|
+
snapBack,
|
|
255
|
+
hasSwipe,
|
|
256
|
+
hasSwipeEnd,
|
|
257
|
+
fireSwipe,
|
|
258
|
+
fireSwipeEnd,
|
|
259
|
+
onCommit,
|
|
260
|
+
swipeX,
|
|
261
|
+
swipeY,
|
|
262
|
+
isActive
|
|
263
|
+
]
|
|
264
|
+
);
|
|
265
|
+
const gesture = usePanGesture(config);
|
|
255
266
|
const animatedStyle = useTranslateStyle(swipeX, swipeY);
|
|
256
267
|
const reset = useCallback(() => {
|
|
257
268
|
swipeX.value = 0;
|
|
@@ -294,42 +305,48 @@ function usePan(options = {}) {
|
|
|
294
305
|
const top = constraints?.top;
|
|
295
306
|
const bottom = constraints?.bottom;
|
|
296
307
|
const decel = deceleration;
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
308
|
+
const config = useMemo(
|
|
309
|
+
() => ({
|
|
310
|
+
onActivate: () => {
|
|
311
|
+
"worklet";
|
|
312
|
+
startX.value = panX.value;
|
|
313
|
+
startY.value = panY.value;
|
|
314
|
+
isPanning.value = true;
|
|
315
|
+
},
|
|
316
|
+
onUpdate: (e) => {
|
|
317
|
+
"worklet";
|
|
318
|
+
panX.value = clamp(startX.value + e.translationX, left, right);
|
|
319
|
+
panY.value = clamp(startY.value + e.translationY, top, bottom);
|
|
320
|
+
},
|
|
321
|
+
onDeactivate: (e) => {
|
|
322
|
+
"worklet";
|
|
323
|
+
isPanning.value = false;
|
|
324
|
+
if (disableMomentum) return;
|
|
325
|
+
const clampX = boundsTuple(left, right);
|
|
326
|
+
const clampY = boundsTuple(top, bottom);
|
|
327
|
+
panX.value = withDecay(decayConfig(e.velocityX, decel, clampX));
|
|
328
|
+
panY.value = withDecay(decayConfig(e.velocityY, decel, clampY));
|
|
329
|
+
},
|
|
330
|
+
onFinalize: () => {
|
|
331
|
+
"worklet";
|
|
332
|
+
isPanning.value = false;
|
|
333
|
+
}
|
|
334
|
+
}),
|
|
335
|
+
[
|
|
336
|
+
left,
|
|
337
|
+
right,
|
|
338
|
+
top,
|
|
339
|
+
bottom,
|
|
340
|
+
decel,
|
|
341
|
+
disableMomentum,
|
|
342
|
+
panX,
|
|
343
|
+
panY,
|
|
344
|
+
startX,
|
|
345
|
+
startY,
|
|
346
|
+
isPanning
|
|
347
|
+
]
|
|
348
|
+
);
|
|
349
|
+
const gesture = usePanGesture(config);
|
|
333
350
|
const animatedStyle = useTranslateStyle(panX, panY);
|
|
334
351
|
return { gesture, animatedStyle, panX, panY, isPanning };
|
|
335
352
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rootnative/inertia-gestures",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "Gesture-handler-driven drag / pan / swipe adapters for @rootnative/inertia.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RootNative",
|
|
@@ -50,28 +50,28 @@
|
|
|
50
50
|
"!**/*.test.*"
|
|
51
51
|
],
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@rootnative/inertia": ">=0.0.
|
|
54
|
-
"react": ">=19.
|
|
55
|
-
"react-native": ">=0.
|
|
56
|
-
"react-native-gesture-handler": ">=
|
|
57
|
-
"react-native-reanimated": ">=4.
|
|
53
|
+
"@rootnative/inertia": ">=0.0.20 <0.1.0",
|
|
54
|
+
"react": ">=19.3.0 <20.0.0",
|
|
55
|
+
"react-native": ">=0.88.0 <0.89.0",
|
|
56
|
+
"react-native-gesture-handler": ">=3.3.0 <4.0.0",
|
|
57
|
+
"react-native-reanimated": ">=4.7.0 <4.8.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@react-native/babel-preset": "^0.
|
|
61
|
-
"@react-native/jest-preset": "^0.
|
|
60
|
+
"@react-native/babel-preset": "^0.88.0",
|
|
61
|
+
"@react-native/jest-preset": "^0.88.0",
|
|
62
62
|
"@testing-library/react-native": "^13.3.3",
|
|
63
63
|
"@types/jest": "^29.5.14",
|
|
64
|
-
"@types/react": "^19.
|
|
64
|
+
"@types/react": "^19.3.0",
|
|
65
65
|
"jest": "^29.7.0",
|
|
66
|
-
"react": "19.
|
|
67
|
-
"react-native": "0.
|
|
68
|
-
"react-native-gesture-handler": "~
|
|
69
|
-
"react-native-reanimated": "4.
|
|
70
|
-
"react-native-worklets": "0.
|
|
71
|
-
"react-test-renderer": "19.
|
|
66
|
+
"react": "19.3.0",
|
|
67
|
+
"react-native": "0.88.0",
|
|
68
|
+
"react-native-gesture-handler": "~3.3.0",
|
|
69
|
+
"react-native-reanimated": "4.7.1",
|
|
70
|
+
"react-native-worklets": "0.13.0",
|
|
71
|
+
"react-test-renderer": "19.3.0",
|
|
72
72
|
"tsup": "^8.3.5",
|
|
73
73
|
"typescript": "^5.7.3",
|
|
74
|
-
"@rootnative/inertia": "0.0.
|
|
74
|
+
"@rootnative/inertia": "0.0.20"
|
|
75
75
|
},
|
|
76
76
|
"publishConfig": {
|
|
77
77
|
"access": "public"
|
package/src/useDrag.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
usePanGesture,
|
|
4
|
+
type PanGesture,
|
|
5
|
+
type PanGestureConfig,
|
|
6
|
+
} from 'react-native-gesture-handler'
|
|
3
7
|
import {
|
|
4
8
|
runOnJS,
|
|
5
9
|
useSharedValue,
|
|
@@ -91,16 +95,16 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
91
95
|
const fireDragStart = useLatestCallback(onDragStart)
|
|
92
96
|
const fireDragEnd = useLatestCallback(onDragEnd)
|
|
93
97
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
const config = useMemo<PanGestureConfig>(
|
|
99
|
+
() => ({
|
|
100
|
+
onActivate: () => {
|
|
97
101
|
'worklet'
|
|
98
102
|
startX.value = dragX.value
|
|
99
103
|
startY.value = dragY.value
|
|
100
104
|
isDragging.value = true
|
|
101
105
|
if (hasDragStart) runOnJS(fireDragStart)()
|
|
102
|
-
}
|
|
103
|
-
|
|
106
|
+
},
|
|
107
|
+
onUpdate: (e) => {
|
|
104
108
|
'worklet'
|
|
105
109
|
if (lockX) {
|
|
106
110
|
dragX.value = applyBounds(
|
|
@@ -118,8 +122,8 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
118
122
|
elasticCoef,
|
|
119
123
|
)
|
|
120
124
|
}
|
|
121
|
-
}
|
|
122
|
-
|
|
125
|
+
},
|
|
126
|
+
onDeactivate: (e) => {
|
|
123
127
|
'worklet'
|
|
124
128
|
isDragging.value = false
|
|
125
129
|
const x = dragX.value
|
|
@@ -151,27 +155,30 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
151
155
|
if (hasDragEnd) {
|
|
152
156
|
runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } })
|
|
153
157
|
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
[
|
|
161
|
+
lockX,
|
|
162
|
+
lockY,
|
|
163
|
+
left,
|
|
164
|
+
right,
|
|
165
|
+
top,
|
|
166
|
+
bottom,
|
|
167
|
+
elasticCoef,
|
|
168
|
+
hasDragStart,
|
|
169
|
+
hasDragEnd,
|
|
170
|
+
fireDragStart,
|
|
171
|
+
fireDragEnd,
|
|
172
|
+
onRelease,
|
|
173
|
+
dragX,
|
|
174
|
+
dragY,
|
|
175
|
+
startX,
|
|
176
|
+
startY,
|
|
177
|
+
isDragging,
|
|
178
|
+
],
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
const gesture = usePanGesture(config)
|
|
175
182
|
|
|
176
183
|
const animatedStyle = useTranslateStyle(dragX, dragY)
|
|
177
184
|
|
package/src/usePan.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
usePanGesture,
|
|
4
|
+
type PanGesture,
|
|
5
|
+
type PanGestureConfig,
|
|
6
|
+
} from 'react-native-gesture-handler'
|
|
3
7
|
import {
|
|
4
8
|
useSharedValue,
|
|
5
9
|
withDecay,
|
|
@@ -73,20 +77,20 @@ export function usePan(options: PanOptions = {}): UsePanResult {
|
|
|
73
77
|
const bottom = constraints?.bottom
|
|
74
78
|
const decel = deceleration
|
|
75
79
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
const config = useMemo<PanGestureConfig>(
|
|
81
|
+
() => ({
|
|
82
|
+
onActivate: () => {
|
|
79
83
|
'worklet'
|
|
80
84
|
startX.value = panX.value
|
|
81
85
|
startY.value = panY.value
|
|
82
86
|
isPanning.value = true
|
|
83
|
-
}
|
|
84
|
-
|
|
87
|
+
},
|
|
88
|
+
onUpdate: (e) => {
|
|
85
89
|
'worklet'
|
|
86
90
|
panX.value = clamp(startX.value + e.translationX, left, right)
|
|
87
91
|
panY.value = clamp(startY.value + e.translationY, top, bottom)
|
|
88
|
-
}
|
|
89
|
-
|
|
92
|
+
},
|
|
93
|
+
onDeactivate: (e) => {
|
|
90
94
|
'worklet'
|
|
91
95
|
isPanning.value = false
|
|
92
96
|
if (disableMomentum) return
|
|
@@ -94,25 +98,28 @@ export function usePan(options: PanOptions = {}): UsePanResult {
|
|
|
94
98
|
const clampY = boundsTuple(top, bottom)
|
|
95
99
|
panX.value = withDecay(decayConfig(e.velocityX, decel, clampX))
|
|
96
100
|
panY.value = withDecay(decayConfig(e.velocityY, decel, clampY))
|
|
97
|
-
}
|
|
98
|
-
|
|
101
|
+
},
|
|
102
|
+
onFinalize: () => {
|
|
99
103
|
'worklet'
|
|
100
104
|
isPanning.value = false
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
[
|
|
108
|
+
left,
|
|
109
|
+
right,
|
|
110
|
+
top,
|
|
111
|
+
bottom,
|
|
112
|
+
decel,
|
|
113
|
+
disableMomentum,
|
|
114
|
+
panX,
|
|
115
|
+
panY,
|
|
116
|
+
startX,
|
|
117
|
+
startY,
|
|
118
|
+
isPanning,
|
|
119
|
+
],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
const gesture = usePanGesture(config)
|
|
116
123
|
|
|
117
124
|
const animatedStyle = useTranslateStyle(panX, panY)
|
|
118
125
|
|
package/src/useSwipe.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
usePanGesture,
|
|
4
|
+
type PanGesture,
|
|
5
|
+
type PanGestureConfig,
|
|
6
|
+
} from 'react-native-gesture-handler'
|
|
3
7
|
import {
|
|
4
8
|
runOnJS,
|
|
5
9
|
useSharedValue,
|
|
@@ -230,18 +234,18 @@ export function useSwipe(options: SwipeOptions = {}): UseSwipeResult {
|
|
|
230
234
|
const fireSwipe = useLatestCallback(onSwipe)
|
|
231
235
|
const fireSwipeEnd = useLatestCallback(onSwipeEnd)
|
|
232
236
|
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
237
|
+
const config = useMemo<PanGestureConfig>(
|
|
238
|
+
() => ({
|
|
239
|
+
onActivate: () => {
|
|
236
240
|
'worklet'
|
|
237
241
|
isActive.value = true
|
|
238
|
-
}
|
|
239
|
-
|
|
242
|
+
},
|
|
243
|
+
onUpdate: (e) => {
|
|
240
244
|
'worklet'
|
|
241
245
|
swipeX.value = e.translationX
|
|
242
246
|
swipeY.value = e.translationY
|
|
243
|
-
}
|
|
244
|
-
|
|
247
|
+
},
|
|
248
|
+
onDeactivate: (e) => {
|
|
245
249
|
'worklet'
|
|
246
250
|
isActive.value = false
|
|
247
251
|
const direction = pickDirection(
|
|
@@ -322,29 +326,32 @@ export function useSwipe(options: SwipeOptions = {}): UseSwipeResult {
|
|
|
322
326
|
settleY,
|
|
323
327
|
) as unknown as number
|
|
324
328
|
}
|
|
325
|
-
}
|
|
326
|
-
|
|
329
|
+
},
|
|
330
|
+
onFinalize: () => {
|
|
327
331
|
'worklet'
|
|
328
332
|
isActive.value = false
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
333
|
+
},
|
|
334
|
+
}),
|
|
335
|
+
[
|
|
336
|
+
distanceThreshold,
|
|
337
|
+
velocityThreshold,
|
|
338
|
+
allowLeft,
|
|
339
|
+
allowRight,
|
|
340
|
+
allowUp,
|
|
341
|
+
allowDown,
|
|
342
|
+
snapBack,
|
|
343
|
+
hasSwipe,
|
|
344
|
+
hasSwipeEnd,
|
|
345
|
+
fireSwipe,
|
|
346
|
+
fireSwipeEnd,
|
|
347
|
+
onCommit,
|
|
348
|
+
swipeX,
|
|
349
|
+
swipeY,
|
|
350
|
+
isActive,
|
|
351
|
+
],
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
const gesture = usePanGesture(config)
|
|
348
355
|
|
|
349
356
|
const animatedStyle = useTranslateStyle(swipeX, swipeY)
|
|
350
357
|
|