"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
require("../motion-utils/dist-es-errors.cjs");
const timeConversion = require("../motion-utils/dist-es-time-conversion.cjs");
const calcDuration = require("../motion-dom/dist-es-animation-generators-utils-calc-duration.cjs");
const linear = require("../motion-dom/dist-es-animation-waapi-utils-linear.cjs");
const clamp = require("./dist-es-utils-clamp.cjs");
const velocity = require("./dist-es-animation-generators-utils-velocity.cjs");
const defaults = require("./dist-es-animation-generators-spring-defaults.cjs");
const find = require("./dist-es-animation-generators-spring-find.cjs");
const durationKeys = ["duration", "bounce"];
const physicsKeys = ["stiffness", "damping", "mass"];
function isSpringType(options, keys) {
  return keys.some((key) => options[key] !== void 0);
}
function getSpringOptions(options) {
  let springOptions = {
    velocity: defaults.springDefaults.velocity,
    stiffness: defaults.springDefaults.stiffness,
    damping: defaults.springDefaults.damping,
    mass: defaults.springDefaults.mass,
    isResolvedFromDuration: false,
    ...options
  };
  if (!isSpringType(options, physicsKeys) && isSpringType(options, durationKeys)) {
    if (options.visualDuration) {
      const visualDuration = options.visualDuration;
      const root = 2 * Math.PI / (visualDuration * 1.2);
      const stiffness = root * root;
      const damping = 2 * clamp.clamp(0.05, 1, 1 - (options.bounce || 0)) * Math.sqrt(stiffness);
      springOptions = {
        ...springOptions,
        mass: defaults.springDefaults.mass,
        stiffness,
        damping
      };
    } else {
      const derived = find.findSpring(options);
      springOptions = {
        ...springOptions,
        ...derived,
        mass: defaults.springDefaults.mass
      };
      springOptions.isResolvedFromDuration = true;
    }
  }
  return springOptions;
}
function spring(optionsOrVisualDuration = defaults.springDefaults.visualDuration, bounce = defaults.springDefaults.bounce) {
  const options = typeof optionsOrVisualDuration !== "object" ? {
    visualDuration: optionsOrVisualDuration,
    keyframes: [0, 1],
    bounce
  } : optionsOrVisualDuration;
  let { restSpeed, restDelta } = options;
  const origin = options.keyframes[0];
  const target = options.keyframes[options.keyframes.length - 1];
  const state = { done: false, value: origin };
  const { stiffness, damping, mass, duration, velocity: velocity$1, isResolvedFromDuration } = getSpringOptions({
    ...options,
    velocity: -timeConversion.millisecondsToSeconds(options.velocity || 0)
  });
  const initialVelocity = velocity$1 || 0;
  const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
  const initialDelta = target - origin;
  const undampedAngularFreq = timeConversion.millisecondsToSeconds(Math.sqrt(stiffness / mass));
  const isGranularScale = Math.abs(initialDelta) < 5;
  restSpeed || (restSpeed = isGranularScale ? defaults.springDefaults.restSpeed.granular : defaults.springDefaults.restSpeed.default);
  restDelta || (restDelta = isGranularScale ? defaults.springDefaults.restDelta.granular : defaults.springDefaults.restDelta.default);
  let resolveSpring;
  if (dampingRatio < 1) {
    const angularFreq = find.calcAngularFreq(undampedAngularFreq, dampingRatio);
    resolveSpring = (t) => {
      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
      return target - envelope * ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / angularFreq * Math.sin(angularFreq * t) + initialDelta * Math.cos(angularFreq * t));
    };
  } else if (dampingRatio === 1) {
    resolveSpring = (t) => target - Math.exp(-undampedAngularFreq * t) * (initialDelta + (initialVelocity + undampedAngularFreq * initialDelta) * t);
  } else {
    const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
    resolveSpring = (t) => {
      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
      const freqForT = Math.min(dampedAngularFreq * t, 300);
      return target - envelope * ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) * Math.sinh(freqForT) + dampedAngularFreq * initialDelta * Math.cosh(freqForT)) / dampedAngularFreq;
    };
  }
  const generator = {
    calculatedDuration: isResolvedFromDuration ? duration || null : null,
    next: (t) => {
      const current = resolveSpring(t);
      if (!isResolvedFromDuration) {
        let currentVelocity = 0;
        if (dampingRatio < 1) {
          currentVelocity = t === 0 ? timeConversion.secondsToMilliseconds(initialVelocity) : velocity.calcGeneratorVelocity(resolveSpring, t, current);
        }
        const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
        const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
        state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
      } else {
        state.done = t >= duration;
      }
      state.value = state.done ? target : current;
      return state;
    },
    toString: () => {
      const calculatedDuration = Math.min(calcDuration.calcGeneratorDuration(generator), calcDuration.maxGeneratorDuration);
      const easing = linear.generateLinearEasing((progress) => generator.next(calculatedDuration * progress).value, calculatedDuration, 30);
      return calculatedDuration + "ms " + easing;
    }
  };
  return generator;
}
exports.spring = spring;
//# sourceMappingURL=dist-es-animation-generators-spring-index.cjs.map
