"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useAnimationStartSnapshot = useAnimationStartSnapshot;
var _react = require("react");
/**
 * Small state machine shared by animated components that need interruption-safe
 * animations.
 *
 * Why this exists:
 * Recharts stores the latest visible animation frame in mutable refs so the next
 * animation can resume from that exact geometry. That works well, but there is a
 * subtle trap: when an animation is interrupted, React may render several times
 * before the new animation has actually emitted its own `animationElapsedTime=0` frame. If we keep
 * reading and writing the same live ref during that window, the "start" value of
 * the new animation can drift, which produces visible jumps.
 *
 * This hook separates those two responsibilities:
 * - `startValue` is a frozen snapshot of the previous animation state, captured
 *   once per animation cycle and kept stable while that cycle is being matched
 *   and interpolated.
 * - `previousValueRef.current` remains the mutable "latest visible frame" store
 *   that future animations can resume from.
 *
 * The hook does not know anything about points, baselines, sectors, or shapes.
 * It only manages *when* a snapshot is captured and *when* new frames are allowed
 * to overwrite the mutable ref.
 *
 * Lifecycle:
 * 1. When `animationInput` changes by reference, a new cycle begins. We capture
 *    the current ref value into `startValue` and temporarily block writes.
 * 2. When the new animation renders `animationElapsedTime=0`, we unlock writes. This ensures the new
 *    animation has had a chance to render its true starting frame before any live
 *    ref gets updated.
 * 3. For `animationElapsedTime > 0`, callers may commit the visible frame back into the mutable ref.
 *    Callers can still veto that with `canCommit=false` (for example when a Line
 *    needs to wait until SVG path length has been measured).
 * 4. At `animationElapsedTime=1`, we also refresh the frozen snapshot so subsequent rerenders in the
 *    completed state observe the finished geometry.
 */
function useAnimationStartSnapshot(animationInput, previousValueRef) {
  /*
   * Stores the identity of the animation cycle we are currently serving.
   * As soon as this changes, we know we need a brand new frozen snapshot.
   */
  var previousAnimationInputRef = (0, _react.useRef)(animationInput);
  /*
   * Frozen start-of-cycle value used for interpolation.
   * This is the value callers should match against for the whole duration of the
   * current animation, even if the live ref is updated many times afterward.
   */
  var startValueRef = (0, _react.useRef)(previousValueRef.current);
  /*
   * Prevents us from writing back into the live ref until the new animation has
   * actually rendered its own animationElapsedTime=0 frame. This avoids "pre-start" renders from
   * accidentally rebasing the next animation onto already-shifted geometry.
   */
  var isReadyToCommitRef = (0, _react.useRef)(true);
  if (previousAnimationInputRef.current !== animationInput) {
    // New animation cycle: capture exactly one frozen starting snapshot.
    previousAnimationInputRef.current = animationInput;
    startValueRef.current = previousValueRef.current;
    // Writes stay blocked until the new cycle acknowledges its animationElapsedTime=0 frame.
    isReadyToCommitRef.current = false;
  }
  var syncStepValue = (0, _react.useCallback)(function (stepValue, animationElapsedTime) {
    var canCommit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
    if (animationElapsedTime === 0) {
      /*
       * animationElapsedTime=0 is the handshake that says: "the new animation has now rendered its
       * own starting frame". We do not write anything yet; we only allow later
       * in-flight frames to be committed safely.
       */
      isReadyToCommitRef.current = true;
      return;
    }
    if (animationElapsedTime === 1) {
      // Keep the frozen snapshot aligned with the fully completed geometry.
      startValueRef.current = stepValue;
    }
    if (animationElapsedTime > 0 && isReadyToCommitRef.current && canCommit) {
      /*
       * Commit the latest visible frame so a future interruption can resume from
       * exactly what the user saw on screen most recently.
       */
      // eslint-disable-next-line no-param-reassign
      previousValueRef.current = stepValue;
    }
  }, [previousValueRef]);
  return {
    startValue: startValueRef.current,
    syncStepValue
  };
}