@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +51 -5
  2. package/README.md +206 -11
  3. package/dist/{chunk-5BMRKYVY.js → chunk-2UZTAWUQ.js} +20 -2
  4. package/dist/chunk-BNSFDNLA.js +75 -0
  5. package/dist/chunk-DXXGWG4Q.js +136 -0
  6. package/dist/{chunk-PMR25UCT.js → chunk-HGBCIL6X.js} +1 -1
  7. package/dist/chunk-HI5PHDJY.js +94 -0
  8. package/dist/{chunk-IG5RXCYR.js → chunk-IH7SQ5X6.js} +11 -15
  9. package/dist/chunk-MWCIEVTA.js +199 -0
  10. package/dist/{chunk-F4RHM4ZK.js → chunk-NYDDZD4G.js} +58 -1
  11. package/dist/chunk-PGOQSKEJ.js +144 -0
  12. package/dist/{chunk-FR242SUF.js → chunk-TGOGIZDH.js} +13 -7
  13. package/dist/chunk-VEPUHGPN.js +12 -0
  14. package/dist/chunk-YZHAQ4XK.js +136 -0
  15. package/dist/compose/index.d.ts +1 -1
  16. package/dist/double-tap/index.d.ts +184 -0
  17. package/dist/double-tap/index.js +5 -0
  18. package/dist/drag/index.d.ts +18 -13
  19. package/dist/drag/index.js +3 -3
  20. package/dist/index.d.ts +10 -3
  21. package/dist/index.js +12 -5
  22. package/dist/long-press/index.d.ts +219 -0
  23. package/dist/long-press/index.js +4 -0
  24. package/dist/pan/index.d.ts +221 -0
  25. package/dist/pan/index.js +4 -0
  26. package/dist/pinch/index.d.ts +239 -0
  27. package/dist/pinch/index.js +4 -0
  28. package/dist/raw/index.d.ts +3 -3
  29. package/dist/raw/index.js +2 -2
  30. package/dist/rotate/index.d.ts +263 -0
  31. package/dist/rotate/index.js +4 -0
  32. package/dist/swipe/index.d.ts +254 -0
  33. package/dist/swipe/index.js +4 -0
  34. package/dist/tap/index.d.ts +34 -29
  35. package/dist/tap/index.js +4 -3
  36. package/dist/tapEvent-KSSojt_l.d.ts +28 -0
  37. package/dist/{types-Ch2HM3aP.d.ts → types-ChGKY28a.d.ts} +27 -1
  38. package/dist/{useGestureMemo-Ccv8rB0C.d.ts → useGestureMemo-BRW1EKcJ.d.ts} +1 -1
  39. package/jest-setup.cjs +32 -1
  40. package/llms.txt +155 -0
  41. package/package.json +35 -2
  42. package/src/index.ts +50 -4
  43. package/src/intents/double-tap/index.ts +6 -0
  44. package/src/intents/long-press/index.ts +6 -0
  45. package/src/intents/pan/index.ts +2 -0
  46. package/src/intents/pinch/index.ts +2 -0
  47. package/src/intents/rotate/index.ts +6 -0
  48. package/src/intents/swipe/index.ts +8 -0
  49. package/src/intents/tapEvent.ts +50 -0
  50. package/src/intents/useDoubleTap.ts +321 -0
  51. package/src/intents/useDrag.ts +49 -28
  52. package/src/intents/useLongPress.ts +391 -0
  53. package/src/intents/usePan.ts +444 -0
  54. package/src/intents/usePinch.ts +483 -0
  55. package/src/intents/useRotate.ts +507 -0
  56. package/src/intents/useSwipe.ts +585 -0
  57. package/src/intents/useTap.ts +51 -60
  58. package/src/internal/intentResult.ts +67 -0
  59. package/src/internal/phaseCallbacks.ts +51 -0
  60. package/src/internal/useGestureMemo.ts +32 -4
  61. package/src/internal/useLatestCallback.ts +2 -2
  62. package/src/raw/useRawGesture.ts +1 -1
  63. package/src/relations/index.ts +94 -0
  64. package/src/types.ts +27 -0
@@ -0,0 +1,4 @@
1
+ export { useLongPress } from '../chunk-HI5PHDJY.js';
2
+ import '../chunk-2UZTAWUQ.js';
3
+ import '../chunk-NYDDZD4G.js';
4
+ import '../chunk-ZX7WNICB.js';
@@ -0,0 +1,221 @@
1
+ import { PanGesture } from 'react-native-gesture-handler';
2
+ import { SharedValue } from 'react-native-reanimated';
3
+ import { G as GestureMemoOptions } from '../useGestureMemo-BRW1EKcJ.js';
4
+ import { P as Point, H as HitSlop, I as IntentEndInfo, c as IntentResult } from '../types-ChGKY28a.js';
5
+ import 'react';
6
+
7
+ /** Which way the pan is allowed to move. */
8
+ type PanAxis = 'x' | 'y' | 'both';
9
+ /** The intent-shaped payload a {@link usePan} callback receives. */
10
+ interface PanEvent {
11
+ /**
12
+ * How far the finger has moved since the pan activated.
13
+ *
14
+ * Measured from the activation point, not from touch-down, so it does not
15
+ * include the `threshold` travel the finger spent before the pan existed.
16
+ * It resets to zero at the start of every gesture — a pan reports movement
17
+ * and owns no position.
18
+ */
19
+ readonly translation: Point;
20
+ /**
21
+ * How far the finger moved since the previous frame.
22
+ *
23
+ * The field `useDrag` cannot give, and the reason to reach for this hook:
24
+ * a value the consumer owns is advanced by adding this, rather than by
25
+ * re-deriving it from a translation Impulse already clamped.
26
+ *
27
+ * Zero outside `onUpdate`. The first frame after activation reports the
28
+ * movement since activation, so a value advanced by `change` never jumps
29
+ * by `threshold`.
30
+ */
31
+ readonly change: Point;
32
+ /** Finger speed, in points per second. */
33
+ readonly velocity: Point;
34
+ /** The touch point relative to the window. */
35
+ readonly absolute: Point;
36
+ /** How many fingers are down. */
37
+ readonly pointers: number;
38
+ }
39
+ /** Options for {@link usePan}. */
40
+ interface UsePanOptions extends GestureMemoOptions {
41
+ /**
42
+ * Which way the pan may move. Default `'both'`.
43
+ *
44
+ * The locked axis reports zero for the life of the hook — `axis: 'x'`
45
+ * leaves `y`, `translation.y`, and `change.y` at zero. The axis also
46
+ * decides the activation criterion, which is the part that matters inside
47
+ * a scroll view: see `threshold`.
48
+ */
49
+ axis?: PanAxis;
50
+ /**
51
+ * How far the finger must travel before the pan activates, in points.
52
+ * Default `10`.
53
+ *
54
+ * On a single axis this is a directional threshold, so a pan with
55
+ * `axis: 'x'` ignores vertical movement entirely and a vertical scroll view
56
+ * under it keeps working. On `'both'` it is a radial distance.
57
+ */
58
+ threshold?: number;
59
+ /**
60
+ * Movement across the axis that makes the pan fail, in points. Unset by
61
+ * default, which leaves RNGH's own behaviour in place.
62
+ *
63
+ * `threshold` decides when the pan wins; this decides when it gives up.
64
+ * Ignored when `axis` is `'both'`, which has no cross axis.
65
+ */
66
+ failOffset?: number;
67
+ /**
68
+ * How many fingers must be on the view. Unset by default, which leaves
69
+ * RNGH's range of one to ten in place.
70
+ *
71
+ * Setting it fixes the count exactly, so `pointers: 2` is a two-finger pan
72
+ * that neither starts with one finger nor survives a third.
73
+ */
74
+ pointers?: number;
75
+ /**
76
+ * Extra touchable area around the view, in points.
77
+ *
78
+ * Written inline as an object is fine — the gesture is not rebuilt when the
79
+ * contents are unchanged.
80
+ */
81
+ hitSlop?: HitSlop;
82
+ /**
83
+ * Whether the gesture is recognized at all. Default `true`.
84
+ *
85
+ * Prefer this over unmounting the `<GestureDetector>`: a disabled gesture
86
+ * keeps its identity and its relations, so re-enabling it does not
87
+ * re-attach anything.
88
+ */
89
+ enabled?: boolean;
90
+ /**
91
+ * The pan passed `threshold` and now owns the touch. **Runs on the JS
92
+ * thread** — Impulse owns the `scheduleOnRN` boundary, so this is an
93
+ * ordinary function and may touch React state.
94
+ *
95
+ * This is the first moment the pan has definitely won. `onBegin` fires
96
+ * earlier and promises nothing.
97
+ */
98
+ onPanStart?: (event: PanEvent) => void;
99
+ /**
100
+ * The pan is over. **Runs on the JS thread.**
101
+ *
102
+ * Fires only for a pan that activated, so a touch that never passed the
103
+ * threshold never reaches here on either path.
104
+ *
105
+ * It fires for both endings, and `cancelled` says which. `false` is the
106
+ * finger lifting, and `velocity` then describes the release. `true` is the
107
+ * system taking the pan away — a competing gesture won, or the app went to
108
+ * the background. **There was no release on that path, so the velocity
109
+ * describes the last movement rather than a throw.**
110
+ */
111
+ onPanEnd?: (event: PanEvent, info: IntentEndInfo) => void;
112
+ /**
113
+ * The finger went down and the gesture is now a candidate. **This is a
114
+ * worklet** — mark it with the `'worklet'` directive, and do not touch
115
+ * React state from it.
116
+ *
117
+ * Being a candidate is not the same as winning: the pan has not passed
118
+ * `threshold` yet and may never. Undo whatever it sets in `onFinalize`.
119
+ */
120
+ onBegin?: (event: PanEvent) => void;
121
+ /**
122
+ * The pan moved. **This is a worklet**, and it runs on every frame the
123
+ * finger moves.
124
+ *
125
+ * This is where `change` is read, and it is the reason the hook exists:
126
+ * advance the value the consumer owns from here, on the thread that already
127
+ * holds it.
128
+ *
129
+ * There is no JS-thread counterpart on purpose. A per-frame `scheduleOnRN`
130
+ * is a scheduling cost paid sixty times a second for a value that is
131
+ * already on the thread that needs it.
132
+ */
133
+ onUpdate?: (event: PanEvent) => void;
134
+ /**
135
+ * The gesture is over, whether it activated or not. **This is a worklet.**
136
+ *
137
+ * `success` is `true` when the pan activated and ended normally. This is
138
+ * the right place to clear anything `onBegin` set, because it runs on both
139
+ * paths.
140
+ */
141
+ onFinalize?: (event: PanEvent, success: boolean) => void;
142
+ }
143
+ /** What {@link usePan} returns. */
144
+ interface UsePanResult extends IntentResult<PanGesture> {
145
+ /**
146
+ * How far the finger has moved along the x axis since the pan activated.
147
+ *
148
+ * **This is movement, not a position.** It is set to zero at the start of
149
+ * every gesture, so a second pan does not continue from where the first
150
+ * stopped. `useDrag` is the hook whose value accumulates.
151
+ *
152
+ * It keeps its final number after the gesture ends, so a release animation
153
+ * has something to animate from.
154
+ *
155
+ * Frozen at zero when `axis` is `'y'`.
156
+ */
157
+ readonly x: SharedValue<number>;
158
+ /**
159
+ * How far the finger has moved along the y axis since the pan activated.
160
+ * Same terms as `x`. Frozen at zero when `axis` is `'x'`.
161
+ */
162
+ readonly y: SharedValue<number>;
163
+ }
164
+ /**
165
+ * Recognize a pan, and report how the finger moved.
166
+ *
167
+ * ```tsx
168
+ * const camera = { x: useSharedValue(0), y: useSharedValue(0) }
169
+ * const pan = usePan({
170
+ * onUpdate: (event) => {
171
+ * 'worklet'
172
+ * camera.x.value += event.change.x
173
+ * camera.y.value += event.change.y
174
+ * },
175
+ * })
176
+ *
177
+ * return (
178
+ * <GestureDetector gesture={pan.gesture}>
179
+ * <Animated.View style={style} />
180
+ * </GestureDetector>
181
+ * )
182
+ * ```
183
+ *
184
+ * **`usePan` reports movement; `useDrag` owns a position.** That is the whole
185
+ * difference, and it decides which one a screen wants. `useDrag` holds `x`
186
+ * and `y` as the place a thing sits: they accumulate across gestures, they
187
+ * are clamped by `bounds`, and `elastic` bends them. `usePan` holds no
188
+ * position at all — it hands over `translation`, `velocity`, and a per-frame
189
+ * `change`, and the consumer advances whatever it drives. Reach for `useDrag`
190
+ * to move a view. Reach for this one to pan a camera, scrub a value, or feed
191
+ * a number Impulse has no business clamping.
192
+ *
193
+ * **Activation criteria.** `threshold` defaults to 10 points. With
194
+ * `axis: 'x'` or `'y'` it is directional, so a horizontal pan inside a
195
+ * vertical `ScrollView` leaves the scroll alone until the finger commits
196
+ * sideways; with `'both'` it is a radial distance. The device sweep did not
197
+ * test the default.
198
+ *
199
+ * **Coexistence.** A threshold decides who moves first; it does not decide
200
+ * who wins a contested touch. Say which gesture the touch belongs to as well
201
+ * — `deferTo` for a pan that is the fallback, `blocks` for one that is the
202
+ * foreground affordance, `alongside` for a pan that shares the touch with a
203
+ * pinch.
204
+ *
205
+ * **Web.** RNGH recognizes pan from pointer events, so a mouse drag behaves
206
+ * the same as a touch drag and `velocity` is reported in the same units. A
207
+ * trackpad's momentum scroll is not a pan and never reaches this hook.
208
+ * `pointers` above 1 is unreliable on web.
209
+ *
210
+ * **Accessibility.** A pan is invisible to a screen reader and unreachable
211
+ * from a keyboard, and this hook does not fix that. Whatever the pan moves
212
+ * must be reachable another way: buttons that step the value, a reset
213
+ * control for a panned canvas, or `accessibilityActions` with
214
+ * `onAccessibilityAction`. A pan-only affordance is a bug, not a trade-off.
215
+ *
216
+ * @param options - Activation criteria, callbacks, and the `alongside` /
217
+ * `blocks` / `deferTo` coexistence options every Impulse hook accepts.
218
+ */
219
+ declare function usePan(options?: UsePanOptions): UsePanResult;
220
+
221
+ export { type PanAxis, type PanEvent, type UsePanOptions, type UsePanResult, usePan };
@@ -0,0 +1,4 @@
1
+ export { usePan } from '../chunk-PGOQSKEJ.js';
2
+ import '../chunk-2UZTAWUQ.js';
3
+ import '../chunk-NYDDZD4G.js';
4
+ import '../chunk-ZX7WNICB.js';
@@ -0,0 +1,239 @@
1
+ import { PinchGesture } from 'react-native-gesture-handler';
2
+ import { SharedValue } from 'react-native-reanimated';
3
+ import { G as GestureMemoOptions } from '../useGestureMemo-BRW1EKcJ.js';
4
+ import { P as Point, H as HitSlop, I as IntentEndInfo, c as IntentResult } from '../types-ChGKY28a.js';
5
+ import 'react';
6
+
7
+ /** The intent-shaped payload a {@link usePinch} callback receives. */
8
+ interface PinchEvent {
9
+ /**
10
+ * How much the thing is scaled now — the same number as `scale`, after
11
+ * `min`, `max` and `elastic` were applied.
12
+ *
13
+ * This accumulates across gestures. A second pinch continues from where the
14
+ * first one stopped, which is why `min` and `max` can be written as the
15
+ * zoom range of the whole viewer rather than of one gesture.
16
+ */
17
+ readonly scale: number;
18
+ /**
19
+ * How much the fingers scaled during **this gesture alone**, raw.
20
+ *
21
+ * Untouched by `min`, `max` and `elastic`, and reset to `1` at the start of
22
+ * every gesture. This is RNGH's own `scale`. Read `scale` for how big the
23
+ * thing being pinched actually is.
24
+ */
25
+ readonly gestureScale: number;
26
+ /**
27
+ * The midpoint between the fingers, relative to the view.
28
+ *
29
+ * This is the point the zoom must happen about. A pinch scaled about the
30
+ * view's centre instead slides the content out from under the fingers, and
31
+ * that is the defect this field exists to prevent.
32
+ */
33
+ readonly focal: Point;
34
+ /** How fast the scale is changing, in scale units per second. */
35
+ readonly velocity: number;
36
+ /**
37
+ * The nearest scale inside `min` and `max`. Equal to `scale` whenever the
38
+ * pinch is in range, which with the default `elastic` of `0` is always.
39
+ *
40
+ * With `elastic` set, the fingers can pull the scale past an end and
41
+ * Impulse leaves it there on release — moving it back is an animation, and
42
+ * Impulse owns no animation vocabulary. This field is the destination that
43
+ * animation needs, so the consumer does not have to re-derive the clamp
44
+ * from a range it already handed over.
45
+ */
46
+ readonly settled: number;
47
+ /** How many fingers are down. */
48
+ readonly pointers: number;
49
+ }
50
+ /** Options for {@link usePinch}. */
51
+ interface UsePinchOptions extends GestureMemoOptions {
52
+ /**
53
+ * The scale before any pinch. Default `1`.
54
+ *
55
+ * Read once, at mount. `useSharedValue` keeps its first argument and
56
+ * ignores every later one, and that is the behaviour this option
57
+ * documents: after mount `scale` is the pinch's state, and the consumer
58
+ * moves it by writing it.
59
+ */
60
+ initial?: number;
61
+ /**
62
+ * The smallest scale. Unset by default, which lets the fingers shrink the
63
+ * thing without limit.
64
+ *
65
+ * Set it to `1` for a viewer that may zoom in but never out.
66
+ */
67
+ min?: number;
68
+ /**
69
+ * The largest scale. Unset by default, which lets the fingers grow the
70
+ * thing without limit.
71
+ */
72
+ max?: number;
73
+ /**
74
+ * How much of the travel past `min` or `max` reaches `scale`, from `0` to
75
+ * `1`. Default `0`.
76
+ *
77
+ * `0` stops dead at the end. `1` ignores the end while the fingers are
78
+ * down. Anything between is resistance — the pinch keeps moving and moves
79
+ * less than the fingers do.
80
+ *
81
+ * Impulse does not bring the scale back. The end callback carries
82
+ * `settled` — the scale to animate to — and `@rootnative/inertia` or a
83
+ * `withSpring` of your own does the rest.
84
+ */
85
+ elastic?: number;
86
+ /**
87
+ * Extra touchable area around the view, in points.
88
+ *
89
+ * Written inline as an object is fine — the gesture is not rebuilt when the
90
+ * contents are unchanged.
91
+ */
92
+ hitSlop?: HitSlop;
93
+ /**
94
+ * Whether the gesture is recognized at all. Default `true`.
95
+ *
96
+ * Prefer this over unmounting the `<GestureDetector>`: a disabled gesture
97
+ * keeps its identity and its relations, so re-enabling it does not
98
+ * re-attach anything.
99
+ */
100
+ enabled?: boolean;
101
+ /**
102
+ * The pinch now owns the touch. **Runs on the JS thread** — Impulse owns
103
+ * the `scheduleOnRN` boundary, so this is an ordinary function and may
104
+ * touch React state.
105
+ *
106
+ * This is the first moment the pinch has definitely won. `onBegin` fires
107
+ * earlier and promises nothing.
108
+ */
109
+ onPinchStart?: (event: PinchEvent) => void;
110
+ /**
111
+ * The pinch is over. **Runs on the JS thread.**
112
+ *
113
+ * Fires only for a pinch that activated, so a touch that never became a
114
+ * pinch never reaches here on either path.
115
+ *
116
+ * It fires for both endings, and `cancelled` says which. `false` is the
117
+ * fingers lifting, and `velocity` then describes the release. `true` is the
118
+ * system taking the pinch away — a competing gesture won, or the app went
119
+ * to the background. **There was no release on that path, so the velocity
120
+ * describes the last movement rather than a throw.**
121
+ *
122
+ * Read `settled` on both paths for where an elastic overshoot belongs.
123
+ */
124
+ onPinchEnd?: (event: PinchEvent, info: IntentEndInfo) => void;
125
+ /**
126
+ * A finger went down and the gesture is now a candidate. **This is a
127
+ * worklet** — mark it with the `'worklet'` directive, and do not touch
128
+ * React state from it.
129
+ *
130
+ * Being a candidate is not the same as winning: one finger is not a pinch,
131
+ * and a second one may never arrive. Undo whatever it sets in
132
+ * `onFinalize`.
133
+ */
134
+ onBegin?: (event: PinchEvent) => void;
135
+ /**
136
+ * The scale changed. **This is a worklet**, and it runs on every frame the
137
+ * fingers move.
138
+ *
139
+ * `scale` is already written by the time this runs, so a `useAnimatedStyle`
140
+ * reading it needs nothing from here. Use this for the work that scaling
141
+ * alone does not do — holding the focal point still, say.
142
+ *
143
+ * There is no JS-thread counterpart on purpose. A per-frame `scheduleOnRN`
144
+ * is a scheduling cost paid sixty times a second for a value that is
145
+ * already on the thread that needs it.
146
+ */
147
+ onUpdate?: (event: PinchEvent) => void;
148
+ /**
149
+ * The gesture is over, whether it activated or not. **This is a worklet.**
150
+ *
151
+ * `success` is `true` when the pinch activated and ended normally. This is
152
+ * the right place to clear anything `onBegin` set, because it runs on both
153
+ * paths.
154
+ */
155
+ onFinalize?: (event: PinchEvent, success: boolean) => void;
156
+ }
157
+ /** What {@link usePinch} returns. */
158
+ interface UsePinchResult extends IntentResult<PinchGesture> {
159
+ /**
160
+ * How much the thing is scaled, after `min`, `max` and `elastic`.
161
+ *
162
+ * **This is a position, not a movement.** It accumulates across gestures,
163
+ * so a second pinch continues from where the first stopped. `usePan` is the
164
+ * hook whose value zeroes at every gesture.
165
+ *
166
+ * Writing it is allowed and is how a release animation, or a reset button,
167
+ * hands control back. The next pinch continues from whatever it holds.
168
+ */
169
+ readonly scale: SharedValue<number>;
170
+ /**
171
+ * The midpoint between the fingers, relative to the view.
172
+ *
173
+ * It keeps the last gesture's focal point after the fingers lift, so a
174
+ * release animation scales about the same place the pinch did rather than
175
+ * snapping to the origin.
176
+ */
177
+ readonly focal: SharedValue<Point>;
178
+ }
179
+ /**
180
+ * Recognize a two-finger pinch, and own the scale it produces.
181
+ *
182
+ * ```tsx
183
+ * const pinch = usePinch({ min: 1, max: 4 })
184
+ *
185
+ * const style = useAnimatedStyle(() => ({
186
+ * transform: [{ scale: pinch.scale.value }],
187
+ * }))
188
+ *
189
+ * return (
190
+ * <GestureDetector gesture={pinch.gesture}>
191
+ * <Animated.Image style={style} source={source} />
192
+ * </GestureDetector>
193
+ * )
194
+ * ```
195
+ *
196
+ * **The scale accumulates; RNGH's does not.** A bare `Gesture.Pinch()`
197
+ * reports a factor that restarts at `1` on every gesture, so a viewer built
198
+ * on it snaps back to its original size the moment the fingers lift again.
199
+ * Carrying the scale across gestures is the multiplication and the stored
200
+ * start that every consumer otherwise writes, and it is why `min` and `max`
201
+ * can be the range of the viewer rather than of one gesture.
202
+ *
203
+ * **`focal` is the field a zoom viewer cannot skip.** Scaling about the
204
+ * view's centre slides the content out from under the fingers. The focal
205
+ * point is where the zoom has to happen, and it is reported relative to the
206
+ * view so it can go straight into a `translate` / `scale` / `translate`
207
+ * transform.
208
+ *
209
+ * **Activation criteria.** There are none to set. RNGH's pinch takes the
210
+ * touch as soon as a second finger moves, and it exposes no threshold, so
211
+ * Impulse has none to pass on. This is the one continuous intent whose
212
+ * coexistence is decided entirely by relations — see below.
213
+ *
214
+ * **Coexistence.** A pinch almost always shares its view with a pan, and it
215
+ * has no threshold to separate them with. Say it: `alongside` on both, so the
216
+ * two recognize at once and the same two fingers can move and scale the
217
+ * thing. `useGestures` with `mode: 'simultaneous'` is the same statement for
218
+ * gestures this screen owns.
219
+ *
220
+ * **Web.** RNGH recognizes pinch from pointer events, so it needs two
221
+ * pointers — a touchscreen or a device that reports them. A trackpad's pinch
222
+ * arrives as a `wheel` event with `ctrlKey`, which is not a pointer pair and
223
+ * never reaches this hook, so a desktop browser with a trackpad alone cannot
224
+ * zoom. Give it a control that sets `scale` directly, which the
225
+ * accessibility fallback needs anyway. The browser's own page zoom is
226
+ * unaffected either way.
227
+ *
228
+ * **Accessibility.** A pinch is invisible to a screen reader and unreachable
229
+ * from a keyboard, and this hook does not fix that. Whatever the pinch scales
230
+ * must be reachable another way: zoom-in and zoom-out buttons that write
231
+ * `scale`, a control that resets it, or `accessibilityActions` with
232
+ * `onAccessibilityAction`. A pinch-only zoom is a bug, not a trade-off.
233
+ *
234
+ * @param options - The scale range, callbacks, and the `alongside` /
235
+ * `blocks` / `deferTo` coexistence options every Impulse hook accepts.
236
+ */
237
+ declare function usePinch(options?: UsePinchOptions): UsePinchResult;
238
+
239
+ export { type PinchEvent, type UsePinchOptions, type UsePinchResult, usePinch };
@@ -0,0 +1,4 @@
1
+ export { usePinch } from '../chunk-DXXGWG4Q.js';
2
+ import '../chunk-2UZTAWUQ.js';
3
+ import '../chunk-NYDDZD4G.js';
4
+ import '../chunk-ZX7WNICB.js';
@@ -1,7 +1,7 @@
1
1
  import { DependencyList } from 'react';
2
2
  import { GestureType } from 'react-native-gesture-handler';
3
- import { B as BuiltGesture, G as GestureMemoOptions } from '../useGestureMemo-Ccv8rB0C.js';
4
- import '../types-Ch2HM3aP.js';
3
+ import { B as BuiltGesture, G as GestureMemoOptions } from '../useGestureMemo-BRW1EKcJ.js';
4
+ import '../types-ChGKY28a.js';
5
5
  import 'react-native-reanimated';
6
6
 
7
7
  /** Options for {@link useRawGesture}. */
@@ -35,7 +35,7 @@ type RawGestureResult<G extends GestureType> = BuiltGesture<G>;
35
35
  * put it through `useLatestCallback` and depend on the stable result.
36
36
  * - **The thread.** RNGH decides per callback, by whether it carries the
37
37
  * `'worklet'` directive, and warns in development when a gesture mixes the
38
- * two. Impulse does not insert a `runOnJS` boundary for you here; that is
38
+ * two. Impulse does not insert a `scheduleOnRN` boundary for you here; that is
39
39
  * something the intent hooks do because they know what each callback means.
40
40
  * - **The payload.** You get RNGH's flat event, not an intent-shaped one.
41
41
  *
package/dist/raw/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { useRawGesture } from '../chunk-PMR25UCT.js';
2
- import '../chunk-F4RHM4ZK.js';
1
+ export { useRawGesture } from '../chunk-HGBCIL6X.js';
2
+ import '../chunk-NYDDZD4G.js';
3
3
  import '../chunk-ZX7WNICB.js';