@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.
@@ -335,11 +335,20 @@ const useNativeCanGoBack = () => {
335
335
  };
336
336
 
337
337
  /**
338
- * finger travel that reads as "swipe back recognised". flat px on purpose:
339
- * scaling it by screen width would move the tick to a different physical
340
- * thumb distance on every device
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 SWIPE_BACK_HAPTIC_THRESHOLD = 100;
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 has travelled far enough to read as
375
- * recognised. iOS only, mirroring `gestureEnabled` in getStackOptions.
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 < SWIPE_BACK_HAPTIC_THRESHOLD) {
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.164.1-beta.3",
3
+ "version": "0.164.1-beta.5",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},