@react-hive/honey-utils 3.17.0 → 3.19.0

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.
@@ -1631,75 +1631,50 @@ __webpack_require__.r(__webpack_exports__);
1631
1631
  /* harmony import */ var _geometry__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~/geometry */ "./src/geometry/index.ts");
1632
1632
 
1633
1633
  /**
1634
- * Advances a value by one inertia step using velocity, friction, and hard bounds.
1634
+ * Applies a **single step** of bounded, velocity-based inertia.
1635
1635
  *
1636
- * This utility models **inertial motion** (momentum + decay) on top of
1637
- * {@link resolveBoundedDelta}, which acts as the authoritative constraint layer.
1636
+ * This function models **momentum-driven motion** by:
1637
+ * - integrating velocity over elapsed time
1638
+ * - applying exponential friction
1639
+ * - optionally smoothing velocity using EMA
1640
+ * - enforcing hard bounds via {@link resolveBoundedDelta}
1638
1641
  *
1639
- * The function:
1640
- * - Integrates velocity over the elapsed time to produce a movement delta
1641
- * - Resolves that delta against fixed bounds
1642
- * - Applies exponential friction to gradually reduce velocity
1643
- * - Stops immediately when a bound is hit or velocity falls below a threshold
1642
+ * Boundary handling guarantees:
1643
+ * - no overshoot
1644
+ * - no oscillation at limits
1645
+ * - deterministic stopping behavior
1644
1646
  *
1645
- * ⚠️ This function performs **one step only** and is intended to be called
1646
- * repeatedly from an animation loop (e.g. `requestAnimationFrame`).
1647
+ * ---
1647
1648
  *
1648
- * ### Common use cases
1649
- * - Synthetic scrolling with momentum
1650
- * - Carousels and sliders
1651
- * - Timelines and scrubbers
1652
- * - Drag-to-scroll interactions with inertia
1649
+ * ### Termination conditions
1650
+ * Inertia ends immediately when:
1651
+ * - the absolute velocity falls below `minVelocityPxMs`, or
1652
+ * - movement in the current direction is blocked by a bound
1653
1653
  *
1654
- * @param value - Current value before applying inertia (e.g. translate position).
1655
- * @param min - Minimum allowed value (inclusive).
1656
- * @param max - Maximum allowed value (inclusive).
1657
- * @param velocity - Current velocity in units per millisecond (e.g. px/ms).
1658
- * @param deltaTime - Time elapsed since the previous step, in milliseconds.
1659
- * @param friction - Exponential friction coefficient controlling decay rate.
1660
- * @param minVelocity - Minimum velocity below which inertia stops.
1654
+ * ---
1661
1655
  *
1662
- * @returns An object containing the updated value and velocity,
1663
- * or `null` when inertia has completed or movement is no longer possible.
1656
+ * ⚠️ **Single-step function**
1657
+ * This function advances inertia **once only**.
1658
+ * It must be invoked repeatedly from an animation loop
1659
+ * (e.g. `requestAnimationFrame`) to produce continuous motion.
1664
1660
  *
1665
- * @example
1666
- * ```ts
1667
- * let value = translateX;
1668
- * let velocity = releaseVelocity; // px/ms from drag end
1669
- * let lastTime = performance.now();
1670
- *
1671
- * const step = (time: number) => {
1672
- * const deltaTime = time - lastTime;
1673
- * lastTime = time;
1674
- *
1675
- * const result = applyInertiaStep({
1676
- * value,
1677
- * velocity,
1678
- * min: -maxOverflow,
1679
- * max: 0,
1680
- * deltaTime,
1681
- * });
1661
+ * ---
1682
1662
  *
1683
- * if (!result) {
1684
- * return; // inertia finished
1685
- * }
1686
- *
1687
- * value = result.value;
1688
- * velocity = result.velocity;
1689
- *
1690
- * container.style.transform = `translateX(${value}px)`;
1691
- * requestAnimationFrame(step);
1692
- * };
1663
+ * ### Common use cases
1664
+ * - Synthetic scrolling with momentum
1665
+ * - Drag-to-scroll interactions
1666
+ * - Carousels and sliders
1667
+ * - Timelines and scrubbers
1693
1668
  *
1694
- * requestAnimationFrame(step);
1695
- * ```
1669
+ * @returns An {@link InertiaStepResult} while inertia remains active,
1670
+ * or `null` when inertia has completed or cannot proceed.
1696
1671
  */
1697
- const applyInertiaStep = ({ value, min, max, velocity, deltaTime, friction = 0.002, minVelocity = 0.01, }) => {
1698
- if (Math.abs(velocity) < minVelocity) {
1672
+ const applyInertiaStep = ({ value, min, max, velocityPxMs, deltaTimeMs, friction = 0.002, minVelocityPxMs = 0.01, emaAlpha = 0.2, }) => {
1673
+ if (Math.abs(velocityPxMs) < minVelocityPxMs) {
1699
1674
  return null;
1700
1675
  }
1701
1676
  // Distance we want to move this frame
1702
- const delta = velocity * deltaTime;
1677
+ const delta = velocityPxMs * deltaTimeMs;
1703
1678
  const nextValue = (0,_geometry__WEBPACK_IMPORTED_MODULE_0__.resolveBoundedDelta)({
1704
1679
  delta,
1705
1680
  value,
@@ -1711,11 +1686,15 @@ const applyInertiaStep = ({ value, min, max, velocity, deltaTime, friction = 0.0
1711
1686
  return null;
1712
1687
  }
1713
1688
  // Apply exponential friction
1714
- const decay = Math.exp(-friction * deltaTime);
1715
- const nextVelocity = velocity * decay;
1689
+ const decay = Math.exp(-friction * deltaTimeMs);
1690
+ const pureVelocityPxMs = velocityPxMs * decay;
1691
+ const nextVelocityPxMs = emaAlpha > 0 ? velocityPxMs * (1 - emaAlpha) + pureVelocityPxMs * emaAlpha : pureVelocityPxMs;
1692
+ if (Math.abs(nextVelocityPxMs) < minVelocityPxMs) {
1693
+ return null;
1694
+ }
1716
1695
  return {
1717
1696
  value: nextValue,
1718
- velocity: nextVelocity,
1697
+ velocityPxMs: nextVelocityPxMs,
1719
1698
  };
1720
1699
  };
1721
1700