@react-hive/honey-layout 10.6.0 → 10.8.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.
@@ -13730,6 +13730,7 @@ __webpack_require__.r(__webpack_exports__);
13730
13730
  /* harmony export */ useHoneySyntheticScroll: () => (/* reexport safe */ _use_honey_synthetic_scroll__WEBPACK_IMPORTED_MODULE_8__.useHoneySyntheticScroll),
13731
13731
  /* harmony export */ useHoneySyntheticScrollX: () => (/* reexport safe */ _use_honey_synthetic_scroll_x__WEBPACK_IMPORTED_MODULE_9__.useHoneySyntheticScrollX),
13732
13732
  /* harmony export */ useHoneySyntheticScrollY: () => (/* reexport safe */ _use_honey_synthetic_scroll_y__WEBPACK_IMPORTED_MODULE_10__.useHoneySyntheticScrollY),
13733
+ /* harmony export */ useHoneyTimer: () => (/* reexport safe */ _use_honey_timer__WEBPACK_IMPORTED_MODULE_12__.useHoneyTimer),
13733
13734
  /* harmony export */ useRegisterHoneyOverlay: () => (/* reexport safe */ _use_register_honey_overlay__WEBPACK_IMPORTED_MODULE_5__.useRegisterHoneyOverlay)
13734
13735
  /* harmony export */ });
13735
13736
  /* harmony import */ var _use_honey_on_change__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./use-honey-on-change */ "./src/hooks/use-honey-on-change.ts");
@@ -13744,6 +13745,8 @@ __webpack_require__.r(__webpack_exports__);
13744
13745
  /* harmony import */ var _use_honey_synthetic_scroll_x__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./use-honey-synthetic-scroll-x */ "./src/hooks/use-honey-synthetic-scroll-x.ts");
13745
13746
  /* harmony import */ var _use_honey_synthetic_scroll_y__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./use-honey-synthetic-scroll-y */ "./src/hooks/use-honey-synthetic-scroll-y.ts");
13746
13747
  /* harmony import */ var _use_honey_raf_loop__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./use-honey-raf-loop */ "./src/hooks/use-honey-raf-loop.ts");
13748
+ /* harmony import */ var _use_honey_timer__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./use-honey-timer */ "./src/hooks/use-honey-timer.ts");
13749
+
13747
13750
 
13748
13751
 
13749
13752
 
@@ -14191,7 +14194,7 @@ __webpack_require__.r(__webpack_exports__);
14191
14194
  *
14192
14195
  * Features:
14193
14196
  * - Explicit RAF lifecycle control (`start` / `stop`)
14194
- * - Delta time (`dt`) calculation with frame clamping
14197
+ * - Delta time calculation with frame clamping
14195
14198
  * - Automatic cleanup on unmounting
14196
14199
  * - Conservative handling of tab visibility changes (mobile-safe)
14197
14200
  * - Safe error handling (stops loop on exception)
@@ -14203,7 +14206,7 @@ __webpack_require__.r(__webpack_exports__);
14203
14206
  * This hook is designed for gesture handling, inertia, physics simulations,
14204
14207
  * and animation loops that must not trigger React re-renders on every frame.
14205
14208
  *
14206
- * @param callback - Function invoked on each animation frame.
14209
+ * @param onFrame - Function invoked on each animation frame.
14207
14210
  * @param options - Optional configuration for the RAF loop.
14208
14211
  *
14209
14212
  * @returns Control helpers and RAF loop state.
@@ -14215,7 +14218,7 @@ __webpack_require__.r(__webpack_exports__);
14215
14218
  *
14216
14219
  * const velocityRef = useRef({ x: 12, y: 4 });
14217
14220
  *
14218
- * const onFrame = useCallback<HoneyRafCallback>(
14221
+ * const onFrame = useCallback<HoneyRafOnFrameHandler>(
14219
14222
  * (dtMs, { stop }) => {
14220
14223
  * velocityRef.current.x *= 0.94;
14221
14224
  * velocityRef.current.y *= 0.94;
@@ -14238,77 +14241,77 @@ __webpack_require__.r(__webpack_exports__);
14238
14241
  * useHoneyRafLoop(onFrame);
14239
14242
  * ```
14240
14243
  */
14241
- const useHoneyRafLoop = (callback, { autoStart = false, resumeOnVisibility = false, maxDeltaMs = 32, // ~30fps clamp
14244
+ const useHoneyRafLoop = (onFrame, { autoStart = false, resumeOnVisibility = false, maxDeltaMs = 32, // ~30fps clamp
14242
14245
  onError, } = {}) => {
14243
14246
  const rafIdRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
14244
- const lastTimeRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
14245
- const callbackRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(callback);
14247
+ const lastTimeMsRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
14248
+ const onFrameRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(onFrame);
14246
14249
  // Always keep the latest callback without restarting RAF
14247
- callbackRef.current = callback;
14248
- const [isRafLoopRunning, setIsRafLoopRunning] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
14249
- const loop = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(time => {
14250
- if (lastTimeRef.current === null) {
14251
- lastTimeRef.current = time;
14250
+ onFrameRef.current = onFrame;
14251
+ const [isRunning, setIsRunning] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
14252
+ const loop = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(timeMs => {
14253
+ if (lastTimeMsRef.current === null) {
14254
+ lastTimeMsRef.current = timeMs;
14252
14255
  }
14253
- let dt = time - lastTimeRef.current;
14254
- lastTimeRef.current = time;
14256
+ let deltaTimeMs = timeMs - lastTimeMsRef.current;
14257
+ lastTimeMsRef.current = timeMs;
14255
14258
  // Clamp delta (prevents jumps after background tab / lag)
14256
- if (dt > maxDeltaMs) {
14257
- dt = maxDeltaMs;
14259
+ if (deltaTimeMs > maxDeltaMs) {
14260
+ deltaTimeMs = maxDeltaMs;
14258
14261
  }
14259
14262
  try {
14260
- callbackRef.current(dt, {
14261
- stop: stopRafLoop,
14263
+ onFrameRef.current(deltaTimeMs, {
14264
+ stop,
14262
14265
  });
14263
14266
  rafIdRef.current = requestAnimationFrame(loop);
14264
14267
  }
14265
14268
  catch (e) {
14266
- stopRafLoop();
14269
+ stop();
14267
14270
  onError?.(e);
14268
14271
  }
14269
14272
  }, [maxDeltaMs, onError]);
14270
- const startRafLoop = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14273
+ const start = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14271
14274
  if (rafIdRef.current !== null) {
14272
14275
  return;
14273
14276
  }
14274
- lastTimeRef.current = null;
14275
- setIsRafLoopRunning(true);
14277
+ lastTimeMsRef.current = null;
14278
+ setIsRunning(true);
14276
14279
  rafIdRef.current = requestAnimationFrame(loop);
14277
14280
  }, [loop]);
14278
- const stopRafLoop = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14281
+ const stop = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14279
14282
  if (rafIdRef.current === null) {
14280
14283
  return;
14281
14284
  }
14282
14285
  cancelAnimationFrame(rafIdRef.current);
14283
14286
  rafIdRef.current = null;
14284
- lastTimeRef.current = null;
14285
- setIsRafLoopRunning(false);
14287
+ lastTimeMsRef.current = null;
14288
+ setIsRunning(false);
14286
14289
  }, []);
14287
14290
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
14288
14291
  if (autoStart) {
14289
- startRafLoop();
14292
+ start();
14290
14293
  }
14291
- return stopRafLoop;
14292
- }, [autoStart, startRafLoop, stopRafLoop]);
14294
+ return stop;
14295
+ }, [autoStart, start, stop]);
14293
14296
  // Pause when a tab is hidden (important for mobile)
14294
14297
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
14295
14298
  const onVisibilityChange = () => {
14296
14299
  if (document.hidden) {
14297
- stopRafLoop();
14300
+ stop();
14298
14301
  }
14299
14302
  else if (resumeOnVisibility && autoStart) {
14300
- startRafLoop();
14303
+ start();
14301
14304
  }
14302
14305
  };
14303
14306
  document.addEventListener('visibilitychange', onVisibilityChange);
14304
14307
  return () => {
14305
14308
  document.removeEventListener('visibilitychange', onVisibilityChange);
14306
14309
  };
14307
- }, [autoStart, resumeOnVisibility, startRafLoop, stopRafLoop]);
14310
+ }, [autoStart, resumeOnVisibility, start, stop]);
14308
14311
  return {
14309
- startRafLoop,
14310
- stopRafLoop,
14311
- isRafLoopRunning,
14312
+ isRunning,
14313
+ start,
14314
+ stop,
14312
14315
  };
14313
14316
  };
14314
14317
 
@@ -14618,6 +14621,118 @@ const useHoneySyntheticScroll = ({ axis = 'both', overscrollPct = 0, onStartDrag
14618
14621
  };
14619
14622
 
14620
14623
 
14624
+ /***/ },
14625
+
14626
+ /***/ "./src/hooks/use-honey-timer.ts"
14627
+ /*!**************************************!*\
14628
+ !*** ./src/hooks/use-honey-timer.ts ***!
14629
+ \**************************************/
14630
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
14631
+
14632
+ "use strict";
14633
+ __webpack_require__.r(__webpack_exports__);
14634
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
14635
+ /* harmony export */ useHoneyTimer: () => (/* binding */ useHoneyTimer)
14636
+ /* harmony export */ });
14637
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
14638
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
14639
+ /* harmony import */ var _use_honey_raf_loop__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./use-honey-raf-loop */ "./src/hooks/use-honey-raf-loop.ts");
14640
+
14641
+
14642
+ /**
14643
+ * A high-precision timer hook built on top of {@link useHoneyRafLoop}.
14644
+ *
14645
+ * Features:
14646
+ * - Frame-accurate time progression using `requestAnimationFrame`
14647
+ * - Supports countdown and count-up modes
14648
+ * - Explicit lifecycle control (start / pause / resume / reset)
14649
+ * - Drift-free timing using delta-based updates
14650
+ * - Safe completion handling via `onEnd`
14651
+ *
14652
+ * Architectural notes:
14653
+ * - Time progression is handled imperatively via refs to avoid stale closures and unnecessary re-renders.
14654
+ * - React state is updated only with the derived timer value.
14655
+ * - RAF lifecycle is fully delegated to `useHoneyRafLoop`.
14656
+ *
14657
+ * @example
14658
+ * ```ts
14659
+ * const timer = useHoneyTimer({
14660
+ * initialTimeMs: 10_000,
14661
+ * targetTimeMs: 0,
14662
+ * onEnd: () => console.log('Done'),
14663
+ * });
14664
+ *
14665
+ * timer.startTimer();
14666
+ * ```
14667
+ */
14668
+ const useHoneyTimer = ({ initialTimeMs, targetTimeMs = 0, mode = 'countdown', autoStart = false, onEnd, }) => {
14669
+ const [timeMs, setTimeMs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initialTimeMs);
14670
+ const timeRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(timeMs);
14671
+ timeRef.current = timeMs;
14672
+ const onEndRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(onEnd);
14673
+ onEndRef.current = onEnd;
14674
+ /**
14675
+ * RAF frame handler responsible for advancing the timer.
14676
+ *
14677
+ * - Computes the next timer value based on `deltaTimeMs`
14678
+ * - Detects completion and stops the RAF loop
14679
+ * - Updates React state with the derived value
14680
+ */
14681
+ const onFrameHandler = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)((deltaTimeMs, { stop }) => {
14682
+ let nextTime = mode === 'countdown' ? timeRef.current - deltaTimeMs : timeRef.current + deltaTimeMs;
14683
+ let finished = false;
14684
+ if (mode === 'countdown') {
14685
+ if (nextTime <= targetTimeMs) {
14686
+ nextTime = targetTimeMs;
14687
+ finished = true;
14688
+ }
14689
+ }
14690
+ else if (targetTimeMs > 0 && nextTime >= targetTimeMs) {
14691
+ nextTime = targetTimeMs;
14692
+ finished = true;
14693
+ }
14694
+ timeRef.current = nextTime;
14695
+ setTimeMs(nextTime);
14696
+ if (finished) {
14697
+ stop();
14698
+ onEndRef.current?.();
14699
+ }
14700
+ }, [mode, targetTimeMs]);
14701
+ const rafLoop = (0,_use_honey_raf_loop__WEBPACK_IMPORTED_MODULE_1__.useHoneyRafLoop)(onFrameHandler);
14702
+ const start = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14703
+ timeRef.current = initialTimeMs;
14704
+ setTimeMs(initialTimeMs);
14705
+ rafLoop.start();
14706
+ }, [initialTimeMs, rafLoop.start]);
14707
+ const pause = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14708
+ rafLoop.stop();
14709
+ }, [rafLoop.stop]);
14710
+ const resume = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
14711
+ if (!rafLoop.isRunning) {
14712
+ rafLoop.start();
14713
+ }
14714
+ }, [rafLoop.isRunning, rafLoop.start]);
14715
+ const reset = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)((nextTimeMs = initialTimeMs) => {
14716
+ rafLoop.stop();
14717
+ timeRef.current = nextTimeMs;
14718
+ setTimeMs(nextTimeMs);
14719
+ }, [initialTimeMs, rafLoop.stop]);
14720
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
14721
+ if (autoStart) {
14722
+ start();
14723
+ }
14724
+ }, [autoStart, start]);
14725
+ return {
14726
+ timeMs,
14727
+ isRunning: rafLoop.isRunning,
14728
+ start,
14729
+ pause,
14730
+ resume,
14731
+ reset,
14732
+ };
14733
+ };
14734
+
14735
+
14621
14736
  /***/ },
14622
14737
 
14623
14738
  /***/ "./src/hooks/use-register-honey-overlay.ts"
@@ -15412,6 +15527,7 @@ __webpack_require__.r(__webpack_exports__);
15412
15527
  /* harmony export */ useHoneySyntheticScroll: () => (/* reexport safe */ _hooks__WEBPACK_IMPORTED_MODULE_5__.useHoneySyntheticScroll),
15413
15528
  /* harmony export */ useHoneySyntheticScrollX: () => (/* reexport safe */ _hooks__WEBPACK_IMPORTED_MODULE_5__.useHoneySyntheticScrollX),
15414
15529
  /* harmony export */ useHoneySyntheticScrollY: () => (/* reexport safe */ _hooks__WEBPACK_IMPORTED_MODULE_5__.useHoneySyntheticScrollY),
15530
+ /* harmony export */ useHoneyTimer: () => (/* reexport safe */ _hooks__WEBPACK_IMPORTED_MODULE_5__.useHoneyTimer),
15415
15531
  /* harmony export */ useRegisterHoneyOverlay: () => (/* reexport safe */ _hooks__WEBPACK_IMPORTED_MODULE_5__.useRegisterHoneyOverlay),
15416
15532
  /* harmony export */ warnOnce: () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.warnOnce)
15417
15533
  /* harmony export */ });