@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,391 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Gesture,
|
|
4
|
+
type GestureStateChangeEvent,
|
|
5
|
+
type LongPressGesture,
|
|
6
|
+
type LongPressGestureHandlerEventPayload,
|
|
7
|
+
} from 'react-native-gesture-handler'
|
|
8
|
+
import { useSharedValue } from 'react-native-reanimated'
|
|
9
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
10
|
+
import {
|
|
11
|
+
useGestureMemo,
|
|
12
|
+
type GestureMemoOptions,
|
|
13
|
+
} from '../internal/useGestureMemo'
|
|
14
|
+
import { buildIntentResult } from '../internal/intentResult'
|
|
15
|
+
import { useLatestCallback } from '../internal/useLatestCallback'
|
|
16
|
+
import { useStableRecord } from '../internal/useStableRecord'
|
|
17
|
+
import {
|
|
18
|
+
type HitSlop,
|
|
19
|
+
type IntentEndInfo,
|
|
20
|
+
type IntentResult,
|
|
21
|
+
type Point,
|
|
22
|
+
} from '../types'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* How long the finger must stay down before the press is recognized, in
|
|
26
|
+
* milliseconds.
|
|
27
|
+
*
|
|
28
|
+
* RNGH's own default, restated rather than inherited so the value is visible
|
|
29
|
+
* at the call site's documentation and cannot move underneath Impulse in an
|
|
30
|
+
* RNGH release.
|
|
31
|
+
*/
|
|
32
|
+
const DEFAULT_MIN_DURATION = 500
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* How far the finger may travel while waiting, in points.
|
|
36
|
+
*
|
|
37
|
+
* This one **is** RNGH's own default — unlike `useTap`'s `maxDistance`, where
|
|
38
|
+
* RNGH defers to the platform and Impulse had to choose a number. Restated
|
|
39
|
+
* for the same reason as `minDuration`.
|
|
40
|
+
*/
|
|
41
|
+
const DEFAULT_MAX_DISTANCE = 10
|
|
42
|
+
|
|
43
|
+
/** The intent-shaped payload a {@link useLongPress} callback receives. */
|
|
44
|
+
export interface LongPressEvent {
|
|
45
|
+
/** X of the press, in points, relative to the view the gesture is attached to. */
|
|
46
|
+
readonly x: number
|
|
47
|
+
/** Y of the press, in points, relative to the view the gesture is attached to. */
|
|
48
|
+
readonly y: number
|
|
49
|
+
/**
|
|
50
|
+
* The same point relative to the window.
|
|
51
|
+
*
|
|
52
|
+
* Prefer it over `x` / `y` when the view itself is being transformed by the
|
|
53
|
+
* gesture — a press on a view that is mid-animation reports a moving `x`.
|
|
54
|
+
*/
|
|
55
|
+
readonly absolute: Point
|
|
56
|
+
/**
|
|
57
|
+
* How long the finger has been down, in milliseconds.
|
|
58
|
+
*
|
|
59
|
+
* At `onLongPress` this is roughly `minDuration`, because that is the
|
|
60
|
+
* moment the press was recognized. At `onLongPressEnd` it is the whole hold
|
|
61
|
+
* — which is the number a hold-to-record affordance wants, and the reason
|
|
62
|
+
* this field is in the payload rather than derived by the consumer from two
|
|
63
|
+
* timestamps.
|
|
64
|
+
*/
|
|
65
|
+
readonly duration: number
|
|
66
|
+
/** How many fingers are down. */
|
|
67
|
+
readonly pointers: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Options for {@link useLongPress}. */
|
|
71
|
+
export interface UseLongPressOptions extends GestureMemoOptions {
|
|
72
|
+
/**
|
|
73
|
+
* How long the finger must stay down before the press is recognized, in
|
|
74
|
+
* milliseconds. Default `500`.
|
|
75
|
+
*
|
|
76
|
+
* Lower it for an affordance the user is expected to discover; raise it for
|
|
77
|
+
* one that must not fire by accident. Below roughly 200ms it stops being
|
|
78
|
+
* distinguishable from a tap that was held a moment too long.
|
|
79
|
+
*/
|
|
80
|
+
minDuration?: number
|
|
81
|
+
/**
|
|
82
|
+
* How far the finger may travel, in points. Default `10`.
|
|
83
|
+
*
|
|
84
|
+
* **What this bounds is platform-dependent, and the split is verified.**
|
|
85
|
+
* RNGH documents it as bounding the wait only: "if the finger travels
|
|
86
|
+
* further than the defined distance and the handler hasn't yet activated,
|
|
87
|
+
* it will fail". Its web implementation does not match that — it checks the
|
|
88
|
+
* distance on every pointer move and *cancels* a press that is already
|
|
89
|
+
* active.
|
|
90
|
+
*
|
|
91
|
+
* So on web the finger may not travel past this once the press is
|
|
92
|
+
* recognized, and hold-then-drag needs this raised explicitly rather than
|
|
93
|
+
* relying on the documented behaviour. Native is unverified.
|
|
94
|
+
*/
|
|
95
|
+
maxDistance?: number
|
|
96
|
+
/**
|
|
97
|
+
* Exactly how many fingers must be down. Unset by default, which leaves
|
|
98
|
+
* RNGH's own behaviour in place.
|
|
99
|
+
*
|
|
100
|
+
* Setting it fixes the count exactly rather than setting a minimum.
|
|
101
|
+
*/
|
|
102
|
+
pointers?: number
|
|
103
|
+
/**
|
|
104
|
+
* Extra touchable area around the view, in points.
|
|
105
|
+
*
|
|
106
|
+
* Written inline as an object is fine — the gesture is not rebuilt when the
|
|
107
|
+
* contents are unchanged.
|
|
108
|
+
*/
|
|
109
|
+
hitSlop?: HitSlop
|
|
110
|
+
/**
|
|
111
|
+
* Whether the gesture is recognized at all. Default `true`.
|
|
112
|
+
*
|
|
113
|
+
* Prefer this over unmounting the `<GestureDetector>`: a disabled gesture
|
|
114
|
+
* keeps its identity and its relations, so re-enabling it does not
|
|
115
|
+
* re-attach anything.
|
|
116
|
+
*/
|
|
117
|
+
enabled?: boolean
|
|
118
|
+
/**
|
|
119
|
+
* The press was held long enough and is now recognized. **Runs on the JS
|
|
120
|
+
* thread** — Impulse owns the `scheduleOnRN` boundary, so this is an ordinary
|
|
121
|
+
* function and may touch React state.
|
|
122
|
+
*
|
|
123
|
+
* **The finger is still down when this fires.** That is the point: a
|
|
124
|
+
* context menu opens under a finger that has not lifted, which is what
|
|
125
|
+
* makes a long press feel like a long press rather than like a slow tap.
|
|
126
|
+
* Fire the haptic here.
|
|
127
|
+
*/
|
|
128
|
+
onLongPress?: (event: LongPressEvent) => void
|
|
129
|
+
/**
|
|
130
|
+
* A recognized press ended. **Runs on the JS thread.**
|
|
131
|
+
*
|
|
132
|
+
* Always preceded by `onLongPress`, because a touch that never became a
|
|
133
|
+
* long press never reaches here on either path.
|
|
134
|
+
*
|
|
135
|
+
* It fires for both endings, and `cancelled` says which. `false` is the
|
|
136
|
+
* finger lifting. `true` is the system taking the press away — a competing
|
|
137
|
+
* gesture won, the app went to the background, or the finger moved past
|
|
138
|
+
* `maxDistance` while still down. Read it before you treat the press as
|
|
139
|
+
* completed: a hold-to-record affordance stops the recording on both paths
|
|
140
|
+
* but keeps the take only on the first.
|
|
141
|
+
*
|
|
142
|
+
* `duration` carries the whole hold, which is what that affordance stops
|
|
143
|
+
* on.
|
|
144
|
+
*/
|
|
145
|
+
onLongPressEnd?: (event: LongPressEvent, info: IntentEndInfo) => void
|
|
146
|
+
/**
|
|
147
|
+
* The finger went down and the gesture is now a candidate. **This is a
|
|
148
|
+
* worklet** — mark it with the `'worklet'` directive, and do not touch
|
|
149
|
+
* React state from it.
|
|
150
|
+
*
|
|
151
|
+
* It fires on every touch, including the ordinary taps that will never
|
|
152
|
+
* become a long press. Use it to show a candidate state, and undo that
|
|
153
|
+
* state in `onFinalize`.
|
|
154
|
+
*/
|
|
155
|
+
onBegin?: (event: LongPressEvent) => void
|
|
156
|
+
/**
|
|
157
|
+
* The gesture is over, whether it was recognized or not. **This is a
|
|
158
|
+
* worklet.**
|
|
159
|
+
*
|
|
160
|
+
* `success` is `true` when the press was recognized and ended normally.
|
|
161
|
+
* This is the right place to clear anything `onBegin` set, because it runs
|
|
162
|
+
* on both paths.
|
|
163
|
+
*/
|
|
164
|
+
onFinalize?: (event: LongPressEvent, success: boolean) => void
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* What {@link useLongPress} returns.
|
|
169
|
+
*
|
|
170
|
+
* An alias rather than an extending interface, because a long press produces
|
|
171
|
+
* no continuous value of its own — the duration is in the payload, not in a
|
|
172
|
+
* shared value, because nothing on the UI thread can read a clock per frame
|
|
173
|
+
* without Impulse starting an animation to drive it.
|
|
174
|
+
*/
|
|
175
|
+
export type UseLongPressResult = IntentResult<LongPressGesture>
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Shape RNGH's flat state-change event into the long-press payload.
|
|
179
|
+
*
|
|
180
|
+
* A worklet, because every caller is one. Keeping the normalizer out of the
|
|
181
|
+
* gesture callbacks means the four call sites cannot disagree about which
|
|
182
|
+
* RNGH field means what — which is the defect the intent payload exists to
|
|
183
|
+
* remove.
|
|
184
|
+
*/
|
|
185
|
+
function toLongPressEvent(
|
|
186
|
+
event: GestureStateChangeEvent<LongPressGestureHandlerEventPayload>,
|
|
187
|
+
): LongPressEvent {
|
|
188
|
+
'worklet'
|
|
189
|
+
return {
|
|
190
|
+
x: event.x,
|
|
191
|
+
y: event.y,
|
|
192
|
+
absolute: { x: event.absoluteX, y: event.absoluteY },
|
|
193
|
+
duration: event.duration,
|
|
194
|
+
pointers: event.numberOfPointers,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Recognize a press held past a duration.
|
|
200
|
+
*
|
|
201
|
+
* ```tsx
|
|
202
|
+
* const hold = useLongPress({ minDuration: 400, onLongPress: openMenu })
|
|
203
|
+
*
|
|
204
|
+
* return (
|
|
205
|
+
* <GestureDetector gesture={hold.gesture}>
|
|
206
|
+
* <View />
|
|
207
|
+
* </GestureDetector>
|
|
208
|
+
* )
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* `onLongPress` runs on the JS thread and may set React state directly, and
|
|
212
|
+
* it fires **while the finger is still down** — that is the moment a context
|
|
213
|
+
* menu should open and a haptic should fire. `onLongPressEnd` runs on the JS
|
|
214
|
+
* thread too, when the finger lifts. `onBegin` and `onFinalize` are worklets
|
|
215
|
+
* and run on the UI thread — the name states the thread, so there is nothing
|
|
216
|
+
* to configure and no `scheduleOnRN` to write.
|
|
217
|
+
*
|
|
218
|
+
* `isActive` is a shared value that is `true` from the moment the press is
|
|
219
|
+
* recognized until the finger lifts — **not** from the moment the finger goes
|
|
220
|
+
* down. It is the held state, not a pressed state: every ordinary tap on the
|
|
221
|
+
* view would set a finger-down flag, and almost none of them are this
|
|
222
|
+
* gesture. Drive a pressed state from a `useTap` instead, and use this for
|
|
223
|
+
* whatever should show only while the press is genuinely being held.
|
|
224
|
+
*
|
|
225
|
+
* **Pairing with a tap.** A tap and a long press on one view race, and the
|
|
226
|
+
* race resolves itself: a tap that is held too long fails, and a press
|
|
227
|
+
* released too early never activates.
|
|
228
|
+
*
|
|
229
|
+
* ```tsx
|
|
230
|
+
* useGestures([useLongPress({ onLongPress: openMenu }), tap], { mode: 'race' })
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* **Hold, then drag.** RNGH has no "activate after this one activates"
|
|
234
|
+
* relation, so this is two gestures and a gate rather than one option. Run
|
|
235
|
+
* them `alongside` each other and let the drag read a flag the press sets:
|
|
236
|
+
*
|
|
237
|
+
* ```tsx
|
|
238
|
+
* const hold = useLongPress({ alongside: dragRef })
|
|
239
|
+
* const drag = useDrag({
|
|
240
|
+
* alongside: hold.ref,
|
|
241
|
+
* onUpdate: () => {
|
|
242
|
+
* 'worklet'
|
|
243
|
+
* // ignore the movement until the press has been held
|
|
244
|
+
* },
|
|
245
|
+
* })
|
|
246
|
+
* ```
|
|
247
|
+
*
|
|
248
|
+
* `hold.isActive` is the flag, and it is a shared value precisely so the
|
|
249
|
+
* drag's worklets can read it without a round trip to the JS thread. Raise
|
|
250
|
+
* the drag's `threshold` as well, or the drag activates before the press ever
|
|
251
|
+
* does — and raise this hook's `maxDistance`, or the press is cancelled by
|
|
252
|
+
* the drag's own movement on web.
|
|
253
|
+
*
|
|
254
|
+
* **Activation criteria.** `minDuration` defaults to 500ms and `maxDistance`
|
|
255
|
+
* to 10 points, and both are RNGH's own numbers restated. What `maxDistance`
|
|
256
|
+
* bounds differs by platform: RNGH documents it as bounding the wait only,
|
|
257
|
+
* but its web implementation cancels a press that is already active once the
|
|
258
|
+
* finger travels past it. Raise it explicitly rather than relying on travel
|
|
259
|
+
* being free after recognition.
|
|
260
|
+
*
|
|
261
|
+
* **Web.** RNGH recognizes long press from pointer events, so a held mouse
|
|
262
|
+
* button works. The browser's own context menu is not suppressed by this
|
|
263
|
+
* hook, so a long press with the right button — or a held touch on some
|
|
264
|
+
* browsers — can open both. Suppress it on the view if that matters.
|
|
265
|
+
*
|
|
266
|
+
* **Accessibility.** A long press is invisible to a screen reader and
|
|
267
|
+
* unreachable from a keyboard, and this hook does not fix that. It has the
|
|
268
|
+
* best fallback of any gesture in the library, so use it: React Native's
|
|
269
|
+
* `<Pressable>` takes `onLongPress` directly and is reachable by every
|
|
270
|
+
* assistive technology, and `accessibilityActions` with
|
|
271
|
+
* `onAccessibilityAction` names the same action explicitly. A long-press-only
|
|
272
|
+
* affordance is a bug, not a trade-off.
|
|
273
|
+
*
|
|
274
|
+
* @param options - Activation criteria, callbacks, and the `alongside` /
|
|
275
|
+
* `blocks` / `deferTo` coexistence options every Impulse hook accepts.
|
|
276
|
+
*/
|
|
277
|
+
export function useLongPress(
|
|
278
|
+
options: UseLongPressOptions = {},
|
|
279
|
+
): UseLongPressResult {
|
|
280
|
+
const {
|
|
281
|
+
minDuration = DEFAULT_MIN_DURATION,
|
|
282
|
+
maxDistance = DEFAULT_MAX_DISTANCE,
|
|
283
|
+
pointers,
|
|
284
|
+
enabled,
|
|
285
|
+
onLongPress,
|
|
286
|
+
onLongPressEnd,
|
|
287
|
+
onBegin,
|
|
288
|
+
onFinalize,
|
|
289
|
+
} = options
|
|
290
|
+
|
|
291
|
+
const isActive = useSharedValue(false)
|
|
292
|
+
// `hitSlop` is the one option a consumer writes as an object literal, so it
|
|
293
|
+
// is the one that would rebuild the gesture every render if taken as-is.
|
|
294
|
+
const hitSlop = useStableRecord(options.hitSlop)
|
|
295
|
+
// JS-thread callbacks reach the gesture through stable identities, so they
|
|
296
|
+
// are never gesture dependencies. The worklet callbacks stay direct
|
|
297
|
+
// dependencies, because a worklet is captured as written.
|
|
298
|
+
const handleLongPress = useLatestCallback(onLongPress)
|
|
299
|
+
const handleLongPressEnd = useLatestCallback(onLongPressEnd)
|
|
300
|
+
// Attaching a handler is not the same as calling it: RNGH decides which
|
|
301
|
+
// thread a gesture's callbacks run on by inspecting the ones it was given,
|
|
302
|
+
// so the gesture does have to change when a handler appears or disappears.
|
|
303
|
+
// Booleans, so they change only when that is actually true.
|
|
304
|
+
const hasLongPress = onLongPress !== undefined
|
|
305
|
+
const hasLongPressEnd = onLongPressEnd !== undefined
|
|
306
|
+
|
|
307
|
+
const built = useGestureMemo(
|
|
308
|
+
'useLongPress',
|
|
309
|
+
() => {
|
|
310
|
+
const press = Gesture.LongPress()
|
|
311
|
+
.minDuration(minDuration)
|
|
312
|
+
.maxDistance(maxDistance)
|
|
313
|
+
.onBegin((event) => {
|
|
314
|
+
'worklet'
|
|
315
|
+
onBegin?.(toLongPressEvent(event))
|
|
316
|
+
})
|
|
317
|
+
.onStart((event) => {
|
|
318
|
+
'worklet'
|
|
319
|
+
// Recognition, not touch-down: the press has now been held past
|
|
320
|
+
// `minDuration` and the finger is still on the view. `isActive`
|
|
321
|
+
// tracks that held state rather than the candidate state, which is
|
|
322
|
+
// what makes it worth reading at all.
|
|
323
|
+
isActive.value = true
|
|
324
|
+
if (hasLongPress) {
|
|
325
|
+
scheduleOnRN(handleLongPress, toLongPressEvent(event))
|
|
326
|
+
}
|
|
327
|
+
})
|
|
328
|
+
.onEnd((event, success) => {
|
|
329
|
+
'worklet'
|
|
330
|
+
// Not guarded on `success`: RNGH calls this for a cancelled press
|
|
331
|
+
// too, and `cancelled` is what separates the two. The guard used to
|
|
332
|
+
// be here, which left the cancel reportable only from `onFinalize`
|
|
333
|
+
// — a worklet — so a consumer holding phase in React state had to
|
|
334
|
+
// cross the thread boundary by hand.
|
|
335
|
+
//
|
|
336
|
+
// Reporting the cancel is safe because RNGH calls `onEnd` only when
|
|
337
|
+
// the old state was ACTIVE. A touch that never became a long press
|
|
338
|
+
// reaches `onFinalize` and never gets here, so this never announces
|
|
339
|
+
// the end of a press that never started.
|
|
340
|
+
if (hasLongPressEnd) {
|
|
341
|
+
scheduleOnRN(handleLongPressEnd, toLongPressEvent(event), {
|
|
342
|
+
cancelled: !success,
|
|
343
|
+
})
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
.onFinalize((event, success) => {
|
|
347
|
+
'worklet'
|
|
348
|
+
isActive.value = false
|
|
349
|
+
onFinalize?.(toLongPressEvent(event), success)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
// Applied conditionally rather than with a default, so an option the
|
|
353
|
+
// consumer did not set leaves RNGH's own default in place instead of
|
|
354
|
+
// Impulse overwriting it with a guess.
|
|
355
|
+
if (pointers !== undefined) {
|
|
356
|
+
press.numberOfPointers(pointers)
|
|
357
|
+
}
|
|
358
|
+
if (hitSlop !== undefined) {
|
|
359
|
+
press.hitSlop(hitSlop)
|
|
360
|
+
}
|
|
361
|
+
if (enabled !== undefined) {
|
|
362
|
+
press.enabled(enabled)
|
|
363
|
+
}
|
|
364
|
+
return press
|
|
365
|
+
},
|
|
366
|
+
[
|
|
367
|
+
minDuration,
|
|
368
|
+
maxDistance,
|
|
369
|
+
pointers,
|
|
370
|
+
hitSlop,
|
|
371
|
+
enabled,
|
|
372
|
+
hasLongPress,
|
|
373
|
+
hasLongPressEnd,
|
|
374
|
+
handleLongPress,
|
|
375
|
+
handleLongPressEnd,
|
|
376
|
+
isActive,
|
|
377
|
+
onBegin,
|
|
378
|
+
onFinalize,
|
|
379
|
+
],
|
|
380
|
+
options,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
// Memoised for the same reason `useGestureMemo` memoises its own result: a
|
|
384
|
+
// consumer may put the whole hook result in a dependency list, and a fresh
|
|
385
|
+
// object every render would make that dependency useless. `isActive` is
|
|
386
|
+
// stable for the life of the hook, so `built` is the only real input.
|
|
387
|
+
return useMemo(
|
|
388
|
+
() => buildIntentResult(built, { isActive }),
|
|
389
|
+
[built, isActive],
|
|
390
|
+
)
|
|
391
|
+
}
|