@rootnative/inertia-gestures 0.0.22 → 0.0.24
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 +17 -1
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +22 -0
- package/dist/index.mjs +22 -0
- package/llms.txt +10 -10
- package/package.json +3 -3
- package/src/types.ts +8 -3
- package/src/useDrag.ts +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ This package ships in lockstep with `@rootnative/inertia` — version numbers tr
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.0.24] - 2026-10-31
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`useDrag` springs an `elastic` overshoot back inside its `constraints` on release.** With `elastic` above 0, a drag past a bound stretched the element past it, and the element stayed there after release until the next drag. The docs promised a Framer Motion feel, and that feel includes the return. Now an axis that lands past `constraints` and gets no transition from `onRelease` springs back to the nearest bound, with the default spring and the release velocity. A transition that `onRelease` returns for an axis still replaces the spring back on that axis, and an axis that lands inside the bounds stays where it landed, as before. `useTouchDrag` in `@rootnative/inertia` gets the same fix.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- The `@rootnative/inertia` peer range moves to `>=0.0.24 <0.1.0`, in lockstep.
|
|
18
|
+
|
|
19
|
+
## [0.0.23] - 2026-10-31
|
|
20
|
+
|
|
21
|
+
**Lockstep version bump** alongside `@rootnative/inertia@0.0.23` (the `useHideOnScroll` hook, a 0↔1 shared value from the direction of a scroll). No runtime changes in this adapter; the `@rootnative/inertia` peer range moves to `>=0.0.23 <0.1.0`.
|
|
22
|
+
|
|
9
23
|
## [0.0.22] - 2026-10-29
|
|
10
24
|
|
|
11
25
|
**Lockstep version bump** alongside `@rootnative/inertia@0.0.22` (`<Presence>` removes a departing child that holds no `Motion.*`). No runtime changes in this adapter; the `@rootnative/inertia` peer range moves to `>=0.0.22 <0.1.0`.
|
|
@@ -148,7 +162,9 @@ Initial alpha publish alongside `@rootnative/inertia@0.0.0-alpha.0`. Optional ad
|
|
|
148
162
|
- `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.
|
|
149
163
|
- `useSwipe`, `usePan` hooks composable with any `Motion.*` primitive via `<GestureDetector>`.
|
|
150
164
|
|
|
151
|
-
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.
|
|
165
|
+
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.24...HEAD
|
|
166
|
+
[0.0.24]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.24
|
|
167
|
+
[0.0.23]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.23
|
|
152
168
|
[0.0.22]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.22
|
|
153
169
|
[0.0.21]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.21
|
|
154
170
|
[0.0.20]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.20
|
package/dist/index.d.mts
CHANGED
|
@@ -47,7 +47,9 @@ type ReleaseTransition = (SpringTransition & {
|
|
|
47
47
|
});
|
|
48
48
|
/**
|
|
49
49
|
* Per-axis release transitions returned by `onRelease`. Omit an axis to leave
|
|
50
|
-
* its SV where it landed (no release animation on that axis).
|
|
50
|
+
* its SV where it landed (no release animation on that axis). An omitted axis
|
|
51
|
+
* that landed past `constraints` (an `elastic` overshoot) springs back to the
|
|
52
|
+
* nearest bound.
|
|
51
53
|
*
|
|
52
54
|
* `useSwipe`'s `onCommit` returns the same shape with one difference in the
|
|
53
55
|
* omit semantics: an omitted axis snaps back to zero (the hook's resting
|
|
@@ -83,7 +85,9 @@ interface DragOptions {
|
|
|
83
85
|
/**
|
|
84
86
|
* Rubber-band coefficient applied to overshoot past `constraints`. `0`
|
|
85
87
|
* (default) hard-clamps; `1` is fully elastic (no resistance). Typical
|
|
86
|
-
* Framer-Motion-style feel sits around `0.2`–`0.4`.
|
|
88
|
+
* Framer-Motion-style feel sits around `0.2`–`0.4`. On release, an
|
|
89
|
+
* overshoot springs back to the nearest bound with the release velocity,
|
|
90
|
+
* unless `onRelease` returns a transition for that axis.
|
|
87
91
|
*/
|
|
88
92
|
elastic?: number;
|
|
89
93
|
/**
|
|
@@ -99,7 +103,8 @@ interface DragOptions {
|
|
|
99
103
|
* UI-thread callback fired on release. Return per-axis release transitions
|
|
100
104
|
* to animate the SVs to a settled position via Inertia's transition
|
|
101
105
|
* resolver — spring snap-to-tick, decay with bounds, timing settle, etc.
|
|
102
|
-
* Omit an axis (or return nothing) to leave that SV where it landed
|
|
106
|
+
* Omit an axis (or return nothing) to leave that SV where it landed, or,
|
|
107
|
+
* after an `elastic` overshoot, to spring it back inside `constraints`.
|
|
103
108
|
*
|
|
104
109
|
* This callback runs as a worklet so the release velocity stays on the UI
|
|
105
110
|
* thread. Author it with the `'worklet'` directive at the top of the body.
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,9 @@ type ReleaseTransition = (SpringTransition & {
|
|
|
47
47
|
});
|
|
48
48
|
/**
|
|
49
49
|
* Per-axis release transitions returned by `onRelease`. Omit an axis to leave
|
|
50
|
-
* its SV where it landed (no release animation on that axis).
|
|
50
|
+
* its SV where it landed (no release animation on that axis). An omitted axis
|
|
51
|
+
* that landed past `constraints` (an `elastic` overshoot) springs back to the
|
|
52
|
+
* nearest bound.
|
|
51
53
|
*
|
|
52
54
|
* `useSwipe`'s `onCommit` returns the same shape with one difference in the
|
|
53
55
|
* omit semantics: an omitted axis snaps back to zero (the hook's resting
|
|
@@ -83,7 +85,9 @@ interface DragOptions {
|
|
|
83
85
|
/**
|
|
84
86
|
* Rubber-band coefficient applied to overshoot past `constraints`. `0`
|
|
85
87
|
* (default) hard-clamps; `1` is fully elastic (no resistance). Typical
|
|
86
|
-
* Framer-Motion-style feel sits around `0.2`–`0.4`.
|
|
88
|
+
* Framer-Motion-style feel sits around `0.2`–`0.4`. On release, an
|
|
89
|
+
* overshoot springs back to the nearest bound with the release velocity,
|
|
90
|
+
* unless `onRelease` returns a transition for that axis.
|
|
87
91
|
*/
|
|
88
92
|
elastic?: number;
|
|
89
93
|
/**
|
|
@@ -99,7 +103,8 @@ interface DragOptions {
|
|
|
99
103
|
* UI-thread callback fired on release. Return per-axis release transitions
|
|
100
104
|
* to animate the SVs to a settled position via Inertia's transition
|
|
101
105
|
* resolver — spring snap-to-tick, decay with bounds, timing settle, etc.
|
|
102
|
-
* Omit an axis (or return nothing) to leave that SV where it landed
|
|
106
|
+
* Omit an axis (or return nothing) to leave that SV where it landed, or,
|
|
107
|
+
* after an `elastic` overshoot, to spring it back inside `constraints`.
|
|
103
108
|
*
|
|
104
109
|
* This callback runs as a worklet so the release velocity stays on the UI
|
|
105
110
|
* thread. Author it with the `'worklet'` directive at the top of the body.
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,8 @@ function useDrag(options = {}) {
|
|
|
75
75
|
const y = dragY.value;
|
|
76
76
|
const vx = e.velocityX;
|
|
77
77
|
const vy = e.velocityY;
|
|
78
|
+
let releasedX = false;
|
|
79
|
+
let releasedY = false;
|
|
78
80
|
if (onRelease) {
|
|
79
81
|
const result = onRelease({ x, y, velocity: { x: vx, y: vy } });
|
|
80
82
|
if (result) {
|
|
@@ -84,6 +86,7 @@ function useDrag(options = {}) {
|
|
|
84
86
|
result.x,
|
|
85
87
|
toX
|
|
86
88
|
);
|
|
89
|
+
releasedX = true;
|
|
87
90
|
}
|
|
88
91
|
if (result.y && lockY) {
|
|
89
92
|
const toY = "to" in result.y ? result.y.to : y;
|
|
@@ -91,9 +94,28 @@ function useDrag(options = {}) {
|
|
|
91
94
|
result.y,
|
|
92
95
|
toY
|
|
93
96
|
);
|
|
97
|
+
releasedY = true;
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
}
|
|
101
|
+
if (lockX && !releasedX) {
|
|
102
|
+
const restX = inertia.applyBounds(x, left, right, 0);
|
|
103
|
+
if (restX !== x) {
|
|
104
|
+
dragX.value = inertia.buildReleaseAnimation(
|
|
105
|
+
{ type: "spring", velocity: vx },
|
|
106
|
+
restX
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (lockY && !releasedY) {
|
|
111
|
+
const restY = inertia.applyBounds(y, top, bottom, 0);
|
|
112
|
+
if (restY !== y) {
|
|
113
|
+
dragY.value = inertia.buildReleaseAnimation(
|
|
114
|
+
{ type: "spring", velocity: vy },
|
|
115
|
+
restY
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
97
119
|
if (hasDragEnd) {
|
|
98
120
|
reactNativeReanimated.runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } });
|
|
99
121
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -73,6 +73,8 @@ function useDrag(options = {}) {
|
|
|
73
73
|
const y = dragY.value;
|
|
74
74
|
const vx = e.velocityX;
|
|
75
75
|
const vy = e.velocityY;
|
|
76
|
+
let releasedX = false;
|
|
77
|
+
let releasedY = false;
|
|
76
78
|
if (onRelease) {
|
|
77
79
|
const result = onRelease({ x, y, velocity: { x: vx, y: vy } });
|
|
78
80
|
if (result) {
|
|
@@ -82,6 +84,7 @@ function useDrag(options = {}) {
|
|
|
82
84
|
result.x,
|
|
83
85
|
toX
|
|
84
86
|
);
|
|
87
|
+
releasedX = true;
|
|
85
88
|
}
|
|
86
89
|
if (result.y && lockY) {
|
|
87
90
|
const toY = "to" in result.y ? result.y.to : y;
|
|
@@ -89,9 +92,28 @@ function useDrag(options = {}) {
|
|
|
89
92
|
result.y,
|
|
90
93
|
toY
|
|
91
94
|
);
|
|
95
|
+
releasedY = true;
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
}
|
|
99
|
+
if (lockX && !releasedX) {
|
|
100
|
+
const restX = applyBounds(x, left, right, 0);
|
|
101
|
+
if (restX !== x) {
|
|
102
|
+
dragX.value = buildReleaseAnimation(
|
|
103
|
+
{ type: "spring", velocity: vx },
|
|
104
|
+
restX
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (lockY && !releasedY) {
|
|
109
|
+
const restY = applyBounds(y, top, bottom, 0);
|
|
110
|
+
if (restY !== y) {
|
|
111
|
+
dragY.value = buildReleaseAnimation(
|
|
112
|
+
{ type: "spring", velocity: vy },
|
|
113
|
+
restY
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
95
117
|
if (hasDragEnd) {
|
|
96
118
|
runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } });
|
|
97
119
|
}
|
package/llms.txt
CHANGED
|
@@ -45,20 +45,20 @@ function DraggableBox() {
|
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
| Option | Type | Default | Notes
|
|
49
|
-
| ------------- | ---------------------------------------------- | -------- |
|
|
50
|
-
| `axis` | `'x' \| 'y' \| 'both'` | `'both'` | Lock the gesture to one axis.
|
|
51
|
-
| `constraints` | `{ left?, right?, top?, bottom? }` | none | Bounds in px from the resting position. Each side independently optional.
|
|
52
|
-
| `elastic` | `number` (0–1) | `0` | Rubber-band coefficient past `constraints`. `0` hard-clamps; `0.4` is a typical Framer-Motion feel. |
|
|
53
|
-
| `onDragStart` | `() => void` | none | Fires on JS thread when drag begins.
|
|
54
|
-
| `onDragEnd` | `(info: { x, y, velocity: { x, y } }) => void` | none | Fires on JS thread when drag ends.
|
|
55
|
-
| `onRelease` | `(info) => ReleaseResult \| void` (worklet) | none | UI-thread release transition — see below.
|
|
48
|
+
| Option | Type | Default | Notes |
|
|
49
|
+
| ------------- | ---------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
50
|
+
| `axis` | `'x' \| 'y' \| 'both'` | `'both'` | Lock the gesture to one axis. |
|
|
51
|
+
| `constraints` | `{ left?, right?, top?, bottom? }` | none | Bounds in px from the resting position. Each side independently optional. |
|
|
52
|
+
| `elastic` | `number` (0–1) | `0` | Rubber-band coefficient past `constraints`. `0` hard-clamps; `0.4` is a typical Framer-Motion feel. An overshoot springs back to the bound on release. |
|
|
53
|
+
| `onDragStart` | `() => void` | none | Fires on JS thread when drag begins. |
|
|
54
|
+
| `onDragEnd` | `(info: { x, y, velocity: { x, y } }) => void` | none | Fires on JS thread when drag ends. |
|
|
55
|
+
| `onRelease` | `(info) => ReleaseResult \| void` (worklet) | none | UI-thread release transition — see below. |
|
|
56
56
|
|
|
57
57
|
Returns `{ gesture, animatedStyle, dragX, dragY, isDragging }`. The shared values are exposed for power use cases (deriving secondary effects from drag position).
|
|
58
58
|
|
|
59
59
|
### Release transitions (`onRelease`)
|
|
60
60
|
|
|
61
|
-
By default `useDrag` leaves the shared values
|
|
61
|
+
By default `useDrag` leaves the shared values where the finger lifted. The one exception is an `elastic` overshoot: an axis that lifted past `constraints` springs back to the nearest bound with the default spring and the release velocity. Pass `onRelease` to animate them to a settled position via Inertia's transition vocabulary — spring snap-to-tick, decay with bounds, timing settle. The callback runs as a **worklet** so the release velocity stays on the UI thread (no JS round-trip):
|
|
62
62
|
|
|
63
63
|
```tsx
|
|
64
64
|
const drag = useDrag({
|
|
@@ -75,7 +75,7 @@ const drag = useDrag({
|
|
|
75
75
|
})
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Return per-axis release transitions in a `ReleaseResult` shape — omit an axis (or return nothing) to leave that SV where it landed. The transition shapes mirror the core `transition` prop:
|
|
78
|
+
Return per-axis release transitions in a `ReleaseResult` shape — omit an axis (or return nothing) to leave that SV where it landed, or, after an `elastic` overshoot, to spring it back inside `constraints`. A transition you return for an axis replaces the spring back on that axis. The transition shapes mirror the core `transition` prop:
|
|
79
79
|
|
|
80
80
|
```ts
|
|
81
81
|
type ReleaseTransition =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rootnative/inertia-gestures",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Gesture-handler-driven drag / pan / swipe adapters for @rootnative/inertia.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RootNative",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"!**/*.test.*"
|
|
51
51
|
],
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@rootnative/inertia": ">=0.0.
|
|
53
|
+
"@rootnative/inertia": ">=0.0.24 <0.1.0",
|
|
54
54
|
"react": ">=19.3.0 <20.0.0",
|
|
55
55
|
"react-native": ">=0.88.0 <0.89.0",
|
|
56
56
|
"react-native-gesture-handler": ">=3.3.0 <4.0.0",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
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.24"
|
|
75
75
|
},
|
|
76
76
|
"publishConfig": {
|
|
77
77
|
"access": "public"
|
package/src/types.ts
CHANGED
|
@@ -48,7 +48,9 @@ export type ReleaseTransition =
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Per-axis release transitions returned by `onRelease`. Omit an axis to leave
|
|
51
|
-
* its SV where it landed (no release animation on that axis).
|
|
51
|
+
* its SV where it landed (no release animation on that axis). An omitted axis
|
|
52
|
+
* that landed past `constraints` (an `elastic` overshoot) springs back to the
|
|
53
|
+
* nearest bound.
|
|
52
54
|
*
|
|
53
55
|
* `useSwipe`'s `onCommit` returns the same shape with one difference in the
|
|
54
56
|
* omit semantics: an omitted axis snaps back to zero (the hook's resting
|
|
@@ -89,7 +91,9 @@ export interface DragOptions {
|
|
|
89
91
|
/**
|
|
90
92
|
* Rubber-band coefficient applied to overshoot past `constraints`. `0`
|
|
91
93
|
* (default) hard-clamps; `1` is fully elastic (no resistance). Typical
|
|
92
|
-
* Framer-Motion-style feel sits around `0.2`–`0.4`.
|
|
94
|
+
* Framer-Motion-style feel sits around `0.2`–`0.4`. On release, an
|
|
95
|
+
* overshoot springs back to the nearest bound with the release velocity,
|
|
96
|
+
* unless `onRelease` returns a transition for that axis.
|
|
93
97
|
*/
|
|
94
98
|
elastic?: number
|
|
95
99
|
/**
|
|
@@ -105,7 +109,8 @@ export interface DragOptions {
|
|
|
105
109
|
* UI-thread callback fired on release. Return per-axis release transitions
|
|
106
110
|
* to animate the SVs to a settled position via Inertia's transition
|
|
107
111
|
* resolver — spring snap-to-tick, decay with bounds, timing settle, etc.
|
|
108
|
-
* Omit an axis (or return nothing) to leave that SV where it landed
|
|
112
|
+
* Omit an axis (or return nothing) to leave that SV where it landed, or,
|
|
113
|
+
* after an `elastic` overshoot, to spring it back inside `constraints`.
|
|
109
114
|
*
|
|
110
115
|
* This callback runs as a worklet so the release velocity stays on the UI
|
|
111
116
|
* thread. Author it with the `'worklet'` directive at the top of the body.
|
package/src/useDrag.ts
CHANGED
|
@@ -130,6 +130,8 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
130
130
|
const y = dragY.value
|
|
131
131
|
const vx = e.velocityX
|
|
132
132
|
const vy = e.velocityY
|
|
133
|
+
let releasedX = false
|
|
134
|
+
let releasedY = false
|
|
133
135
|
if (onRelease) {
|
|
134
136
|
const result = onRelease({ x, y, velocity: { x: vx, y: vy } })
|
|
135
137
|
if (result) {
|
|
@@ -142,6 +144,7 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
142
144
|
result.x,
|
|
143
145
|
toX,
|
|
144
146
|
) as unknown as number
|
|
147
|
+
releasedX = true
|
|
145
148
|
}
|
|
146
149
|
if (result.y && lockY) {
|
|
147
150
|
const toY = 'to' in result.y ? result.y.to : y
|
|
@@ -149,9 +152,31 @@ export function useDrag(options: DragOptions = {}): UseDragResult {
|
|
|
149
152
|
result.y,
|
|
150
153
|
toY,
|
|
151
154
|
) as unknown as number
|
|
155
|
+
releasedY = true
|
|
152
156
|
}
|
|
153
157
|
}
|
|
154
158
|
}
|
|
159
|
+
// An elastic overshoot that gets no release transition springs back
|
|
160
|
+
// to the nearest bound with the release velocity. Without this it
|
|
161
|
+
// stays stretched past `constraints` until the next drag.
|
|
162
|
+
if (lockX && !releasedX) {
|
|
163
|
+
const restX = applyBounds(x, left, right, 0)
|
|
164
|
+
if (restX !== x) {
|
|
165
|
+
dragX.value = buildReleaseAnimation(
|
|
166
|
+
{ type: 'spring', velocity: vx },
|
|
167
|
+
restX,
|
|
168
|
+
) as unknown as number
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (lockY && !releasedY) {
|
|
172
|
+
const restY = applyBounds(y, top, bottom, 0)
|
|
173
|
+
if (restY !== y) {
|
|
174
|
+
dragY.value = buildReleaseAnimation(
|
|
175
|
+
{ type: 'spring', velocity: vy },
|
|
176
|
+
restY,
|
|
177
|
+
) as unknown as number
|
|
178
|
+
}
|
|
179
|
+
}
|
|
155
180
|
if (hasDragEnd) {
|
|
156
181
|
runOnJS(fireDragEnd)({ x, y, velocity: { x: vx, y: vy } })
|
|
157
182
|
}
|