@momo-kits/foundation 0.164.1-beta.2 → 0.164.1-beta.4
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 +43 -32
- package/package.json +1 -1
package/Application/utils.tsx
CHANGED
|
@@ -374,14 +374,28 @@ const getSwipeGestureValue = (
|
|
|
374
374
|
* one light tick once the swipe back has travelled far enough to read as
|
|
375
375
|
* recognised. iOS only, mirroring `gestureEnabled` in getStackOptions.
|
|
376
376
|
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
377
|
+
* both listeners are installed on mount and never lazily inside the gesture:
|
|
378
|
+
* on the New Architecture `addListener` queues `startListeningToAnimatedNodeValue`
|
|
379
|
+
* via `queueOperationBlock`, and that queue is only drained by a React mount
|
|
380
|
+
* commit — which never happens during a native driven pan. subscribing when the
|
|
381
|
+
* swipe starts installs an observer that the release flush tears down again
|
|
382
|
+
* before a single frame is delivered, so it must stay on mount.
|
|
383
|
+
*
|
|
384
|
+
* `gesture` also drives the programmatic push and pop animations, so it is the
|
|
385
|
+
* JS `isSwiping` flag, not the subscription lifetime, that keeps the tick
|
|
386
|
+
* exclusive to a real finger drag.
|
|
380
387
|
*/
|
|
381
388
|
const useSwipeBackHaptic = () => {
|
|
382
389
|
const { navigator } = useContext<any>(ApplicationContext);
|
|
383
390
|
const animation = useContext(CardAnimationContext);
|
|
384
391
|
|
|
392
|
+
/**
|
|
393
|
+
* the latch has to outlive the effect. `animation` identity changes on every
|
|
394
|
+
* navigator render, so a `hasFired` local re-arms several times per drag and
|
|
395
|
+
* the tick then repeats on every frame past the threshold
|
|
396
|
+
*/
|
|
397
|
+
const hasFired = useRef(false);
|
|
398
|
+
|
|
385
399
|
useEffect(() => {
|
|
386
400
|
if (Platform.OS !== 'ios' || !animation) {
|
|
387
401
|
return;
|
|
@@ -393,47 +407,44 @@ const useSwipeBackHaptic = () => {
|
|
|
393
407
|
return;
|
|
394
408
|
}
|
|
395
409
|
|
|
396
|
-
|
|
397
|
-
|
|
410
|
+
/**
|
|
411
|
+
* `animation` identity is not stable, so this effect can re-run mid swipe.
|
|
412
|
+
* seed from the live value instead of waiting for a 0 -> 1 transition that
|
|
413
|
+
* has already been missed
|
|
414
|
+
*/
|
|
415
|
+
let isSwiping = readAnimatedValue(swiping, 0) === 1;
|
|
398
416
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
hasFired = false;
|
|
405
|
-
};
|
|
417
|
+
/**
|
|
418
|
+
* sign, not magnitude: a leftward overdrag reports a negative
|
|
419
|
+
* translation and must not count as progress toward dismissal
|
|
420
|
+
*/
|
|
421
|
+
const direction = readAnimatedValue(inverted, 1);
|
|
406
422
|
|
|
407
423
|
const swipingListener = swiping.addListener(({ value }) => {
|
|
408
|
-
|
|
409
|
-
|
|
424
|
+
isSwiping = value === 1;
|
|
425
|
+
if (!isSwiping) {
|
|
426
|
+
hasFired.current = false;
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const gestureListener = gesture.addListener(({ value: translation }) => {
|
|
431
|
+
if (!isSwiping) {
|
|
410
432
|
return;
|
|
411
433
|
}
|
|
412
434
|
|
|
413
|
-
if (
|
|
435
|
+
if (translation * direction < SWIPE_BACK_HAPTIC_THRESHOLD) {
|
|
436
|
+
hasFired.current = false;
|
|
414
437
|
return;
|
|
415
438
|
}
|
|
416
439
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const direction = readAnimatedValue(inverted, 1);
|
|
422
|
-
gestureListener = gesture.addListener(({ value: translation }) => {
|
|
423
|
-
if (translation * direction < SWIPE_BACK_HAPTIC_THRESHOLD) {
|
|
424
|
-
hasFired = false;
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (!hasFired) {
|
|
429
|
-
hasFired = true;
|
|
430
|
-
navigator?.maxApi?.triggerEventVibration?.('light');
|
|
431
|
-
}
|
|
432
|
-
});
|
|
440
|
+
if (!hasFired.current) {
|
|
441
|
+
hasFired.current = true;
|
|
442
|
+
navigator?.maxApi?.triggerEventVibration?.('light');
|
|
443
|
+
}
|
|
433
444
|
});
|
|
434
445
|
|
|
435
446
|
return () => {
|
|
436
|
-
|
|
447
|
+
gesture.removeListener(gestureListener);
|
|
437
448
|
swiping.removeListener(swipingListener);
|
|
438
449
|
};
|
|
439
450
|
}, [animation, navigator]);
|