@momo-kits/foundation 0.164.1-beta.3 → 0.164.1-beta.5
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/Application/utils.tsx +37 -14
- package/package.json +1 -1
package/Application/utils.tsx
CHANGED
|
@@ -335,11 +335,20 @@ const useNativeCanGoBack = () => {
|
|
|
335
335
|
};
|
|
336
336
|
|
|
337
337
|
/**
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
338
|
+
* fraction of screen width at which releasing commits the pop. deliberately
|
|
339
|
+
* pinned to react-navigation's own rule: Card.tsx (GestureState.END,
|
|
340
|
+
* @react-navigation/stack 7.4.2) closes the card when
|
|
341
|
+
* `(translation + velocity * gestureVelocityImpact) * inverted > distance / 2`
|
|
342
|
+
* with `distance = layout.width` for a horizontal gesture, and exposes no
|
|
343
|
+
* option to override it. so the tick means "release now and you go back"
|
|
344
|
+
* instead of marking a distance of its own — keep the two in sync.
|
|
345
|
+
*
|
|
346
|
+
* mid drag only translation is known, velocity exists solely at release, so a
|
|
347
|
+
* short fast flick can commit without ever crossing this and pops with no
|
|
348
|
+
* tick. that asymmetry is intended: modelling velocity per frame would tick
|
|
349
|
+
* on swipes that then do not commit, which is the worse error
|
|
341
350
|
*/
|
|
342
|
-
const
|
|
351
|
+
const SWIPE_BACK_HAPTIC_COMMIT_RATIO = 0.5;
|
|
343
352
|
|
|
344
353
|
const readAnimatedValue = (node: unknown, fallback: number): number => {
|
|
345
354
|
const getValue = (node as { __getValue?: () => unknown } | undefined)
|
|
@@ -371,8 +380,8 @@ const getSwipeGestureValue = (
|
|
|
371
380
|
};
|
|
372
381
|
|
|
373
382
|
/**
|
|
374
|
-
* one light tick once the swipe back
|
|
375
|
-
*
|
|
383
|
+
* one light tick once the swipe back passes the point where releasing commits
|
|
384
|
+
* the pop. iOS only, mirroring `gestureEnabled` in getStackOptions.
|
|
376
385
|
*
|
|
377
386
|
* both listeners are installed on mount and never lazily inside the gesture:
|
|
378
387
|
* on the New Architecture `addListener` queues `startListeningToAnimatedNodeValue`
|
|
@@ -389,12 +398,19 @@ const useSwipeBackHaptic = () => {
|
|
|
389
398
|
const { navigator } = useContext<any>(ApplicationContext);
|
|
390
399
|
const animation = useContext(CardAnimationContext);
|
|
391
400
|
|
|
401
|
+
/**
|
|
402
|
+
* the latch has to outlive the effect. `animation` identity changes on every
|
|
403
|
+
* navigator render, so a `hasFired` local re-arms several times per drag and
|
|
404
|
+
* the tick then repeats on every frame past the threshold
|
|
405
|
+
*/
|
|
406
|
+
const hasFired = useRef(false);
|
|
407
|
+
|
|
392
408
|
useEffect(() => {
|
|
393
409
|
if (Platform.OS !== 'ios' || !animation) {
|
|
394
410
|
return;
|
|
395
411
|
}
|
|
396
412
|
|
|
397
|
-
const { swiping, inverted, current } = animation;
|
|
413
|
+
const { swiping, inverted, current, layouts } = animation;
|
|
398
414
|
const gesture = getSwipeGestureValue(current?.progress);
|
|
399
415
|
if (!gesture || typeof swiping?.addListener !== 'function') {
|
|
400
416
|
return;
|
|
@@ -406,7 +422,6 @@ const useSwipeBackHaptic = () => {
|
|
|
406
422
|
* has already been missed
|
|
407
423
|
*/
|
|
408
424
|
let isSwiping = readAnimatedValue(swiping, 0) === 1;
|
|
409
|
-
let hasFired = false;
|
|
410
425
|
|
|
411
426
|
/**
|
|
412
427
|
* sign, not magnitude: a leftward overdrag reports a negative
|
|
@@ -414,25 +429,33 @@ const useSwipeBackHaptic = () => {
|
|
|
414
429
|
*/
|
|
415
430
|
const direction = readAnimatedValue(inverted, 1);
|
|
416
431
|
|
|
432
|
+
/**
|
|
433
|
+
* plain JS numbers, not animated nodes (`StackCardInterpolationProps`).
|
|
434
|
+
* screen layout can still be unmeasured on an early render, and a zero
|
|
435
|
+
* width would put the threshold at 0 and tick the moment the finger moves
|
|
436
|
+
*/
|
|
437
|
+
const commitThreshold =
|
|
438
|
+
(layouts?.screen?.width ?? 0) * SWIPE_BACK_HAPTIC_COMMIT_RATIO;
|
|
439
|
+
|
|
417
440
|
const swipingListener = swiping.addListener(({ value }) => {
|
|
418
441
|
isSwiping = value === 1;
|
|
419
442
|
if (!isSwiping) {
|
|
420
|
-
hasFired = false;
|
|
443
|
+
hasFired.current = false;
|
|
421
444
|
}
|
|
422
445
|
});
|
|
423
446
|
|
|
424
447
|
const gestureListener = gesture.addListener(({ value: translation }) => {
|
|
425
|
-
if (!isSwiping) {
|
|
448
|
+
if (!isSwiping || commitThreshold <= 0) {
|
|
426
449
|
return;
|
|
427
450
|
}
|
|
428
451
|
|
|
429
|
-
if (translation * direction <
|
|
430
|
-
hasFired = false;
|
|
452
|
+
if (translation * direction < commitThreshold) {
|
|
453
|
+
hasFired.current = false;
|
|
431
454
|
return;
|
|
432
455
|
}
|
|
433
456
|
|
|
434
|
-
if (!hasFired) {
|
|
435
|
-
hasFired = true;
|
|
457
|
+
if (!hasFired.current) {
|
|
458
|
+
hasFired.current = true;
|
|
436
459
|
navigator?.maxApi?.triggerEventVibration?.('light');
|
|
437
460
|
}
|
|
438
461
|
});
|